aboutsummaryrefslogtreecommitdiffstats
path: root/java/src
diff options
context:
space:
mode:
Diffstat (limited to 'java/src')
-rw-r--r--java/src/com/android/inputmethod/compat/CursorAnchorInfoCompatWrapper.java38
-rw-r--r--java/src/com/android/inputmethod/compat/InputConnectionCompatUtils.java32
-rw-r--r--java/src/com/android/inputmethod/compat/NotificationCompatUtils.java83
-rw-r--r--java/src/com/android/inputmethod/compat/ViewCompatUtils.java19
-rw-r--r--java/src/com/android/inputmethod/dictionarypack/ActionBatch.java19
-rw-r--r--java/src/com/android/inputmethod/dictionarypack/DictionaryProvider.java6
-rw-r--r--java/src/com/android/inputmethod/dictionarypack/MetadataDbHelper.java81
-rw-r--r--java/src/com/android/inputmethod/dictionarypack/MetadataHandler.java19
-rw-r--r--java/src/com/android/inputmethod/dictionarypack/MetadataParser.java1
-rw-r--r--java/src/com/android/inputmethod/dictionarypack/UpdateHandler.java103
-rw-r--r--java/src/com/android/inputmethod/dictionarypack/WordListMetadata.java12
-rw-r--r--java/src/com/android/inputmethod/keyboard/Key.java60
-rw-r--r--java/src/com/android/inputmethod/keyboard/KeyboardLayoutSet.java10
-rw-r--r--java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java9
-rw-r--r--java/src/com/android/inputmethod/keyboard/KeyboardTheme.java20
-rw-r--r--java/src/com/android/inputmethod/keyboard/MainKeyboardView.java28
-rw-r--r--java/src/com/android/inputmethod/keyboard/MoreKeysKeyboard.java39
-rw-r--r--java/src/com/android/inputmethod/keyboard/TextDecorator.java11
-rw-r--r--java/src/com/android/inputmethod/keyboard/internal/KeyPreviewChoreographer.java93
-rw-r--r--java/src/com/android/inputmethod/keyboard/internal/KeyPreviewDrawParams.java86
-rw-r--r--java/src/com/android/inputmethod/keyboard/internal/KeyboardBuilder.java18
-rw-r--r--java/src/com/android/inputmethod/latin/BinaryDictionary.java7
-rw-r--r--java/src/com/android/inputmethod/latin/Constants.java7
-rw-r--r--java/src/com/android/inputmethod/latin/Dictionary.java9
-rw-r--r--java/src/com/android/inputmethod/latin/DictionaryCollection.java15
-rw-r--r--java/src/com/android/inputmethod/latin/DictionaryFacilitator.java22
-rw-r--r--java/src/com/android/inputmethod/latin/DictionaryFactory.java6
-rw-r--r--java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java6
-rw-r--r--java/src/com/android/inputmethod/latin/InputAttributes.java11
-rw-r--r--java/src/com/android/inputmethod/latin/LatinIME.java20
-rw-r--r--java/src/com/android/inputmethod/latin/ReadOnlyBinaryDictionary.java2
-rw-r--r--java/src/com/android/inputmethod/latin/RichInputConnection.java6
-rw-r--r--java/src/com/android/inputmethod/latin/Suggest.java16
-rw-r--r--java/src/com/android/inputmethod/latin/SuggestedWords.java2
-rw-r--r--java/src/com/android/inputmethod/latin/SystemBroadcastReceiver.java29
-rw-r--r--java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java2
-rw-r--r--java/src/com/android/inputmethod/latin/settings/CustomInputStyleSettingsFragment.java26
-rw-r--r--java/src/com/android/inputmethod/latin/settings/DebugSettings.java14
-rw-r--r--java/src/com/android/inputmethod/latin/settings/DebugSettingsFragment.java18
-rw-r--r--java/src/com/android/inputmethod/latin/settings/SettingsValues.java49
-rw-r--r--java/src/com/android/inputmethod/latin/setup/LauncherIconVisibilityManager.java9
-rw-r--r--java/src/com/android/inputmethod/latin/utils/DistracterFilterCheckingExactMatchesAndSuggestions.java167
-rw-r--r--java/src/com/android/inputmethod/latin/utils/SuggestionResults.java8
43 files changed, 795 insertions, 443 deletions
diff --git a/java/src/com/android/inputmethod/compat/CursorAnchorInfoCompatWrapper.java b/java/src/com/android/inputmethod/compat/CursorAnchorInfoCompatWrapper.java
index 24eaec85c..3a86ccbda 100644
--- a/java/src/com/android/inputmethod/compat/CursorAnchorInfoCompatWrapper.java
+++ b/java/src/com/android/inputmethod/compat/CursorAnchorInfoCompatWrapper.java
@@ -23,34 +23,16 @@ import com.android.inputmethod.annotations.UsedForTesting;
@UsedForTesting
public final class CursorAnchorInfoCompatWrapper {
- public static final int CHARACTER_RECT_TYPE_MASK = 0x0f;
/**
- * Type for {@link #CHARACTER_RECT_TYPE_MASK}: the editor did not specify any type of this
- * character. Editor authors should not use this flag.
+ * The insertion marker or character bounds have at least one visible region.
*/
- public static final int CHARACTER_RECT_TYPE_UNSPECIFIED = 0;
+ public static final int FLAG_HAS_VISIBLE_REGION = 0x01;
/**
- * Type for {@link #CHARACTER_RECT_TYPE_MASK}: the character is entirely visible.
+ * The insertion marker or character bounds have at least one invisible (clipped) region.
*/
- public static final int CHARACTER_RECT_TYPE_FULLY_VISIBLE = 1;
-
- /**
- * Type for {@link #CHARACTER_RECT_TYPE_MASK}: some area of the character is invisible.
- */
- public static final int CHARACTER_RECT_TYPE_PARTIALLY_VISIBLE = 2;
-
- /**
- * Type for {@link #CHARACTER_RECT_TYPE_MASK}: the character is entirely invisible.
- */
- public static final int CHARACTER_RECT_TYPE_INVISIBLE = 3;
-
- /**
- * Type for {@link #CHARACTER_RECT_TYPE_MASK}: the editor gave up to calculate the rectangle
- * for this character. Input method authors should ignore the returned rectangle.
- */
- public static final int CHARACTER_RECT_TYPE_NOT_FEASIBLE = 4;
+ public static final int FLAG_HAS_INVISIBLE_REGION = 0x02;
// Note that CursorAnchorInfo has been introduced in API level XX (Build.VERSION_CODE.LXX).
private static final CompatUtils.ClassWrapper sCursorAnchorInfoClass;
@@ -63,7 +45,7 @@ public final class CursorAnchorInfoCompatWrapper {
private static final CompatUtils.ToFloatMethodWrapper sGetInsertionMarkerHorizontalMethod;
private static final CompatUtils.ToFloatMethodWrapper sGetInsertionMarkerTopMethod;
private static final CompatUtils.ToObjectMethodWrapper<Matrix> sGetMatrixMethod;
- private static final CompatUtils.ToBooleanMethodWrapper sIsInsertionMarkerClippedMethod;
+ private static final CompatUtils.ToIntMethodWrapper sGetInsertionMarkerFlagsMethod;
private static int COMPOSING_TEXT_START_DEFAULT = -1;
static {
@@ -72,7 +54,7 @@ public final class CursorAnchorInfoCompatWrapper {
sGetCharacterRectMethod = sCursorAnchorInfoClass.getMethod(
"getCharacterRect", (RectF)null, int.class);
sGetCharacterRectFlagsMethod = sCursorAnchorInfoClass.getPrimitiveMethod(
- "getCharacterRectFlags", CHARACTER_RECT_TYPE_UNSPECIFIED, int.class);
+ "getCharacterRectFlags", 0, int.class);
sGetComposingTextMethod = sCursorAnchorInfoClass.getMethod(
"getComposingText", (CharSequence)null);
sGetComposingTextStartMethod = sCursorAnchorInfoClass.getPrimitiveMethod(
@@ -86,8 +68,8 @@ public final class CursorAnchorInfoCompatWrapper {
sGetInsertionMarkerTopMethod = sCursorAnchorInfoClass.getPrimitiveMethod(
"getInsertionMarkerTop", 0.0f);
sGetMatrixMethod = sCursorAnchorInfoClass.getMethod("getMatrix", (Matrix)null);
- sIsInsertionMarkerClippedMethod = sCursorAnchorInfoClass.getPrimitiveMethod(
- "isInsertionMarkerClipped", false);
+ sGetInsertionMarkerFlagsMethod = sCursorAnchorInfoClass.getPrimitiveMethod(
+ "getInsertionMarkerFlags", 0);
}
@UsedForTesting
@@ -154,7 +136,7 @@ public final class CursorAnchorInfoCompatWrapper {
return sGetInsertionMarkerTopMethod.invoke(mInstance);
}
- public boolean isInsertionMarkerClipped() {
- return sIsInsertionMarkerClippedMethod.invoke(mInstance);
+ public int getInsertionMarkerFlags() {
+ return sGetInsertionMarkerFlagsMethod.invoke(mInstance);
}
}
diff --git a/java/src/com/android/inputmethod/compat/InputConnectionCompatUtils.java b/java/src/com/android/inputmethod/compat/InputConnectionCompatUtils.java
index 862ec8a58..a5c71b22f 100644
--- a/java/src/com/android/inputmethod/compat/InputConnectionCompatUtils.java
+++ b/java/src/com/android/inputmethod/compat/InputConnectionCompatUtils.java
@@ -21,30 +21,29 @@ import android.view.inputmethod.InputMethodManager;
public final class InputConnectionCompatUtils {
private static final CompatUtils.ClassWrapper sInputConnectionType;
- private static final CompatUtils.ToBooleanMethodWrapper sRequestUpdateCursorAnchorInfoMethod;
+ private static final CompatUtils.ToBooleanMethodWrapper sRequestCursorUpdatesMethod;
static {
sInputConnectionType = new CompatUtils.ClassWrapper(InputConnection.class);
- sRequestUpdateCursorAnchorInfoMethod = sInputConnectionType.getPrimitiveMethod(
- "requestUpdateCursorAnchorInfo", false, int.class);
+ sRequestCursorUpdatesMethod = sInputConnectionType.getPrimitiveMethod(
+ "requestCursorUpdates", false, int.class);
}
- public static boolean isRequestUpdateCursorAnchorInfoAvailable() {
- return sRequestUpdateCursorAnchorInfoMethod != null;
+ public static boolean isRequestCursorUpdatesAvailable() {
+ return sRequestCursorUpdatesMethod != null;
}
/**
- * Local copies of some constants in CursorAnchorInfoRequest until the SDK becomes publicly
- * available.
+ * Local copies of some constants in InputConnection until the SDK becomes publicly available.
*/
- private static int REQUEST_UPDATE_CURSOR_UPDATE_IMMEDIATE = 1 << 0;
- private static int REQUEST_UPDATE_CURSOR_UPDATE_MONITOR = 1 << 1;
+ private static int CURSOR_UPDATE_IMMEDIATE = 1 << 0;
+ private static int CURSOR_UPDATE_MONITOR = 1 << 1;
- private static boolean requestUpdateCursorAnchorInfoImpl(final InputConnection inputConnection,
+ private static boolean requestCursorUpdatesImpl(final InputConnection inputConnection,
final int cursorUpdateMode) {
- if (!isRequestUpdateCursorAnchorInfoAvailable()) {
+ if (!isRequestCursorUpdatesAvailable()) {
return false;
}
- return sRequestUpdateCursorAnchorInfoMethod.invoke(inputConnection, cursorUpdateMode);
+ return sRequestCursorUpdatesMethod.invoke(inputConnection, cursorUpdateMode);
}
/**
@@ -56,11 +55,10 @@ public final class InputConnectionCompatUtils {
* as soon as possible to notify the current cursor/anchor position to the input method.
* @return {@code false} if the request is not handled. Otherwise returns {@code true}.
*/
- public static boolean requestUpdateCursorAnchorInfo(final InputConnection inputConnection,
+ public static boolean requestCursorUpdates(final InputConnection inputConnection,
final boolean enableMonitor, final boolean requestImmediateCallback) {
- final int cursorUpdateMode = (enableMonitor ? REQUEST_UPDATE_CURSOR_UPDATE_MONITOR : 0)
- | (requestImmediateCallback ? REQUEST_UPDATE_CURSOR_UPDATE_IMMEDIATE : 0);
- return requestUpdateCursorAnchorInfoImpl(inputConnection, cursorUpdateMode);
+ final int cursorUpdateMode = (enableMonitor ? CURSOR_UPDATE_MONITOR : 0)
+ | (requestImmediateCallback ? CURSOR_UPDATE_IMMEDIATE : 0);
+ return requestCursorUpdatesImpl(inputConnection, cursorUpdateMode);
}
-
}
diff --git a/java/src/com/android/inputmethod/compat/NotificationCompatUtils.java b/java/src/com/android/inputmethod/compat/NotificationCompatUtils.java
new file mode 100644
index 000000000..eb180071e
--- /dev/null
+++ b/java/src/com/android/inputmethod/compat/NotificationCompatUtils.java
@@ -0,0 +1,83 @@
+/*
+ * 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.compat;
+
+import android.app.Notification;
+import android.os.Build;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+
+public class NotificationCompatUtils {
+ // Note that TextInfo.getCharSequence() is supposed to be available in API level 21 and later.
+ private static final Method METHOD_setColor =
+ CompatUtils.getMethod(Notification.Builder.class, "setColor", int.class);
+ private static final Method METHOD_setVisibility =
+ CompatUtils.getMethod(Notification.Builder.class, "setVisibility", int.class);
+ private static final Method METHOD_setCategory =
+ CompatUtils.getMethod(Notification.Builder.class, "setCategory", String.class);
+ private static final Method METHOD_setPriority =
+ CompatUtils.getMethod(Notification.Builder.class, "setPriority", int.class);
+ private static final Method METHOD_build =
+ CompatUtils.getMethod(Notification.Builder.class, "build");
+ private static final Field FIELD_VISIBILITY_SECRET =
+ CompatUtils.getField(Notification.class, "VISIBILITY_SECRET");
+ private static final int VISIBILITY_SECRET = null == FIELD_VISIBILITY_SECRET ? 0
+ : (Integer) CompatUtils.getFieldValue(null /* receiver */, null /* defaultValue */,
+ FIELD_VISIBILITY_SECRET);
+ private static final Field FIELD_CATEGORY_RECOMMENDATION =
+ CompatUtils.getField(Notification.class, "CATEGORY_RECOMMENDATION");
+ private static final String CATEGORY_RECOMMENDATION = null == FIELD_CATEGORY_RECOMMENDATION ? ""
+ : (String) CompatUtils.getFieldValue(null /* receiver */, null /* defaultValue */,
+ FIELD_CATEGORY_RECOMMENDATION);
+ private static final Field FIELD_PRIORITY_LOW =
+ CompatUtils.getField(Notification.class, "PRIORITY_LOW");
+ private static final int PRIORITY_LOW = null == FIELD_PRIORITY_LOW ? 0
+ : (Integer) CompatUtils.getFieldValue(null /* receiver */, null /* defaultValue */,
+ FIELD_PRIORITY_LOW);
+
+ private NotificationCompatUtils() {
+ // This class is non-instantiable.
+ }
+
+ // Sets the accent color
+ public static void setColor(final Notification.Builder builder, final int color) {
+ CompatUtils.invoke(builder, null, METHOD_setColor, color);
+ }
+
+ public static void setVisibilityToSecret(final Notification.Builder builder) {
+ CompatUtils.invoke(builder, null, METHOD_setVisibility, VISIBILITY_SECRET);
+ }
+
+ public static void setCategoryToRecommendation(final Notification.Builder builder) {
+ CompatUtils.invoke(builder, null, METHOD_setCategory, CATEGORY_RECOMMENDATION);
+ }
+
+ public static void setPriorityToLow(final Notification.Builder builder) {
+ CompatUtils.invoke(builder, null, METHOD_setPriority, PRIORITY_LOW);
+ }
+
+ public static Notification build(final Notification.Builder builder) {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
+ // #build was added in API level 16, JELLY_BEAN
+ return (Notification) CompatUtils.invoke(builder, null, METHOD_build);
+ } else {
+ // #getNotification was deprecated in API level 16, JELLY_BEAN
+ return builder.getNotification();
+ }
+ }
+}
diff --git a/java/src/com/android/inputmethod/compat/ViewCompatUtils.java b/java/src/com/android/inputmethod/compat/ViewCompatUtils.java
index afbe8c890..0f00be133 100644
--- a/java/src/com/android/inputmethod/compat/ViewCompatUtils.java
+++ b/java/src/com/android/inputmethod/compat/ViewCompatUtils.java
@@ -34,6 +34,9 @@ public final class ViewCompatUtils {
// Note that View.setElevation(float) has been introduced in API level 21.
private static final Method METHOD_setElevation = CompatUtils.getMethod(
View.class, "setElevation", float.class);
+ // Note that View.setTextAlignment(int) has been introduced in API level 17.
+ private static final Method METHOD_setTextAlignment = CompatUtils.getMethod(
+ View.class, "setTextAlignment", int.class);
private ViewCompatUtils() {
// This utility class is not publicly instantiable.
@@ -56,9 +59,19 @@ public final class ViewCompatUtils {
}
public static void setElevation(final View view, final float elevation) {
- if (METHOD_setElevation == null) {
- return;
- }
CompatUtils.invoke(view, null, METHOD_setElevation, elevation);
}
+
+ // These TEXT_ALIGNMENT_* constants have been introduced in API 17.
+ public static final int TEXT_ALIGNMENT_INHERIT = 0;
+ public static final int TEXT_ALIGNMENT_GRAVITY = 1;
+ public static final int TEXT_ALIGNMENT_TEXT_START = 2;
+ public static final int TEXT_ALIGNMENT_TEXT_END = 3;
+ public static final int TEXT_ALIGNMENT_CENTER = 4;
+ public static final int TEXT_ALIGNMENT_VIEW_START = 5;
+ public static final int TEXT_ALIGNMENT_VIEW_END = 6;
+
+ public static void setTextAlignment(final View view, final int textAlignment) {
+ CompatUtils.invoke(view, null, METHOD_setTextAlignment, textAlignment);
+ }
}
diff --git a/java/src/com/android/inputmethod/dictionarypack/ActionBatch.java b/java/src/com/android/inputmethod/dictionarypack/ActionBatch.java
index 3d294acd7..3aa026e77 100644
--- a/java/src/com/android/inputmethod/dictionarypack/ActionBatch.java
+++ b/java/src/com/android/inputmethod/dictionarypack/ActionBatch.java
@@ -120,9 +120,10 @@ public final class ActionBatch {
if (MetadataDbHelper.STATUS_DOWNLOADING == status) {
// The word list is still downloading. Cancel the download and revert the
// word list status to "available".
- manager.remove(values.getAsLong(MetadataDbHelper.PENDINGID_COLUMN));
+ manager.remove(values.getAsLong(MetadataDbHelper.PENDINGID_COLUMN));
MetadataDbHelper.markEntryAsAvailable(db, mWordList.mId, mWordList.mVersion);
- } else if (MetadataDbHelper.STATUS_AVAILABLE != status) {
+ } else if (MetadataDbHelper.STATUS_AVAILABLE != status
+ && MetadataDbHelper.STATUS_RETRYING != status) {
// Should never happen
Log.e(TAG, "Unexpected state of the word list '" + mWordList.mId + "' : " + status
+ " for an upgrade action. Fall back to download.");
@@ -325,8 +326,8 @@ public final class ActionBatch {
mWordList.mId, mWordList.mLocale, mWordList.mDescription,
null == mWordList.mLocalFilename ? "" : mWordList.mLocalFilename,
mWordList.mRemoteFilename, mWordList.mLastUpdate, mWordList.mRawChecksum,
- mWordList.mChecksum, mWordList.mFileSize, mWordList.mVersion,
- mWordList.mFormatVersion);
+ mWordList.mChecksum, mWordList.mRetryCount, mWordList.mFileSize,
+ mWordList.mVersion, mWordList.mFormatVersion);
PrivateLog.log("Insert 'available' record for " + mWordList.mDescription
+ " and locale " + mWordList.mLocale);
db.insert(MetadataDbHelper.METADATA_TABLE_NAME, null, values);
@@ -374,9 +375,9 @@ public final class ActionBatch {
final ContentValues values = MetadataDbHelper.makeContentValues(0,
MetadataDbHelper.TYPE_BULK, MetadataDbHelper.STATUS_INSTALLED,
mWordList.mId, mWordList.mLocale, mWordList.mDescription,
- "", mWordList.mRemoteFilename, mWordList.mLastUpdate, mWordList.mRawChecksum,
- mWordList.mChecksum, mWordList.mFileSize, mWordList.mVersion,
- mWordList.mFormatVersion);
+ "", mWordList.mRemoteFilename, mWordList.mLastUpdate,
+ mWordList.mRawChecksum, mWordList.mChecksum, mWordList.mRetryCount,
+ mWordList.mFileSize, mWordList.mVersion, mWordList.mFormatVersion);
PrivateLog.log("Insert 'preinstalled' record for " + mWordList.mDescription
+ " and locale " + mWordList.mLocale);
db.insert(MetadataDbHelper.METADATA_TABLE_NAME, null, values);
@@ -417,8 +418,8 @@ public final class ActionBatch {
mWordList.mId, mWordList.mLocale, mWordList.mDescription,
oldValues.getAsString(MetadataDbHelper.LOCAL_FILENAME_COLUMN),
mWordList.mRemoteFilename, mWordList.mLastUpdate, mWordList.mRawChecksum,
- mWordList.mChecksum, mWordList.mFileSize, mWordList.mVersion,
- mWordList.mFormatVersion);
+ mWordList.mChecksum, mWordList.mRetryCount, mWordList.mFileSize,
+ mWordList.mVersion, mWordList.mFormatVersion);
PrivateLog.log("Updating record for " + mWordList.mDescription
+ " and locale " + mWordList.mLocale);
db.update(MetadataDbHelper.METADATA_TABLE_NAME, values,
diff --git a/java/src/com/android/inputmethod/dictionarypack/DictionaryProvider.java b/java/src/com/android/inputmethod/dictionarypack/DictionaryProvider.java
index f5bd84c8c..e748321e2 100644
--- a/java/src/com/android/inputmethod/dictionarypack/DictionaryProvider.java
+++ b/java/src/com/android/inputmethod/dictionarypack/DictionaryProvider.java
@@ -470,7 +470,11 @@ public final class DictionaryProvider extends ContentProvider {
} else if (MetadataDbHelper.STATUS_INSTALLED == status) {
final String result = uri.getQueryParameter(QUERY_PARAMETER_DELETE_RESULT);
if (QUERY_PARAMETER_FAILURE.equals(result)) {
- UpdateHandler.markAsBroken(getContext(), clientId, wordlistId, version);
+ if (DEBUG) {
+ Log.d(TAG,
+ "Dictionary is broken, attempting to retry download & installation.");
+ }
+ UpdateHandler.markAsBrokenOrRetrying(getContext(), clientId, wordlistId, version);
}
final String localFilename =
wordList.getAsString(MetadataDbHelper.LOCAL_FILENAME_COLUMN);
diff --git a/java/src/com/android/inputmethod/dictionarypack/MetadataDbHelper.java b/java/src/com/android/inputmethod/dictionarypack/MetadataDbHelper.java
index 17dd781d5..e9dde4245 100644
--- a/java/src/com/android/inputmethod/dictionarypack/MetadataDbHelper.java
+++ b/java/src/com/android/inputmethod/dictionarypack/MetadataDbHelper.java
@@ -47,10 +47,13 @@ public class MetadataDbHelper extends SQLiteOpenHelper {
// used to identify the versions for upgrades. This should never change going forward.
private static final int METADATA_DATABASE_VERSION_WITH_CLIENTID = 6;
// The current database version.
- private static final int CURRENT_METADATA_DATABASE_VERSION = 9;
+ private static final int CURRENT_METADATA_DATABASE_VERSION = 10;
private final static long NOT_A_DOWNLOAD_ID = -1;
+ // The number of retries allowed when attempting to download a broken dictionary.
+ public static final int DICTIONARY_RETRY_THRESHOLD = 2;
+
public static final String METADATA_TABLE_NAME = "pendingUpdates";
static final String CLIENT_TABLE_NAME = "clients";
public static final String PENDINGID_COLUMN = "pendingid"; // Download Manager ID
@@ -68,7 +71,8 @@ public class MetadataDbHelper extends SQLiteOpenHelper {
public static final String FORMATVERSION_COLUMN = "formatversion";
public static final String FLAGS_COLUMN = "flags";
public static final String RAW_CHECKSUM_COLUMN = "rawChecksum";
- public static final int COLUMN_COUNT = 14;
+ public static final String RETRY_COUNT_COLUMN = "remainingRetries";
+ public static final int COLUMN_COUNT = 15;
private static final String CLIENT_CLIENT_ID_COLUMN = "clientid";
private static final String CLIENT_METADATA_URI_COLUMN = "uri";
@@ -98,6 +102,8 @@ public class MetadataDbHelper extends SQLiteOpenHelper {
// Deleting: the user marked this word list to be deleted, but it has not been yet because
// Latin IME is not up yet.
public static final int STATUS_DELETING = 5;
+ // Retry: dictionary got corrupted, so an attempt must be done to download & install it again.
+ public static final int STATUS_RETRYING = 6;
// Types, for storing in the TYPE_COLUMN
// This is metadata about what is available.
@@ -124,6 +130,7 @@ public class MetadataDbHelper extends SQLiteOpenHelper {
+ FORMATVERSION_COLUMN + " INTEGER, "
+ FLAGS_COLUMN + " INTEGER, "
+ RAW_CHECKSUM_COLUMN + " TEXT,"
+ + RETRY_COUNT_COLUMN + " INTEGER, "
+ "PRIMARY KEY (" + WORDLISTID_COLUMN + "," + VERSION_COLUMN + "));";
private static final String METADATA_CREATE_CLIENT_TABLE =
"CREATE TABLE IF NOT EXISTS " + CLIENT_TABLE_NAME + " ("
@@ -140,7 +147,7 @@ public class MetadataDbHelper extends SQLiteOpenHelper {
STATUS_COLUMN, WORDLISTID_COLUMN, LOCALE_COLUMN, DESCRIPTION_COLUMN,
LOCAL_FILENAME_COLUMN, REMOTE_FILENAME_COLUMN, DATE_COLUMN, CHECKSUM_COLUMN,
FILESIZE_COLUMN, VERSION_COLUMN, FORMATVERSION_COLUMN, FLAGS_COLUMN,
- RAW_CHECKSUM_COLUMN };
+ RAW_CHECKSUM_COLUMN, RETRY_COUNT_COLUMN };
// List of all client table columns.
static final String[] CLIENT_TABLE_COLUMNS = { CLIENT_CLIENT_ID_COLUMN,
CLIENT_METADATA_URI_COLUMN, CLIENT_PENDINGID_COLUMN, FLAGS_COLUMN };
@@ -219,7 +226,7 @@ public class MetadataDbHelper extends SQLiteOpenHelper {
createClientTable(db);
}
- private void addRawChecksumColumnUnlessPresent(final SQLiteDatabase db, final String clientId) {
+ private void addRawChecksumColumnUnlessPresent(final SQLiteDatabase db) {
try {
db.execSQL("SELECT " + RAW_CHECKSUM_COLUMN + " FROM "
+ METADATA_TABLE_NAME + " LIMIT 0;");
@@ -230,6 +237,17 @@ public class MetadataDbHelper extends SQLiteOpenHelper {
}
}
+ private void addRetryCountColumnUnlessPresent(final SQLiteDatabase db) {
+ try {
+ db.execSQL("SELECT " + RETRY_COUNT_COLUMN + " FROM "
+ + METADATA_TABLE_NAME + " LIMIT 0;");
+ } catch (SQLiteException e) {
+ Log.i(TAG, "No " + RETRY_COUNT_COLUMN + " column : creating it");
+ db.execSQL("ALTER TABLE " + METADATA_TABLE_NAME + " ADD COLUMN "
+ + RETRY_COUNT_COLUMN + " INTEGER DEFAULT " + DICTIONARY_RETRY_THRESHOLD + ";");
+ }
+ }
+
/**
* Upgrade the database. Upgrade from version 3 is supported.
* Version 3 has a DB named METADATA_DATABASE_NAME_STEM containing a table METADATA_TABLE_NAME.
@@ -280,7 +298,14 @@ public class MetadataDbHelper extends SQLiteOpenHelper {
// strengthen the system against corrupted dictionary files.
// The most secure way to upgrade a database is to just test for the column presence, and
// add it if it's not there.
- addRawChecksumColumnUnlessPresent(db, mClientId);
+ addRawChecksumColumnUnlessPresent(db);
+
+ // A retry count column that did not exist in the previous versions was added that
+ // corresponds to the number of download & installation attempts that have been made
+ // in order to strengthen the system recovery from corrupted dictionary files.
+ // The most secure way to upgrade a database is to just test for the column presence, and
+ // add it if it's not there.
+ addRetryCountColumnUnlessPresent(db);
}
/**
@@ -452,8 +477,8 @@ public class MetadataDbHelper extends SQLiteOpenHelper {
public static ContentValues makeContentValues(final int pendingId, final int type,
final int status, final String wordlistId, final String locale,
final String description, final String filename, final String url, final long date,
- final String rawChecksum, final String checksum, final long filesize, final int version,
- final int formatVersion) {
+ final String rawChecksum, final String checksum, final int retryCount,
+ final long filesize, final int version, final int formatVersion) {
final ContentValues result = new ContentValues(COLUMN_COUNT);
result.put(PENDINGID_COLUMN, pendingId);
result.put(TYPE_COLUMN, type);
@@ -465,6 +490,7 @@ public class MetadataDbHelper extends SQLiteOpenHelper {
result.put(REMOTE_FILENAME_COLUMN, url);
result.put(DATE_COLUMN, date);
result.put(RAW_CHECKSUM_COLUMN, rawChecksum);
+ result.put(RETRY_COUNT_COLUMN, retryCount);
result.put(CHECKSUM_COLUMN, checksum);
result.put(FILESIZE_COLUMN, filesize);
result.put(VERSION_COLUMN, version);
@@ -502,6 +528,9 @@ public class MetadataDbHelper extends SQLiteOpenHelper {
if (null == result.get(DATE_COLUMN)) result.put(DATE_COLUMN, 0);
// Raw checksum unknown unless specified
if (null == result.get(RAW_CHECKSUM_COLUMN)) result.put(RAW_CHECKSUM_COLUMN, "");
+ // Retry column 0 unless specified
+ if (null == result.get(RETRY_COUNT_COLUMN)) result.put(RETRY_COUNT_COLUMN,
+ DICTIONARY_RETRY_THRESHOLD);
// Checksum unknown unless specified
if (null == result.get(CHECKSUM_COLUMN)) result.put(CHECKSUM_COLUMN, "");
// No filesize unless specified
@@ -551,6 +580,7 @@ public class MetadataDbHelper extends SQLiteOpenHelper {
putIntResult(result, cursor, DATE_COLUMN);
putStringResult(result, cursor, RAW_CHECKSUM_COLUMN);
putStringResult(result, cursor, CHECKSUM_COLUMN);
+ putIntResult(result, cursor, RETRY_COUNT_COLUMN);
putIntResult(result, cursor, FILESIZE_COLUMN);
putIntResult(result, cursor, VERSION_COLUMN);
putIntResult(result, cursor, FORMATVERSION_COLUMN);
@@ -676,8 +706,16 @@ public class MetadataDbHelper extends SQLiteOpenHelper {
final String id, final int version) {
final Cursor cursor = db.query(METADATA_TABLE_NAME,
METADATA_TABLE_COLUMNS,
- WORDLISTID_COLUMN + "= ? AND " + VERSION_COLUMN + "= ?",
- new String[] { id, Integer.toString(version) }, null, null, null);
+ WORDLISTID_COLUMN + "= ? AND " + VERSION_COLUMN + "= ? AND "
+ + FORMATVERSION_COLUMN + "<= ?",
+ new String[]
+ { id,
+ Integer.toString(version),
+ Integer.toString(UpdateHandler.MAXIMUM_SUPPORTED_FORMAT_VERSION)
+ },
+ null /* groupBy */,
+ null /* having */,
+ FORMATVERSION_COLUMN + " DESC"/* orderBy */);
if (null == cursor) {
return null;
}
@@ -706,7 +744,7 @@ public class MetadataDbHelper extends SQLiteOpenHelper {
return null;
}
try {
- // This is a lookup by primary key, so there can't be more than one result.
+ // Return the first result from the list of results.
return getFirstLineAsContentValues(cursor);
} finally {
cursor.close();
@@ -1085,4 +1123,27 @@ public class MetadataDbHelper extends SQLiteOpenHelper {
final int version) {
markEntryAs(db, id, version, STATUS_DELETING, NOT_A_DOWNLOAD_ID);
}
+
+ /**
+ * Checks retry counts and marks the word list as retrying if retry is possible.
+ *
+ * @param db the metadata database.
+ * @param id the id of the word list.
+ * @param version the version of the word list.
+ * @return {@code true} if the retry is possible.
+ */
+ public static boolean maybeMarkEntryAsRetrying(final SQLiteDatabase db, final String id,
+ final int version) {
+ final ContentValues values = MetadataDbHelper.getContentValuesByWordListId(db, id, version);
+ int retryCount = values.getAsInteger(MetadataDbHelper.RETRY_COUNT_COLUMN);
+ if (retryCount > 1) {
+ values.put(STATUS_COLUMN, STATUS_RETRYING);
+ values.put(RETRY_COUNT_COLUMN, retryCount - 1);
+ db.update(METADATA_TABLE_NAME, values,
+ WORDLISTID_COLUMN + " = ? AND " + VERSION_COLUMN + " = ?",
+ new String[] { id, Integer.toString(version) });
+ return true;
+ }
+ return false;
+ }
}
diff --git a/java/src/com/android/inputmethod/dictionarypack/MetadataHandler.java b/java/src/com/android/inputmethod/dictionarypack/MetadataHandler.java
index d66b69050..639d904a0 100644
--- a/java/src/com/android/inputmethod/dictionarypack/MetadataHandler.java
+++ b/java/src/com/android/inputmethod/dictionarypack/MetadataHandler.java
@@ -16,6 +16,7 @@
package com.android.inputmethod.dictionarypack;
+import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
@@ -55,6 +56,7 @@ public class MetadataHandler {
final int rawChecksumIndex =
results.getColumnIndex(MetadataDbHelper.RAW_CHECKSUM_COLUMN);
final int checksumIndex = results.getColumnIndex(MetadataDbHelper.CHECKSUM_COLUMN);
+ final int retryCountIndex = results.getColumnIndex(MetadataDbHelper.RETRY_COUNT_COLUMN);
final int localFilenameIndex =
results.getColumnIndex(MetadataDbHelper.LOCAL_FILENAME_COLUMN);
final int remoteFilenameIndex =
@@ -70,6 +72,7 @@ public class MetadataHandler {
results.getLong(fileSizeIndex),
results.getString(rawChecksumIndex),
results.getString(checksumIndex),
+ results.getInt(retryCountIndex),
results.getString(localFilenameIndex),
results.getString(remoteFilenameIndex),
results.getInt(versionIndex),
@@ -102,6 +105,22 @@ public class MetadataHandler {
}
/**
+ * Gets the metadata, for a specific dictionary.
+ *
+ * @param context The context to open files over.
+ * @param clientId the client id for retrieving the database. null for default (deprecated).
+ * @param wordListId the word list ID.
+ * @param version the word list version.
+ * @return the current metaData
+ */
+ public static WordListMetadata getCurrentMetadataForWordList(final Context context,
+ final String clientId, final String wordListId, final int version) {
+ final ContentValues contentValues = MetadataDbHelper.getContentValuesByWordListId(
+ MetadataDbHelper.getDb(context, clientId), wordListId, version);
+ return WordListMetadata.createFromContentValues(contentValues);
+ }
+
+ /**
* Read metadata from a stream.
* @param input The stream to read from.
* @return The read metadata.
diff --git a/java/src/com/android/inputmethod/dictionarypack/MetadataParser.java b/java/src/com/android/inputmethod/dictionarypack/MetadataParser.java
index 52290cadc..2b67ae9ff 100644
--- a/java/src/com/android/inputmethod/dictionarypack/MetadataParser.java
+++ b/java/src/com/android/inputmethod/dictionarypack/MetadataParser.java
@@ -83,6 +83,7 @@ public class MetadataParser {
Long.parseLong(arguments.get(FILESIZE_FIELD_NAME)),
arguments.get(RAW_CHECKSUM_FIELD_NAME),
arguments.get(CHECKSUM_FIELD_NAME),
+ MetadataDbHelper.DICTIONARY_RETRY_THRESHOLD /* retryCount */,
null,
arguments.get(REMOTE_FILENAME_FIELD_NAME),
Integer.parseInt(arguments.get(VERSION_FIELD_NAME)),
diff --git a/java/src/com/android/inputmethod/dictionarypack/UpdateHandler.java b/java/src/com/android/inputmethod/dictionarypack/UpdateHandler.java
index 95a094232..d8c5f3165 100644
--- a/java/src/com/android/inputmethod/dictionarypack/UpdateHandler.java
+++ b/java/src/com/android/inputmethod/dictionarypack/UpdateHandler.java
@@ -37,6 +37,7 @@ import android.util.Log;
import com.android.inputmethod.compat.ConnectivityManagerCompatUtils;
import com.android.inputmethod.compat.DownloadManagerCompatUtils;
+import com.android.inputmethod.compat.NotificationCompatUtils;
import com.android.inputmethod.latin.R;
import com.android.inputmethod.latin.utils.ApplicationUtils;
import com.android.inputmethod.latin.utils.DebugLogUtils;
@@ -783,6 +784,10 @@ public final class UpdateHandler {
} else {
final SQLiteDatabase db = MetadataDbHelper.getDb(context, clientId);
if (newInfo.mVersion == currentInfo.mVersion) {
+ if (newInfo.mRemoteFilename == currentInfo.mRemoteFilename) {
+ // If the dictionary url hasn't changed, we should preserve the retryCount.
+ newInfo.mRetryCount = currentInfo.mRetryCount;
+ }
// If it's the same id/version, we update the DB with the new values.
// It doesn't matter too much if they didn't change.
actions.add(new ActionBatch.UpdateDataAction(clientId, newInfo));
@@ -858,7 +863,7 @@ public final class UpdateHandler {
final String language = (null == locale ? "" : locale.getDisplayLanguage());
final String titleFormat = context.getString(R.string.dict_available_notification_title);
final String notificationTitle = String.format(titleFormat, language);
- final Notification notification = new Notification.Builder(context)
+ final Notification.Builder builder = new Notification.Builder(context)
.setAutoCancel(true)
.setContentIntent(notificationIntent)
.setContentTitle(notificationTitle)
@@ -866,8 +871,13 @@ public final class UpdateHandler {
.setTicker(notificationTitle)
.setOngoing(false)
.setOnlyAlertOnce(true)
- .setSmallIcon(R.drawable.ic_notify_dictionary)
- .getNotification();
+ .setSmallIcon(R.drawable.ic_notify_dictionary);
+ NotificationCompatUtils.setColor(builder,
+ context.getResources().getColor(R.color.notification_accent_color));
+ NotificationCompatUtils.setPriorityToLow(builder);
+ NotificationCompatUtils.setVisibilityToSecret(builder);
+ NotificationCompatUtils.setCategoryToRecommendation(builder);
+ final Notification notification = NotificationCompatUtils.build(builder);
notificationManager.notify(DICT_AVAILABLE_NOTIFICATION_ID, notification);
}
@@ -980,16 +990,17 @@ public final class UpdateHandler {
public static void markAsUsed(final Context context, final String clientId,
final String wordlistId, final int version,
final int status, final boolean allowDownloadOnMeteredData) {
- final List<WordListMetadata> currentMetadata =
- MetadataHandler.getCurrentMetadata(context, clientId);
- WordListMetadata wordList = MetadataHandler.findWordListById(currentMetadata, wordlistId);
- if (null == wordList) return;
+ final WordListMetadata wordListMetaData = MetadataHandler.getCurrentMetadataForWordList(
+ context, clientId, wordlistId, version);
+
+ if (null == wordListMetaData) return;
+
final ActionBatch actions = new ActionBatch();
if (MetadataDbHelper.STATUS_DISABLED == status
|| MetadataDbHelper.STATUS_DELETING == status) {
- actions.add(new ActionBatch.EnableAction(clientId, wordList));
+ actions.add(new ActionBatch.EnableAction(clientId, wordListMetaData));
} else if (MetadataDbHelper.STATUS_AVAILABLE == status) {
- actions.add(new ActionBatch.StartDownloadAction(clientId, wordList,
+ actions.add(new ActionBatch.StartDownloadAction(clientId, wordListMetaData,
allowDownloadOnMeteredData));
} else {
Log.e(TAG, "Unexpected state of the word list for markAsUsed : " + status);
@@ -1015,13 +1026,13 @@ public final class UpdateHandler {
// markAsUsed for consistency.
public static void markAsUnused(final Context context, final String clientId,
final String wordlistId, final int version, final int status) {
- final List<WordListMetadata> currentMetadata =
- MetadataHandler.getCurrentMetadata(context, clientId);
- final WordListMetadata wordList =
- MetadataHandler.findWordListById(currentMetadata, wordlistId);
- if (null == wordList) return;
+
+ final WordListMetadata wordListMetaData = MetadataHandler.getCurrentMetadataForWordList(
+ context, clientId, wordlistId, version);
+
+ if (null == wordListMetaData) return;
final ActionBatch actions = new ActionBatch();
- actions.add(new ActionBatch.DisableAction(clientId, wordList));
+ actions.add(new ActionBatch.DisableAction(clientId, wordListMetaData));
actions.execute(context, new LogProblemReporter(TAG));
signalNewDictionaryState(context);
}
@@ -1044,14 +1055,14 @@ public final class UpdateHandler {
*/
public static void markAsDeleting(final Context context, final String clientId,
final String wordlistId, final int version, final int status) {
- final List<WordListMetadata> currentMetadata =
- MetadataHandler.getCurrentMetadata(context, clientId);
- final WordListMetadata wordList =
- MetadataHandler.findWordListById(currentMetadata, wordlistId);
- if (null == wordList) return;
+
+ final WordListMetadata wordListMetaData = MetadataHandler.getCurrentMetadataForWordList(
+ context, clientId, wordlistId, version);
+
+ if (null == wordListMetaData) return;
final ActionBatch actions = new ActionBatch();
- actions.add(new ActionBatch.DisableAction(clientId, wordList));
- actions.add(new ActionBatch.StartDeleteAction(clientId, wordList));
+ actions.add(new ActionBatch.DisableAction(clientId, wordListMetaData));
+ actions.add(new ActionBatch.StartDeleteAction(clientId, wordListMetaData));
actions.execute(context, new LogProblemReporter(TAG));
signalNewDictionaryState(context);
}
@@ -1069,33 +1080,47 @@ public final class UpdateHandler {
*/
public static void markAsDeleted(final Context context, final String clientId,
final String wordlistId, final int version, final int status) {
- final List<WordListMetadata> currentMetadata =
- MetadataHandler.getCurrentMetadata(context, clientId);
- final WordListMetadata wordList =
- MetadataHandler.findWordListById(currentMetadata, wordlistId);
- if (null == wordList) return;
+ final WordListMetadata wordListMetaData = MetadataHandler.getCurrentMetadataForWordList(
+ context, clientId, wordlistId, version);
+
+ if (null == wordListMetaData) return;
+
final ActionBatch actions = new ActionBatch();
- actions.add(new ActionBatch.FinishDeleteAction(clientId, wordList));
+ actions.add(new ActionBatch.FinishDeleteAction(clientId, wordListMetaData));
actions.execute(context, new LogProblemReporter(TAG));
signalNewDictionaryState(context);
}
/**
- * Marks the word list with the passed id as broken.
- *
- * This effectively deletes the entry from the metadata. It doesn't prevent the same
- * word list to be downloaded again at a later time if the same or a new version is
- * available the next time we download the metadata.
+ * Checks whether the word list should be downloaded again; in which case an download &
+ * installation attempt is made. Otherwise the word list is marked broken.
*
* @param context the context to open the database on.
* @param clientId the id of the client.
- * @param wordlistId the id of the word list to mark as broken.
- * @param version the version of the word list to mark as deleted.
+ * @param wordlistId the id of the word list which is broken.
+ * @param version the version of the broken word list.
*/
- public static void markAsBroken(final Context context, final String clientId,
+ public static void markAsBrokenOrRetrying(final Context context, final String clientId,
final String wordlistId, final int version) {
- // TODO: do this on another thread to avoid blocking the UI.
- MetadataDbHelper.deleteEntry(MetadataDbHelper.getDb(context, clientId),
- wordlistId, version);
+ boolean isRetryPossible = MetadataDbHelper.maybeMarkEntryAsRetrying(
+ MetadataDbHelper.getDb(context, clientId), wordlistId, version);
+
+ if (isRetryPossible) {
+ if (DEBUG) {
+ Log.d(TAG, "Attempting to download & install the wordlist again.");
+ }
+ final WordListMetadata wordListMetaData = MetadataHandler.getCurrentMetadataForWordList(
+ context, clientId, wordlistId, version);
+
+ final ActionBatch actions = new ActionBatch();
+ actions.add(new ActionBatch.StartDownloadAction(clientId, wordListMetaData, false));
+ actions.execute(context, new LogProblemReporter(TAG));
+ } else {
+ if (DEBUG) {
+ Log.d(TAG, "Retries for wordlist exhausted, deleting the wordlist from table.");
+ }
+ MetadataDbHelper.deleteEntry(MetadataDbHelper.getDb(context, clientId),
+ wordlistId, version);
+ }
}
}
diff --git a/java/src/com/android/inputmethod/dictionarypack/WordListMetadata.java b/java/src/com/android/inputmethod/dictionarypack/WordListMetadata.java
index 9e510a68b..59f75e4ed 100644
--- a/java/src/com/android/inputmethod/dictionarypack/WordListMetadata.java
+++ b/java/src/com/android/inputmethod/dictionarypack/WordListMetadata.java
@@ -36,6 +36,7 @@ public class WordListMetadata {
public final String mRemoteFilename;
public final int mVersion; // version of this word list
public final int mFlags; // Always 0 in this version, reserved for future use
+ public int mRetryCount;
// The locale is matched against the locale requested by the client. The matching algorithm
// is a standard locale matching with fallback; it is implemented in
@@ -51,8 +52,9 @@ public class WordListMetadata {
public WordListMetadata(final String id, final int type,
final String description, final long lastUpdate, final long fileSize,
- final String rawChecksum, final String checksum, final String localFilename,
- final String remoteFilename, final int version, final int formatVersion,
+ final String rawChecksum, final String checksum, final int retryCount,
+ final String localFilename, final String remoteFilename,
+ final int version, final int formatVersion,
final int flags, final String locale) {
mId = id;
mType = type;
@@ -61,6 +63,7 @@ public class WordListMetadata {
mFileSize = fileSize;
mRawChecksum = rawChecksum;
mChecksum = checksum;
+ mRetryCount = retryCount;
mLocalFilename = localFilename;
mRemoteFilename = remoteFilename;
mVersion = version;
@@ -82,6 +85,7 @@ public class WordListMetadata {
final Long fileSize = values.getAsLong(MetadataDbHelper.FILESIZE_COLUMN);
final String rawChecksum = values.getAsString(MetadataDbHelper.RAW_CHECKSUM_COLUMN);
final String checksum = values.getAsString(MetadataDbHelper.CHECKSUM_COLUMN);
+ final int retryCount = values.getAsInteger(MetadataDbHelper.RETRY_COUNT_COLUMN);
final String localFilename = values.getAsString(MetadataDbHelper.LOCAL_FILENAME_COLUMN);
final String remoteFilename = values.getAsString(MetadataDbHelper.REMOTE_FILENAME_COLUMN);
final Integer version = values.getAsInteger(MetadataDbHelper.VERSION_COLUMN);
@@ -103,7 +107,8 @@ public class WordListMetadata {
throw new IllegalArgumentException();
}
return new WordListMetadata(id, type, description, lastUpdate, fileSize, rawChecksum,
- checksum, localFilename, remoteFilename, version, formatVersion, flags, locale);
+ checksum, retryCount, localFilename, remoteFilename, version, formatVersion,
+ flags, locale);
}
@Override
@@ -116,6 +121,7 @@ public class WordListMetadata {
sb.append("\nFileSize : ").append(mFileSize);
sb.append("\nRawChecksum : ").append(mRawChecksum);
sb.append("\nChecksum : ").append(mChecksum);
+ sb.append("\nRetryCount: ").append(mRetryCount);
sb.append("\nLocalFilename : ").append(mLocalFilename);
sb.append("\nRemoteFilename : ").append(mRemoteFilename);
sb.append("\nVersion : ").append(mVersion);
diff --git a/java/src/com/android/inputmethod/keyboard/Key.java b/java/src/com/android/inputmethod/keyboard/Key.java
index 3743d26e6..efa527e15 100644
--- a/java/src/com/android/inputmethod/keyboard/Key.java
+++ b/java/src/com/android/inputmethod/keyboard/Key.java
@@ -108,11 +108,23 @@ public class Key implements Comparable<Key> {
private final MoreKeySpec[] mMoreKeys;
/** More keys column number and flags */
private final int mMoreKeysColumnAndFlags;
- private static final int MORE_KEYS_COLUMN_MASK = 0x000000ff;
- private static final int MORE_KEYS_FLAGS_FIXED_COLUMN_ORDER = 0x80000000;
+ private static final int MORE_KEYS_COLUMN_NUMBER_MASK = 0x000000ff;
+ // If this flag is specified, more keys keyboard should have the specified number of columns.
+ // Otherwise more keys keyboard should have less than or equal to the specified maximum number
+ // of columns.
+ private static final int MORE_KEYS_FLAGS_FIXED_COLUMN = 0x00000100;
+ // If this flag is specified, the order of more keys is determined by the order in the more
+ // keys' specification. Otherwise the order of more keys is automatically determined.
+ private static final int MORE_KEYS_FLAGS_FIXED_ORDER = 0x00000200;
+ private static final int MORE_KEYS_MODE_MAX_COLUMN_WITH_AUTO_ORDER = 0;
+ private static final int MORE_KEYS_MODE_FIXED_COLUMN_WITH_AUTO_ORDER =
+ MORE_KEYS_FLAGS_FIXED_COLUMN;
+ private static final int MORE_KEYS_MODE_FIXED_COLUMN_WITH_FIXED_ORDER =
+ (MORE_KEYS_FLAGS_FIXED_COLUMN | MORE_KEYS_FLAGS_FIXED_ORDER);
private static final int MORE_KEYS_FLAGS_HAS_LABELS = 0x40000000;
private static final int MORE_KEYS_FLAGS_NEEDS_DIVIDERS = 0x20000000;
private static final int MORE_KEYS_FLAGS_NO_PANEL_AUTO_MORE_KEY = 0x10000000;
+ // TODO: Rename these specifiers to !autoOrder! and !fixedOrder! respectively.
private static final String MORE_KEYS_AUTO_COLUMN_ORDER = "!autoColumnOrder!";
private static final String MORE_KEYS_FIXED_COLUMN_ORDER = "!fixedColumnOrder!";
private static final String MORE_KEYS_HAS_LABELS = "!hasLabels!";
@@ -127,7 +139,7 @@ public class Key implements Comparable<Key> {
public static final int BACKGROUND_TYPE_STICKY_OFF = 3;
public static final int BACKGROUND_TYPE_STICKY_ON = 4;
public static final int BACKGROUND_TYPE_ACTION = 5;
- public static final int BACKGROUND_TYPE_CUSTOM_ACTION = 6;
+ public static final int BACKGROUND_TYPE_SPACEBAR = 6;
private final int mActionFlags;
private static final int ACTION_FLAGS_IS_REPEATABLE = 0x01;
@@ -255,25 +267,31 @@ public class Key implements Comparable<Key> {
int actionFlags = style.getFlags(keyAttr, R.styleable.Keyboard_Key_keyActionFlags);
String[] moreKeys = style.getStringArray(keyAttr, R.styleable.Keyboard_Key_moreKeys);
- int moreKeysColumn = style.getInt(keyAttr,
- R.styleable.Keyboard_Key_maxMoreKeysColumn, params.mMaxMoreKeysKeyboardColumn);
+ // Get maximum column order number and set a relevant mode value.
+ int moreKeysColumnAndFlags = MORE_KEYS_MODE_MAX_COLUMN_WITH_AUTO_ORDER
+ | style.getInt(keyAttr, R.styleable.Keyboard_Key_maxMoreKeysColumn,
+ params.mMaxMoreKeysKeyboardColumn);
int value;
if ((value = MoreKeySpec.getIntValue(moreKeys, MORE_KEYS_AUTO_COLUMN_ORDER, -1)) > 0) {
- moreKeysColumn = value & MORE_KEYS_COLUMN_MASK;
+ // Override with fixed column order number and set a relevant mode value.
+ moreKeysColumnAndFlags = MORE_KEYS_MODE_FIXED_COLUMN_WITH_AUTO_ORDER
+ | (value & MORE_KEYS_COLUMN_NUMBER_MASK);
}
if ((value = MoreKeySpec.getIntValue(moreKeys, MORE_KEYS_FIXED_COLUMN_ORDER, -1)) > 0) {
- moreKeysColumn = MORE_KEYS_FLAGS_FIXED_COLUMN_ORDER | (value & MORE_KEYS_COLUMN_MASK);
+ // Override with fixed column order number and set a relevant mode value.
+ moreKeysColumnAndFlags = MORE_KEYS_MODE_FIXED_COLUMN_WITH_FIXED_ORDER
+ | (value & MORE_KEYS_COLUMN_NUMBER_MASK);
}
if (MoreKeySpec.getBooleanValue(moreKeys, MORE_KEYS_HAS_LABELS)) {
- moreKeysColumn |= MORE_KEYS_FLAGS_HAS_LABELS;
+ moreKeysColumnAndFlags |= MORE_KEYS_FLAGS_HAS_LABELS;
}
if (MoreKeySpec.getBooleanValue(moreKeys, MORE_KEYS_NEEDS_DIVIDERS)) {
- moreKeysColumn |= MORE_KEYS_FLAGS_NEEDS_DIVIDERS;
+ moreKeysColumnAndFlags |= MORE_KEYS_FLAGS_NEEDS_DIVIDERS;
}
if (MoreKeySpec.getBooleanValue(moreKeys, MORE_KEYS_NO_PANEL_AUTO_MORE_KEY)) {
- moreKeysColumn |= MORE_KEYS_FLAGS_NO_PANEL_AUTO_MORE_KEY;
+ moreKeysColumnAndFlags |= MORE_KEYS_FLAGS_NO_PANEL_AUTO_MORE_KEY;
}
- mMoreKeysColumnAndFlags = moreKeysColumn;
+ mMoreKeysColumnAndFlags = moreKeysColumnAndFlags;
final String[] additionalMoreKeys;
if ((mLabelFlags & LABEL_FLAGS_DISABLE_ADDITIONAL_MORE_KEYS) != 0) {
@@ -488,7 +506,7 @@ public class Key implements Comparable<Key> {
case BACKGROUND_TYPE_STICKY_OFF: return "stickyOff";
case BACKGROUND_TYPE_STICKY_ON: return "stickyOn";
case BACKGROUND_TYPE_ACTION: return "action";
- case BACKGROUND_TYPE_CUSTOM_ACTION: return "customAction";
+ case BACKGROUND_TYPE_SPACEBAR: return "spacebar";
default: return null;
}
}
@@ -680,12 +698,16 @@ public class Key implements Comparable<Key> {
&& !TextUtils.isEmpty(mHintLabel);
}
- public final int getMoreKeysColumn() {
- return mMoreKeysColumnAndFlags & MORE_KEYS_COLUMN_MASK;
+ public final int getMoreKeysColumnNumber() {
+ return mMoreKeysColumnAndFlags & MORE_KEYS_COLUMN_NUMBER_MASK;
}
- public final boolean isFixedColumnOrderMoreKeys() {
- return (mMoreKeysColumnAndFlags & MORE_KEYS_FLAGS_FIXED_COLUMN_ORDER) != 0;
+ public final boolean isMoreKeysFixedColumn() {
+ return (mMoreKeysColumnAndFlags & MORE_KEYS_FLAGS_FIXED_COLUMN) != 0;
+ }
+
+ public final boolean isMoreKeysFixedOrder() {
+ return (mMoreKeysColumnAndFlags & MORE_KEYS_FLAGS_FIXED_ORDER) != 0;
}
public final boolean hasLabelsInMoreKeys() {
@@ -867,8 +889,8 @@ public class Key implements Comparable<Key> {
new KeyBackgroundState(android.R.attr.state_checkable, android.R.attr.state_checked),
// 5: BACKGROUND_TYPE_ACTION
new KeyBackgroundState(android.R.attr.state_active),
- // 6: BACKGROUND_TYPE_CUSTOM_ACTION
- new KeyBackgroundState(android.R.attr.state_active, android.R.attr.state_checked)
+ // 6: BACKGROUND_TYPE_SPACEBAR
+ new KeyBackgroundState(),
};
}
@@ -882,7 +904,7 @@ public class Key implements Comparable<Key> {
final Drawable background;
if (mBackgroundType == BACKGROUND_TYPE_FUNCTIONAL) {
background = functionalKeyBackground;
- } else if (getCode() == Constants.CODE_SPACE) {
+ } else if (mBackgroundType == BACKGROUND_TYPE_SPACEBAR) {
background = spacebarBackground;
} else {
background = keyBackground;
diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardLayoutSet.java b/java/src/com/android/inputmethod/keyboard/KeyboardLayoutSet.java
index 0804cebc4..3f4367313 100644
--- a/java/src/com/android/inputmethod/keyboard/KeyboardLayoutSet.java
+++ b/java/src/com/android/inputmethod/keyboard/KeyboardLayoutSet.java
@@ -119,7 +119,15 @@ public final class KeyboardLayoutSet {
new SparseArray<>();
}
- public static void clearKeyboardCache() {
+ public static void onSystemLocaleChanged() {
+ clearKeyboardCache();
+ }
+
+ public static void onKeyboardThemeChanged() {
+ clearKeyboardCache();
+ }
+
+ private static void clearKeyboardCache() {
sKeyboardCache.clear();
sKeysCache.clear();
}
diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java b/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java
index 30bd1dfda..91d703330 100644
--- a/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java
+++ b/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java
@@ -103,7 +103,7 @@ public final class KeyboardSwitcher implements KeyboardState.SwitchActions {
if (mThemeContext == null || !keyboardTheme.equals(mKeyboardTheme)) {
mKeyboardTheme = keyboardTheme;
mThemeContext = new ContextThemeWrapper(context, keyboardTheme.mStyleId);
- KeyboardLayoutSet.clearKeyboardCache();
+ KeyboardLayoutSet.onKeyboardThemeChanged();
return true;
}
return false;
@@ -154,9 +154,12 @@ public final class KeyboardSwitcher implements KeyboardState.SwitchActions {
mCurrentSettingsValues.mKeyPreviewPopupOn,
mCurrentSettingsValues.mKeyPreviewPopupDismissDelay);
keyboardView.setKeyPreviewAnimationParams(
- mCurrentSettingsValues.mKeyPreviewShowUpStartScale,
+ mCurrentSettingsValues.mHasCustomKeyPreviewAnimationParams,
+ mCurrentSettingsValues.mKeyPreviewShowUpStartXScale,
+ mCurrentSettingsValues.mKeyPreviewShowUpStartYScale,
mCurrentSettingsValues.mKeyPreviewShowUpDuration,
- mCurrentSettingsValues.mKeyPreviewDismissEndScale,
+ mCurrentSettingsValues.mKeyPreviewDismissEndXScale,
+ mCurrentSettingsValues.mKeyPreviewDismissEndYScale,
mCurrentSettingsValues.mKeyPreviewDismissDuration);
keyboardView.updateShortcutKey(mSubtypeSwitcher.isShortcutImeReady());
final boolean subtypeChanged = (oldKeyboard == null)
diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardTheme.java b/java/src/com/android/inputmethod/keyboard/KeyboardTheme.java
index 0cd606d19..7161d3f26 100644
--- a/java/src/com/android/inputmethod/keyboard/KeyboardTheme.java
+++ b/java/src/com/android/inputmethod/keyboard/KeyboardTheme.java
@@ -32,6 +32,8 @@ public final class KeyboardTheme implements Comparable<KeyboardTheme> {
static final String KLP_KEYBOARD_THEME_KEY = "pref_keyboard_layout_20110916";
static final String LXX_KEYBOARD_THEME_KEY = "pref_keyboard_theme_20140509";
+ // These should be aligned with Keyboard.themeId and Keyboard.Case.keyboardTheme
+ // attributes' values in attrs.xml.
public static final int THEME_ID_ICS = 0;
public static final int THEME_ID_KLP = 2;
public static final int THEME_ID_LXX_LIGHT = 3;
@@ -39,16 +41,16 @@ public final class KeyboardTheme implements Comparable<KeyboardTheme> {
public static final int DEFAULT_THEME_ID = THEME_ID_KLP;
private static final KeyboardTheme[] KEYBOARD_THEMES = {
- new KeyboardTheme(THEME_ID_ICS, R.style.KeyboardTheme_ICS,
+ new KeyboardTheme(THEME_ID_ICS, "ICS", R.style.KeyboardTheme_ICS,
// This has never been selected because we support ICS or later.
VERSION_CODES.BASE),
- new KeyboardTheme(THEME_ID_KLP, R.style.KeyboardTheme_KLP,
+ new KeyboardTheme(THEME_ID_KLP, "KLP", R.style.KeyboardTheme_KLP,
// Default theme for ICS, JB, and KLP.
VERSION_CODES.ICE_CREAM_SANDWICH),
- new KeyboardTheme(THEME_ID_LXX_LIGHT, R.style.KeyboardTheme_LXX_Light,
+ new KeyboardTheme(THEME_ID_LXX_LIGHT, "LXXLight", R.style.KeyboardTheme_LXX_Light,
// Default theme for LXX.
BuildCompatUtils.VERSION_CODES_LXX),
- new KeyboardTheme(THEME_ID_LXX_DARK, R.style.KeyboardTheme_LXX_Dark,
+ new KeyboardTheme(THEME_ID_LXX_DARK, "LXXDark", R.style.KeyboardTheme_LXX_Dark,
VERSION_CODES.BASE),
};
@@ -59,12 +61,15 @@ public final class KeyboardTheme implements Comparable<KeyboardTheme> {
public final int mThemeId;
public final int mStyleId;
+ public final String mThemeName;
private final int mMinApiVersion;
// Note: The themeId should be aligned with "themeId" attribute of Keyboard style
// in values/themes-<style>.xml.
- private KeyboardTheme(final int themeId, final int styleId, final int minApiVersion) {
+ private KeyboardTheme(final int themeId, final String themeName, final int styleId,
+ final int minApiVersion) {
mThemeId = themeId;
+ mThemeName = themeName;
mStyleId = styleId;
mMinApiVersion = minApiVersion;
}
@@ -128,6 +133,11 @@ public final class KeyboardTheme implements Comparable<KeyboardTheme> {
return searchKeyboardThemeById(DEFAULT_THEME_ID);
}
+ public static String getKeyboardThemeName(final int themeId) {
+ final KeyboardTheme theme = searchKeyboardThemeById(themeId);
+ return theme.mThemeName;
+ }
+
public static void saveKeyboardThemeId(final String themeIdString,
final SharedPreferences prefs) {
saveKeyboardThemeId(themeIdString, prefs, BuildCompatUtils.EFFECTIVE_SDK_INT);
diff --git a/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java b/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java
index 847d90711..d2f3e9714 100644
--- a/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java
+++ b/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java
@@ -85,6 +85,8 @@ import java.util.WeakHashMap;
* @attr ref R.styleable#MainKeyboardView_keyPreviewOffset
* @attr ref R.styleable#MainKeyboardView_keyPreviewHeight
* @attr ref R.styleable#MainKeyboardView_keyPreviewLingerTimeout
+ * @attr ref R.styleable#MainKeyboardView_keyPreviewShowUpAnimator
+ * @attr ref R.styleable#MainKeyboardView_keyPreviewDismissAnimator
* @attr ref R.styleable#MainKeyboardView_moreKeysKeyboardLayout
* @attr ref R.styleable#MainKeyboardView_backgroundDimAlpha
* @attr ref R.styleable#MainKeyboardView_showMoreKeysKeyboardAtTouchPoint
@@ -390,20 +392,34 @@ public final class MainKeyboardView extends KeyboardView implements PointerTrack
}
/**
- * Enables or disables the key feedback popup. This is a popup that shows a magnified
+ * Enables or disables the key preview popup. This is a popup that shows a magnified
* version of the depressed key. By default the preview is enabled.
* @param previewEnabled whether or not to enable the key feedback preview
* @param delay the delay after which the preview is dismissed
- * @see #isKeyPreviewPopupEnabled()
*/
public void setKeyPreviewPopupEnabled(final boolean previewEnabled, final int delay) {
mKeyPreviewDrawParams.setPopupEnabled(previewEnabled, delay);
}
- public void setKeyPreviewAnimationParams(final float showUpStartScale, final int showUpDuration,
- final float dismissEndScale, final int dismissDuration) {
- mKeyPreviewDrawParams.setAnimationParams(
- showUpStartScale, showUpDuration, dismissEndScale, dismissDuration);
+ /**
+ * Enables or disables the key preview popup animations and set animations' parameters.
+ *
+ * @param hasCustomAnimationParams false to use the default key preview popup animations
+ * specified by keyPreviewShowUpAnimator and keyPreviewDismissAnimator attributes.
+ * true to override the default animations with the specified parameters.
+ * @param showUpStartXScale from this x-scale the show up animation will start.
+ * @param showUpStartYScale from this y-scale the show up animation will start.
+ * @param showUpDuration the duration of the show up animation in milliseconds.
+ * @param dismissEndXScale to this x-scale the dismiss animation will end.
+ * @param dismissEndYScale to this y-scale the dismiss animation will end.
+ * @param dismissDuration the duration of the dismiss animation in milliseconds.
+ */
+ public void setKeyPreviewAnimationParams(final boolean hasCustomAnimationParams,
+ final float showUpStartXScale, final float showUpStartYScale, final int showUpDuration,
+ final float dismissEndXScale, final float dismissEndYScale, final int dismissDuration) {
+ mKeyPreviewDrawParams.setAnimationParams(hasCustomAnimationParams,
+ showUpStartXScale, showUpStartYScale, showUpDuration,
+ dismissEndXScale, dismissEndYScale, dismissDuration);
}
private void locatePreviewPlacerView() {
diff --git a/java/src/com/android/inputmethod/keyboard/MoreKeysKeyboard.java b/java/src/com/android/inputmethod/keyboard/MoreKeysKeyboard.java
index e0184d7f1..52e2e85ba 100644
--- a/java/src/com/android/inputmethod/keyboard/MoreKeysKeyboard.java
+++ b/java/src/com/android/inputmethod/keyboard/MoreKeysKeyboard.java
@@ -43,7 +43,7 @@ public final class MoreKeysKeyboard extends Keyboard {
@UsedForTesting
static class MoreKeysKeyboardParams extends KeyboardParams {
- public boolean mIsFixedOrder;
+ public boolean mIsMoreKeysFixedOrder;
/* package */int mTopRowAdjustment;
public int mNumRows;
public int mNumColumns;
@@ -61,29 +61,35 @@ public final class MoreKeysKeyboard extends Keyboard {
* Set keyboard parameters of more keys keyboard.
*
* @param numKeys number of keys in this more keys keyboard.
- * @param maxColumns number of maximum columns of this more keys keyboard.
+ * @param numColumn number of columns of this more keys keyboard.
* @param keyWidth more keys keyboard key width in pixel, including horizontal gap.
* @param rowHeight more keys keyboard row height in pixel, including vertical gap.
* @param coordXInParent coordinate x of the key preview in parent keyboard.
* @param parentKeyboardWidth parent keyboard width in pixel.
- * @param isFixedColumnOrder if true, more keys should be laid out in fixed order.
+ * @param isMoreKeysFixedColumn true if more keys keyboard should have
+ * <code>numColumn</code> columns. Otherwise more keys keyboard should have
+ * <code>numColumn</code> columns at most.
+ * @param isMoreKeysFixedOrder true if the order of more keys is determined by the order in
+ * the more keys' specification. Otherwise the order of more keys is automatically
+ * determined.
* @param dividerWidth width of divider, zero for no dividers.
*/
- public void setParameters(final int numKeys, final int maxColumns, final int keyWidth,
+ public void setParameters(final int numKeys, final int numColumn, final int keyWidth,
final int rowHeight, final int coordXInParent, final int parentKeyboardWidth,
- final boolean isFixedColumnOrder, final int dividerWidth) {
- mIsFixedOrder = isFixedColumnOrder;
- if (parentKeyboardWidth / keyWidth < Math.min(numKeys, maxColumns)) {
+ final boolean isMoreKeysFixedColumn, final boolean isMoreKeysFixedOrder,
+ final int dividerWidth) {
+ mIsMoreKeysFixedOrder = isMoreKeysFixedOrder;
+ if (parentKeyboardWidth / keyWidth < Math.min(numKeys, numColumn)) {
throw new IllegalArgumentException("Keyboard is too small to hold more keys: "
- + parentKeyboardWidth + " " + keyWidth + " " + numKeys + " " + maxColumns);
+ + parentKeyboardWidth + " " + keyWidth + " " + numKeys + " " + numColumn);
}
mDefaultKeyWidth = keyWidth;
mDefaultRowHeight = rowHeight;
- final int numRows = (numKeys + maxColumns - 1) / maxColumns;
+ final int numRows = (numKeys + numColumn - 1) / numColumn;
mNumRows = numRows;
- final int numColumns = mIsFixedOrder ? Math.min(numKeys, maxColumns)
- : getOptimizedColumns(numKeys, maxColumns);
+ final int numColumns = isMoreKeysFixedColumn ? Math.min(numKeys, numColumn)
+ : getOptimizedColumns(numKeys, numColumn);
mNumColumns = numColumns;
final int topKeys = numKeys % numColumns;
mTopKeys = topKeys == 0 ? numColumns : topKeys;
@@ -120,7 +126,7 @@ public final class MoreKeysKeyboard extends Keyboard {
mRightKeys = rightKeys;
// Adjustment of the top row.
- mTopRowAdjustment = mIsFixedOrder ? getFixedOrderTopRowAdjustment()
+ mTopRowAdjustment = isMoreKeysFixedOrder ? getFixedOrderTopRowAdjustment()
: getAutoOrderTopRowAdjustment();
mDividerWidth = dividerWidth;
mColumnWidth = mDefaultKeyWidth + mDividerWidth;
@@ -148,7 +154,7 @@ public final class MoreKeysKeyboard extends Keyboard {
// Return key position according to column count (0 is default).
/* package */int getColumnPos(final int n) {
- return mIsFixedOrder ? getFixedOrderColumnPos(n) : getAutomaticColumnPos(n);
+ return mIsMoreKeysFixedOrder ? getFixedOrderColumnPos(n) : getAutomaticColumnPos(n);
}
private int getFixedOrderColumnPos(final int n) {
@@ -263,7 +269,8 @@ public final class MoreKeysKeyboard extends Keyboard {
* @param keyboard the {@link Keyboard} that contains the parentKey.
* @param isSingleMoreKeyWithPreview true if the <code>key</code> has just a single
* "more key" and its key popup preview is enabled.
- * @param keyPreviewDrawParams the parameter to place key preview.
+ * @param keyPreviewVisibleWidth the width of visible part of key popup preview.
+ * @param keyPreviewVisibleHeight the height of visible part of key popup preview
* @param paintToMeasure the {@link Paint} object to measure a "more key" width
*/
public Builder(final Context context, final Key key, final Keyboard keyboard,
@@ -306,9 +313,9 @@ public final class MoreKeysKeyboard extends Keyboard {
dividerWidth = 0;
}
final MoreKeySpec[] moreKeys = key.getMoreKeys();
- mParams.setParameters(moreKeys.length, key.getMoreKeysColumn(), keyWidth, rowHeight,
+ mParams.setParameters(moreKeys.length, key.getMoreKeysColumnNumber(), keyWidth, rowHeight,
key.getX() + key.getWidth() / 2, keyboard.mId.mWidth,
- key.isFixedColumnOrderMoreKeys(), dividerWidth);
+ key.isMoreKeysFixedColumn(), key.isMoreKeysFixedOrder(), dividerWidth);
}
private static int getMaxKeyWidth(final Key parentKey, final int minKeyWidth,
diff --git a/java/src/com/android/inputmethod/keyboard/TextDecorator.java b/java/src/com/android/inputmethod/keyboard/TextDecorator.java
index 178516134..9192853ca 100644
--- a/java/src/com/android/inputmethod/keyboard/TextDecorator.java
+++ b/java/src/com/android/inputmethod/keyboard/TextDecorator.java
@@ -276,10 +276,10 @@ public class TextDecorator {
final int lastCharRectIndex = composingTextStart + composingText.length() - 1;
final RectF lastCharRect = info.getCharacterRect(lastCharRectIndex);
final int lastCharRectFlag = info.getCharacterRectFlags(lastCharRectIndex);
- final int lastCharRectType =
- lastCharRectFlag & CursorAnchorInfoCompatWrapper.CHARACTER_RECT_TYPE_MASK;
- if (lastCharRect == null || matrix == null || lastCharRectType !=
- CursorAnchorInfoCompatWrapper.CHARACTER_RECT_TYPE_FULLY_VISIBLE) {
+ final boolean hasInvisibleRegionInLastCharRect =
+ (lastCharRectFlag & CursorAnchorInfoCompatWrapper.FLAG_HAS_INVISIBLE_REGION)
+ != 0;
+ if (lastCharRect == null || matrix == null || hasInvisibleRegionInLastCharRect) {
mUiOperator.hideUi();
return;
}
@@ -336,7 +336,8 @@ public class TextDecorator {
}
// In MODE_ADD_TO_DICTIONARY, we cannot retrieve the character position at all because
// of the lack of composing text. We will use the insertion marker position instead.
- if (info.isInsertionMarkerClipped()) {
+ if ((info.getInsertionMarkerFlags() &
+ CursorAnchorInfoCompatWrapper.FLAG_HAS_INVISIBLE_REGION) != 0) {
mUiOperator.hideUi();
return;
}
diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeyPreviewChoreographer.java b/java/src/com/android/inputmethod/keyboard/internal/KeyPreviewChoreographer.java
index cd29c8d17..5005b7d7d 100644
--- a/java/src/com/android/inputmethod/keyboard/internal/KeyPreviewChoreographer.java
+++ b/java/src/com/android/inputmethod/keyboard/internal/KeyPreviewChoreographer.java
@@ -18,13 +18,9 @@ package com.android.inputmethod.keyboard.internal;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
-import android.animation.AnimatorSet;
-import android.animation.ObjectAnimator;
import android.content.Context;
import android.view.View;
import android.view.ViewGroup;
-import android.view.animation.AccelerateInterpolator;
-import android.view.animation.DecelerateInterpolator;
import com.android.inputmethod.keyboard.Key;
import com.android.inputmethod.latin.utils.CoordinateUtils;
@@ -89,9 +85,9 @@ public final class KeyPreviewChoreographer {
}
final Object tag = keyPreviewView.getTag();
if (withAnimation) {
- if (tag instanceof KeyPreviewAnimations) {
- final KeyPreviewAnimations animation = (KeyPreviewAnimations)tag;
- animation.startDismiss();
+ if (tag instanceof KeyPreviewAnimators) {
+ final KeyPreviewAnimators animators = (KeyPreviewAnimators)tag;
+ animators.startDismiss();
return;
}
}
@@ -161,87 +157,60 @@ public final class KeyPreviewChoreographer {
}
// Show preview with animation.
- final Animator showUpAnimation = createShowUpAniation(key, keyPreviewView);
- final Animator dismissAnimation = createDismissAnimation(key, keyPreviewView);
- final KeyPreviewAnimations animation = new KeyPreviewAnimations(
- showUpAnimation, dismissAnimation);
- keyPreviewView.setTag(animation);
- animation.startShowUp();
+ final Animator showUpAnimator = createShowUpAnimator(key, keyPreviewView);
+ final Animator dismissAnimator = createDismissAnimator(key, keyPreviewView);
+ final KeyPreviewAnimators animators = new KeyPreviewAnimators(
+ showUpAnimator, dismissAnimator);
+ keyPreviewView.setTag(animators);
+ animators.startShowUp();
}
- private static final float KEY_PREVIEW_SHOW_UP_END_SCALE = 1.0f;
- private static final AccelerateInterpolator ACCELERATE_INTERPOLATOR =
- new AccelerateInterpolator();
- private static final DecelerateInterpolator DECELERATE_INTERPOLATOR =
- new DecelerateInterpolator();
-
- private Animator createShowUpAniation(final Key key, final KeyPreviewView keyPreviewView) {
- // TODO: Optimization for no scale animation and no duration.
- final ObjectAnimator scaleXAnimation = ObjectAnimator.ofFloat(
- keyPreviewView, View.SCALE_X, mParams.getShowUpStartScale(),
- KEY_PREVIEW_SHOW_UP_END_SCALE);
- final ObjectAnimator scaleYAnimation = ObjectAnimator.ofFloat(
- keyPreviewView, View.SCALE_Y, mParams.getShowUpStartScale(),
- KEY_PREVIEW_SHOW_UP_END_SCALE);
- final AnimatorSet showUpAnimation = new AnimatorSet();
- showUpAnimation.play(scaleXAnimation).with(scaleYAnimation);
- showUpAnimation.setDuration(mParams.getShowUpDuration());
- showUpAnimation.setInterpolator(DECELERATE_INTERPOLATOR);
- showUpAnimation.addListener(new AnimatorListenerAdapter() {
+ public Animator createShowUpAnimator(final Key key, final KeyPreviewView keyPreviewView) {
+ final Animator animator = mParams.createShowUpAnimator(keyPreviewView);
+ animator.addListener(new AnimatorListenerAdapter() {
@Override
- public void onAnimationStart(final Animator animation) {
+ public void onAnimationStart(final Animator animator) {
showKeyPreview(key, keyPreviewView, false /* withAnimation */);
}
});
- return showUpAnimation;
+ return animator;
}
- private Animator createDismissAnimation(final Key key, final KeyPreviewView keyPreviewView) {
- // TODO: Optimization for no scale animation and no duration.
- final ObjectAnimator scaleXAnimation = ObjectAnimator.ofFloat(
- keyPreviewView, View.SCALE_X, mParams.getDismissEndScale());
- final ObjectAnimator scaleYAnimation = ObjectAnimator.ofFloat(
- keyPreviewView, View.SCALE_Y, mParams.getDismissEndScale());
- final AnimatorSet dismissAnimation = new AnimatorSet();
- dismissAnimation.play(scaleXAnimation).with(scaleYAnimation);
- final int dismissDuration = Math.min(
- mParams.getDismissDuration(), mParams.getLingerTimeout());
- dismissAnimation.setDuration(dismissDuration);
- dismissAnimation.setInterpolator(ACCELERATE_INTERPOLATOR);
- dismissAnimation.addListener(new AnimatorListenerAdapter() {
+ private Animator createDismissAnimator(final Key key, final KeyPreviewView keyPreviewView) {
+ final Animator animator = mParams.createDismissAnimator(keyPreviewView);
+ animator.addListener(new AnimatorListenerAdapter() {
@Override
- public void onAnimationEnd(final Animator animation) {
+ public void onAnimationEnd(final Animator animator) {
dismissKeyPreview(key, false /* withAnimation */);
}
});
- return dismissAnimation;
+ return animator;
}
- private static class KeyPreviewAnimations extends AnimatorListenerAdapter {
- private final Animator mShowUpAnimation;
- private final Animator mDismissAnimation;
+ private static class KeyPreviewAnimators extends AnimatorListenerAdapter {
+ private final Animator mShowUpAnimator;
+ private final Animator mDismissAnimator;
- public KeyPreviewAnimations(final Animator showUpAnimation,
- final Animator dismissAnimation) {
- mShowUpAnimation = showUpAnimation;
- mDismissAnimation = dismissAnimation;
+ public KeyPreviewAnimators(final Animator showUpAnimator, final Animator dismissAnimator) {
+ mShowUpAnimator = showUpAnimator;
+ mDismissAnimator = dismissAnimator;
}
public void startShowUp() {
- mShowUpAnimation.start();
+ mShowUpAnimator.start();
}
public void startDismiss() {
- if (mShowUpAnimation.isRunning()) {
- mShowUpAnimation.addListener(this);
+ if (mShowUpAnimator.isRunning()) {
+ mShowUpAnimator.addListener(this);
return;
}
- mDismissAnimation.start();
+ mDismissAnimator.start();
}
@Override
- public void onAnimationEnd(final Animator animation) {
- mDismissAnimation.start();
+ public void onAnimationEnd(final Animator animator) {
+ mDismissAnimator.start();
}
}
}
diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeyPreviewDrawParams.java b/java/src/com/android/inputmethod/keyboard/internal/KeyPreviewDrawParams.java
index 68c9831fa..5ed39f986 100644
--- a/java/src/com/android/inputmethod/keyboard/internal/KeyPreviewDrawParams.java
+++ b/java/src/com/android/inputmethod/keyboard/internal/KeyPreviewDrawParams.java
@@ -16,8 +16,14 @@
package com.android.inputmethod.keyboard.internal;
+import android.animation.Animator;
+import android.animation.AnimatorInflater;
+import android.animation.AnimatorSet;
+import android.animation.ObjectAnimator;
import android.content.res.TypedArray;
import android.view.View;
+import android.view.animation.AccelerateInterpolator;
+import android.view.animation.DecelerateInterpolator;
import com.android.inputmethod.latin.R;
@@ -26,10 +32,15 @@ public final class KeyPreviewDrawParams {
public final int mPreviewOffset;
public final int mPreviewHeight;
public final int mPreviewBackgroundResId;
+ private final int mShowUpAnimatorResId;
+ private final int mDismissAnimatorResId;
+ private boolean mHasCustomAnimationParams;
private int mShowUpDuration;
private int mDismissDuration;
- private float mShowUpStartScale;
- private float mDismissEndScale;
+ private float mShowUpStartXScale;
+ private float mShowUpStartYScale;
+ private float mDismissEndXScale;
+ private float mDismissEndYScale;
private int mLingerTimeout;
private boolean mShowPopup = true;
@@ -67,6 +78,10 @@ public final class KeyPreviewDrawParams {
R.styleable.MainKeyboardView_keyPreviewBackground, 0);
mLingerTimeout = mainKeyboardViewAttr.getInt(
R.styleable.MainKeyboardView_keyPreviewLingerTimeout, 0);
+ mShowUpAnimatorResId = mainKeyboardViewAttr.getResourceId(
+ R.styleable.MainKeyboardView_keyPreviewShowUpAnimator, 0);
+ mDismissAnimatorResId = mainKeyboardViewAttr.getResourceId(
+ R.styleable.MainKeyboardView_keyPreviewDismissAnimator, 0);
}
public void setVisibleOffset(final int previewVisibleOffset) {
@@ -112,27 +127,62 @@ public final class KeyPreviewDrawParams {
return mLingerTimeout;
}
- public void setAnimationParams(final float showUpStartScale, final int showUpDuration,
- final float dismissEndScale, final int dismissDuration) {
- mShowUpStartScale = showUpStartScale;
+ public void setAnimationParams(final boolean hasCustomAnimationParams,
+ final float showUpStartXScale, final float showUpStartYScale, final int showUpDuration,
+ final float dismissEndXScale, final float dismissEndYScale, final int dismissDuration) {
+ mHasCustomAnimationParams = hasCustomAnimationParams;
+ mShowUpStartXScale = showUpStartXScale;
+ mShowUpStartYScale = showUpStartYScale;
mShowUpDuration = showUpDuration;
- mDismissEndScale = dismissEndScale;
+ mDismissEndXScale = dismissEndXScale;
+ mDismissEndYScale = dismissEndYScale;
mDismissDuration = dismissDuration;
}
- public float getShowUpStartScale() {
- return mShowUpStartScale;
+ private static final float KEY_PREVIEW_SHOW_UP_END_SCALE = 1.0f;
+ private static final AccelerateInterpolator ACCELERATE_INTERPOLATOR =
+ new AccelerateInterpolator();
+ private static final DecelerateInterpolator DECELERATE_INTERPOLATOR =
+ new DecelerateInterpolator();
+
+ public Animator createShowUpAnimator(final View target) {
+ if (mHasCustomAnimationParams) {
+ final ObjectAnimator scaleXAnimator = ObjectAnimator.ofFloat(
+ target, View.SCALE_X, mShowUpStartXScale,
+ KEY_PREVIEW_SHOW_UP_END_SCALE);
+ final ObjectAnimator scaleYAnimator = ObjectAnimator.ofFloat(
+ target, View.SCALE_Y, mShowUpStartYScale,
+ KEY_PREVIEW_SHOW_UP_END_SCALE);
+ final AnimatorSet showUpAnimator = new AnimatorSet();
+ showUpAnimator.play(scaleXAnimator).with(scaleYAnimator);
+ showUpAnimator.setDuration(mShowUpDuration);
+ showUpAnimator.setInterpolator(DECELERATE_INTERPOLATOR);
+ return showUpAnimator;
+ }
+ final Animator animator = AnimatorInflater.loadAnimator(
+ target.getContext(), mShowUpAnimatorResId);
+ animator.setTarget(target);
+ animator.setInterpolator(DECELERATE_INTERPOLATOR);
+ return animator;
}
- public int getShowUpDuration() {
- return mShowUpDuration;
- }
-
- public float getDismissEndScale() {
- return mDismissEndScale;
- }
-
- public int getDismissDuration() {
- return mDismissDuration;
+ public Animator createDismissAnimator(final View target) {
+ if (mHasCustomAnimationParams) {
+ final ObjectAnimator scaleXAnimator = ObjectAnimator.ofFloat(
+ target, View.SCALE_X, mDismissEndXScale);
+ final ObjectAnimator scaleYAnimator = ObjectAnimator.ofFloat(
+ target, View.SCALE_Y, mDismissEndYScale);
+ final AnimatorSet dismissAnimator = new AnimatorSet();
+ dismissAnimator.play(scaleXAnimator).with(scaleYAnimator);
+ final int dismissDuration = Math.min(mDismissDuration, mLingerTimeout);
+ dismissAnimator.setDuration(dismissDuration);
+ dismissAnimator.setInterpolator(ACCELERATE_INTERPOLATOR);
+ return dismissAnimator;
+ }
+ final Animator animator = AnimatorInflater.loadAnimator(
+ target.getContext(), mDismissAnimatorResId);
+ animator.setTarget(target);
+ animator.setInterpolator(ACCELERATE_INTERPOLATOR);
+ return animator;
}
}
diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeyboardBuilder.java b/java/src/com/android/inputmethod/keyboard/internal/KeyboardBuilder.java
index 8bff27574..fa4192790 100644
--- a/java/src/com/android/inputmethod/keyboard/internal/KeyboardBuilder.java
+++ b/java/src/com/android/inputmethod/keyboard/internal/KeyboardBuilder.java
@@ -31,6 +31,7 @@ import com.android.inputmethod.annotations.UsedForTesting;
import com.android.inputmethod.keyboard.Key;
import com.android.inputmethod.keyboard.Keyboard;
import com.android.inputmethod.keyboard.KeyboardId;
+import com.android.inputmethod.keyboard.KeyboardTheme;
import com.android.inputmethod.latin.Constants;
import com.android.inputmethod.latin.R;
import com.android.inputmethod.latin.utils.ResourceUtils;
@@ -643,6 +644,9 @@ public class KeyboardBuilder<KP extends KeyboardParams> {
final boolean keyboardLayoutSetElementMatched = matchTypedValue(caseAttr,
R.styleable.Keyboard_Case_keyboardLayoutSetElement, id.mElementId,
KeyboardId.elementIdToName(id.mElementId));
+ final boolean keyboardThemeMacthed = matchTypedValue(caseAttr,
+ R.styleable.Keyboard_Case_keyboardTheme, mParams.mThemeId,
+ KeyboardTheme.getKeyboardThemeName(mParams.mThemeId));
final boolean modeMatched = matchTypedValue(caseAttr,
R.styleable.Keyboard_Case_mode, id.mMode, KeyboardId.modeName(id.mMode));
final boolean navigateNextMatched = matchBoolean(caseAttr,
@@ -671,19 +675,21 @@ public class KeyboardBuilder<KP extends KeyboardParams> {
final boolean countryCodeMatched = matchString(caseAttr,
R.styleable.Keyboard_Case_countryCode, id.mLocale.getCountry());
final boolean selected = keyboardLayoutSetMatched && keyboardLayoutSetElementMatched
- && modeMatched && navigateNextMatched && navigatePreviousMatched
- && passwordInputMatched && clobberSettingsKeyMatched && hasShortcutKeyMatched
- && languageSwitchKeyEnabledMatched && isMultiLineMatched && imeActionMatched
- && isIconDefinedMatched && localeCodeMatched && languageCodeMatched
- && countryCodeMatched;
+ && keyboardThemeMacthed && modeMatched && navigateNextMatched
+ && navigatePreviousMatched && passwordInputMatched && clobberSettingsKeyMatched
+ && hasShortcutKeyMatched && languageSwitchKeyEnabledMatched
+ && isMultiLineMatched && imeActionMatched && isIconDefinedMatched
+ && localeCodeMatched && languageCodeMatched && countryCodeMatched;
if (DEBUG) {
- startTag("<%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s>%s", TAG_CASE,
+ startTag("<%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s>%s", TAG_CASE,
textAttr(caseAttr.getString(
R.styleable.Keyboard_Case_keyboardLayoutSet), "keyboardLayoutSet"),
textAttr(caseAttr.getString(
R.styleable.Keyboard_Case_keyboardLayoutSetElement),
"keyboardLayoutSetElement"),
+ textAttr(caseAttr.getString(
+ R.styleable.Keyboard_Case_keyboardTheme), "keyboardTheme"),
textAttr(caseAttr.getString(R.styleable.Keyboard_Case_mode), "mode"),
textAttr(caseAttr.getString(R.styleable.Keyboard_Case_imeAction),
"imeAction"),
diff --git a/java/src/com/android/inputmethod/latin/BinaryDictionary.java b/java/src/com/android/inputmethod/latin/BinaryDictionary.java
index 693e1cdcc..2e108756e 100644
--- a/java/src/com/android/inputmethod/latin/BinaryDictionary.java
+++ b/java/src/com/android/inputmethod/latin/BinaryDictionary.java
@@ -83,7 +83,6 @@ public final class BinaryDictionary extends Dictionary {
public static final String DIR_NAME_SUFFIX_FOR_RECORD_MIGRATION = ".migrating";
private long mNativeDict;
- private final Locale mLocale;
private final long mDictSize;
private final String mDictFilePath;
private final boolean mUseFullEditDistance;
@@ -117,8 +116,7 @@ public final class BinaryDictionary extends Dictionary {
public BinaryDictionary(final String filename, final long offset, final long length,
final boolean useFullEditDistance, final Locale locale, final String dictType,
final boolean isUpdatable) {
- super(dictType);
- mLocale = locale;
+ super(dictType, locale);
mDictSize = length;
mDictFilePath = filename;
mIsUpdatable = isUpdatable;
@@ -138,8 +136,7 @@ public final class BinaryDictionary extends Dictionary {
public BinaryDictionary(final String filename, final boolean useFullEditDistance,
final Locale locale, final String dictType, final long formatVersion,
final Map<String, String> attributeMap) {
- super(dictType);
- mLocale = locale;
+ super(dictType, locale);
mDictSize = 0;
mDictFilePath = filename;
// On memory dictionary is always updatable.
diff --git a/java/src/com/android/inputmethod/latin/Constants.java b/java/src/com/android/inputmethod/latin/Constants.java
index 729481326..02d5eddaa 100644
--- a/java/src/com/android/inputmethod/latin/Constants.java
+++ b/java/src/com/android/inputmethod/latin/Constants.java
@@ -57,6 +57,13 @@ public final class Constants {
@SuppressWarnings("dep-ann")
public static final String FORCE_ASCII = "forceAscii";
+ /**
+ * The private IME option used to suppress the floating gesture preview for a given text
+ * field. This overrides the corresponding keyboard settings preference.
+ * {@link com.android.inputmethod.latin.settings.SettingsValues#mGestureFloatingPreviewTextEnabled}
+ */
+ public static final String NO_FLOATING_GESTURE_PREVIEW = "noGestureFloatingPreview";
+
private ImeOption() {
// This utility class is not publicly instantiable.
}
diff --git a/java/src/com/android/inputmethod/latin/Dictionary.java b/java/src/com/android/inputmethod/latin/Dictionary.java
index 560ced9c4..2f79c7662 100644
--- a/java/src/com/android/inputmethod/latin/Dictionary.java
+++ b/java/src/com/android/inputmethod/latin/Dictionary.java
@@ -16,12 +16,12 @@
package com.android.inputmethod.latin;
-import com.android.inputmethod.annotations.UsedForTesting;
import com.android.inputmethod.keyboard.ProximityInfo;
import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo;
import com.android.inputmethod.latin.settings.SettingsValuesForSuggestion;
import java.util.ArrayList;
+import java.util.Locale;
/**
* Abstract base class for a dictionary that can do a fuzzy search for words based on a set of key
@@ -62,9 +62,12 @@ public abstract class Dictionary {
// Contextual dictionary.
public static final String TYPE_CONTEXTUAL = "contextual";
public final String mDictType;
+ // The locale for this dictionary. May be null if unknown (phony dictionary for example).
+ public final Locale mLocale;
- public Dictionary(final String dictType) {
+ public Dictionary(final String dictType, final Locale locale) {
mDictType = dictType;
+ mLocale = locale;
}
/**
@@ -162,7 +165,7 @@ public abstract class Dictionary {
private static class PhonyDictionary extends Dictionary {
// This class is not publicly instantiable.
private PhonyDictionary(final String type) {
- super(type);
+ super(type, null);
}
@Override
diff --git a/java/src/com/android/inputmethod/latin/DictionaryCollection.java b/java/src/com/android/inputmethod/latin/DictionaryCollection.java
index 2b4c54d48..ca5e93714 100644
--- a/java/src/com/android/inputmethod/latin/DictionaryCollection.java
+++ b/java/src/com/android/inputmethod/latin/DictionaryCollection.java
@@ -25,6 +25,7 @@ import com.android.inputmethod.latin.settings.SettingsValuesForSuggestion;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
+import java.util.Locale;
import java.util.concurrent.CopyOnWriteArrayList;
/**
@@ -34,13 +35,14 @@ public final class DictionaryCollection extends Dictionary {
private final String TAG = DictionaryCollection.class.getSimpleName();
protected final CopyOnWriteArrayList<Dictionary> mDictionaries;
- public DictionaryCollection(final String dictType) {
- super(dictType);
+ public DictionaryCollection(final String dictType, final Locale locale) {
+ super(dictType, locale);
mDictionaries = new CopyOnWriteArrayList<>();
}
- public DictionaryCollection(final String dictType, final Dictionary... dictionaries) {
- super(dictType);
+ public DictionaryCollection(final String dictType, final Locale locale,
+ final Dictionary... dictionaries) {
+ super(dictType, locale);
if (null == dictionaries) {
mDictionaries = new CopyOnWriteArrayList<>();
} else {
@@ -49,8 +51,9 @@ public final class DictionaryCollection extends Dictionary {
}
}
- public DictionaryCollection(final String dictType, final Collection<Dictionary> dictionaries) {
- super(dictType);
+ public DictionaryCollection(final String dictType, final Locale locale,
+ final Collection<Dictionary> dictionaries) {
+ super(dictType, locale);
mDictionaries = new CopyOnWriteArrayList<>(dictionaries);
mDictionaries.removeAll(Collections.singleton(null));
}
diff --git a/java/src/com/android/inputmethod/latin/DictionaryFacilitator.java b/java/src/com/android/inputmethod/latin/DictionaryFacilitator.java
index 60d6bc3e5..480bd1f85 100644
--- a/java/src/com/android/inputmethod/latin/DictionaryFacilitator.java
+++ b/java/src/com/android/inputmethod/latin/DictionaryFacilitator.java
@@ -33,6 +33,7 @@ import com.android.inputmethod.latin.personalization.UserHistoryDictionary;
import com.android.inputmethod.latin.settings.SettingsValuesForSuggestion;
import com.android.inputmethod.latin.settings.SpacingAndPunctuations;
import com.android.inputmethod.latin.utils.DistracterFilter;
+import com.android.inputmethod.latin.utils.DistracterFilterCheckingExactMatchesAndSuggestions;
import com.android.inputmethod.latin.utils.DistracterFilterCheckingIsInDictionary;
import com.android.inputmethod.latin.utils.ExecutorUtils;
import com.android.inputmethod.latin.utils.LanguageModelParam;
@@ -59,6 +60,7 @@ public class DictionaryFacilitator {
// HACK: This threshold is being used when adding a capitalized entry in the User History
// dictionary.
private static final int CAPITALIZED_FORM_MAX_PROBABILITY_FOR_INSERT = 140;
+ private static final int MAX_DICTIONARY_FACILITATOR_CACHE_SIZE = 3;
private Dictionaries mDictionaries = new Dictionaries();
private boolean mIsUserDictEnabled = false;
@@ -66,6 +68,7 @@ public class DictionaryFacilitator {
// To synchronize assigning mDictionaries to ensure closing dictionaries.
private final Object mLock = new Object();
private final DistracterFilter mDistracterFilter;
+ private final DictionaryFacilitatorLruCache mFacilitatorCacheForPersonalization;
private static final String[] DICT_TYPES_ORDERED_TO_GET_SUGGESTIONS =
new String[] {
@@ -173,10 +176,14 @@ public class DictionaryFacilitator {
public DictionaryFacilitator() {
mDistracterFilter = DistracterFilter.EMPTY_DISTRACTER_FILTER;
+ mFacilitatorCacheForPersonalization = null;
}
- public DictionaryFacilitator(final DistracterFilter distracterFilter) {
- mDistracterFilter = distracterFilter;
+ public DictionaryFacilitator(final Context context) {
+ mFacilitatorCacheForPersonalization = new DictionaryFacilitatorLruCache(context,
+ MAX_DICTIONARY_FACILITATOR_CACHE_SIZE, "" /* dictionaryNamePrefix */);
+ mDistracterFilter = new DistracterFilterCheckingExactMatchesAndSuggestions(context,
+ mFacilitatorCacheForPersonalization);
}
public void updateEnabledSubtypes(final List<InputMethodSubtype> enabledSubtypes) {
@@ -351,6 +358,9 @@ public class DictionaryFacilitator {
for (final String dictType : DICT_TYPES_ORDERED_TO_GET_SUGGESTIONS) {
dictionaries.closeDict(dictType);
}
+ if (mFacilitatorCacheForPersonalization != null) {
+ mFacilitatorCacheForPersonalization.evictAll();
+ }
mDistracterFilter.close();
}
@@ -493,7 +503,7 @@ public class DictionaryFacilitator {
final SettingsValuesForSuggestion settingsValuesForSuggestion, final int sessionId) {
final Dictionaries dictionaries = mDictionaries;
final SuggestionResults suggestionResults =
- new SuggestionResults(dictionaries.mLocale, SuggestedWords.MAX_SUGGESTIONS);
+ new SuggestionResults(SuggestedWords.MAX_SUGGESTIONS);
final float[] languageWeight = new float[] { Dictionary.NOT_A_LANGUAGE_WEIGHT };
for (final String dictType : DICT_TYPES_ORDERED_TO_GET_SUGGESTIONS) {
final Dictionary dictionary = dictionaries.getDict(dictType);
@@ -597,11 +607,15 @@ public class DictionaryFacilitator {
}
return;
}
+ // TODO: Get locale from personalizationDataChunk.mDetectedLanguage.
+ final Locale dataChunkLocale = getLocale();
+ final DictionaryFacilitator dictionaryFacilitatorForLocale =
+ mFacilitatorCacheForPersonalization.get(dataChunkLocale);
final ArrayList<LanguageModelParam> languageModelParams =
LanguageModelParam.createLanguageModelParamsFrom(
personalizationDataChunk.mTokens,
personalizationDataChunk.mTimestampInSeconds,
- this /* dictionaryFacilitator */, spacingAndPunctuations,
+ dictionaryFacilitatorForLocale, spacingAndPunctuations,
new DistracterFilterCheckingIsInDictionary(
mDistracterFilter, personalizationDict));
if (languageModelParams == null || languageModelParams.isEmpty()) {
diff --git a/java/src/com/android/inputmethod/latin/DictionaryFactory.java b/java/src/com/android/inputmethod/latin/DictionaryFactory.java
index 59de4f82a..3459b426d 100644
--- a/java/src/com/android/inputmethod/latin/DictionaryFactory.java
+++ b/java/src/com/android/inputmethod/latin/DictionaryFactory.java
@@ -50,7 +50,7 @@ public final class DictionaryFactory {
final Locale locale, final boolean useFullEditDistance) {
if (null == locale) {
Log.e(TAG, "No locale defined for dictionary");
- return new DictionaryCollection(Dictionary.TYPE_MAIN,
+ return new DictionaryCollection(Dictionary.TYPE_MAIN, locale,
createReadOnlyBinaryDictionary(context, locale));
}
@@ -75,7 +75,7 @@ public final class DictionaryFactory {
// If the list is empty, that means we should not use any dictionary (for example, the user
// explicitly disabled the main dictionary), so the following is okay. dictList is never
// null, but if for some reason it is, DictionaryCollection handles it gracefully.
- return new DictionaryCollection(Dictionary.TYPE_MAIN, dictList);
+ return new DictionaryCollection(Dictionary.TYPE_MAIN, locale, dictList);
}
/**
@@ -188,7 +188,7 @@ public final class DictionaryFactory {
public static Dictionary createDictionaryForTest(final AssetFileAddress[] dictionaryList,
final boolean useFullEditDistance, Locale locale) {
final DictionaryCollection dictionaryCollection =
- new DictionaryCollection(Dictionary.TYPE_MAIN);
+ new DictionaryCollection(Dictionary.TYPE_MAIN, locale);
for (final AssetFileAddress address : dictionaryList) {
final ReadOnlyBinaryDictionary readOnlyBinaryDictionary = new ReadOnlyBinaryDictionary(
address.mFilename, address.mOffset, address.mLength, useFullEditDistance,
diff --git a/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java b/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java
index de384037f..a1dd67f27 100644
--- a/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java
+++ b/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java
@@ -86,9 +86,6 @@ abstract public class ExpandableBinaryDictionary extends Dictionary {
*/
private final String mDictName;
- /** Dictionary locale */
- private final Locale mLocale;
-
/** Dictionary file */
private final File mDictFile;
@@ -137,10 +134,9 @@ abstract public class ExpandableBinaryDictionary extends Dictionary {
*/
public ExpandableBinaryDictionary(final Context context, final String dictName,
final Locale locale, final String dictType, final File dictFile) {
- super(dictType);
+ super(dictType, locale);
mDictName = dictName;
mContext = context;
- mLocale = locale;
mDictFile = getDictFile(context, dictName, dictFile);
mBinaryDictionary = null;
mIsReloading = new AtomicBoolean();
diff --git a/java/src/com/android/inputmethod/latin/InputAttributes.java b/java/src/com/android/inputmethod/latin/InputAttributes.java
index ebe436128..782e18255 100644
--- a/java/src/com/android/inputmethod/latin/InputAttributes.java
+++ b/java/src/com/android/inputmethod/latin/InputAttributes.java
@@ -16,6 +16,7 @@
package com.android.inputmethod.latin;
+import static com.android.inputmethod.latin.Constants.ImeOption.NO_FLOATING_GESTURE_PREVIEW;
import static com.android.inputmethod.latin.Constants.ImeOption.NO_MICROPHONE;
import static com.android.inputmethod.latin.Constants.ImeOption.NO_MICROPHONE_COMPAT;
@@ -42,6 +43,12 @@ public final class InputAttributes {
final public boolean mApplicationSpecifiedCompletionOn;
final public boolean mShouldInsertSpacesAutomatically;
final public boolean mShouldShowVoiceInputKey;
+ /**
+ * Whether the floating gesture preview should be disabled. If true, this should override the
+ * corresponding keyboard settings preference, always suppressing the floating preview text.
+ * {@link com.android.inputmethod.latin.settings.SettingsValues#mGestureFloatingPreviewTextEnabled}
+ */
+ final public boolean mDisableGestureFloatingPreviewText;
final private int mInputType;
final private EditorInfo mEditorInfo;
final private String mPackageNameForPrivateImeOptions;
@@ -76,6 +83,7 @@ public final class InputAttributes {
mApplicationSpecifiedCompletionOn = false;
mShouldInsertSpacesAutomatically = false;
mShouldShowVoiceInputKey = false;
+ mDisableGestureFloatingPreviewText = false;
return;
}
// inputClass == InputType.TYPE_CLASS_TEXT
@@ -107,6 +115,9 @@ public final class InputAttributes {
|| hasNoMicrophoneKeyOption();
mShouldShowVoiceInputKey = !noMicrophone;
+ mDisableGestureFloatingPreviewText = InputAttributes.inPrivateImeOptions(
+ mPackageNameForPrivateImeOptions, NO_FLOATING_GESTURE_PREVIEW, editorInfo);
+
// 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.
diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java
index ee0ff5c0a..c55acd462 100644
--- a/java/src/com/android/inputmethod/latin/LatinIME.java
+++ b/java/src/com/android/inputmethod/latin/LatinIME.java
@@ -93,6 +93,7 @@ import com.android.inputmethod.latin.utils.IntentUtils;
import com.android.inputmethod.latin.utils.JniUtils;
import com.android.inputmethod.latin.utils.LeakGuardHandlerWrapper;
import com.android.inputmethod.latin.utils.StatsUtils;
+import com.android.inputmethod.latin.utils.StatsUtilsManager;
import com.android.inputmethod.latin.utils.SubtypeLocaleUtils;
import com.android.inputmethod.latin.utils.ViewLayoutUtils;
@@ -130,8 +131,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
private final Settings mSettings;
private final DictionaryFacilitator mDictionaryFacilitator =
- new DictionaryFacilitator(
- new DistracterFilterCheckingExactMatchesAndSuggestions(this /* context */));
+ new DictionaryFacilitator(this /* context */);
// TODO: Move from LatinIME.
private final PersonalizationDictionaryUpdater mPersonalizationDictionaryUpdater =
new PersonalizationDictionaryUpdater(this /* context */, mDictionaryFacilitator);
@@ -158,6 +158,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
private final SubtypeSwitcher mSubtypeSwitcher;
private final SubtypeState mSubtypeState = new SubtypeState();
private final SpecialKeyDetector mSpecialKeyDetector;
+ private StatsUtilsManager mStatsUtilsManager;
// Object for reacting to adding/removing a dictionary pack.
private final BroadcastReceiver mDictionaryPackInstallReceiver =
@@ -538,6 +539,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
mSubtypeSwitcher = SubtypeSwitcher.getInstance();
mKeyboardSwitcher = KeyboardSwitcher.getInstance();
mSpecialKeyDetector = new SpecialKeyDetector(this);
+ mStatsUtilsManager = StatsUtilsManager.getInstance();
mIsHardwareAcceleratedDrawingEnabled =
InputMethodServiceCompatUtils.enableHardwareAcceleration(this);
Log.i(TAG, "Hardware accelerated drawing: " + mIsHardwareAcceleratedDrawingEnabled);
@@ -553,8 +555,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
KeyboardSwitcher.init(this);
AudioAndHapticFeedbackManager.init(this);
AccessibilityUtils.init(this);
- StatsUtils.init(this);
-
+ mStatsUtilsManager.onCreate(this /* context */);
super.onCreate();
mHandler.onCreate();
@@ -586,7 +587,6 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
registerReceiver(mDictionaryDumpBroadcastReceiver, dictDumpFilter);
DictionaryDecayBroadcastReciever.setUpIntervalAlarmForDictionaryDecaying(this);
-
StatsUtils.onCreate(mSettings.getCurrent(), mRichImm);
}
@@ -609,7 +609,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
mDictionaryFacilitator.updateEnabledSubtypes(mRichImm.getMyEnabledInputMethodSubtypeList(
true /* allowsImplicitlySelectedSubtypes */));
refreshPersonalizationDictionarySession(currentSettingsValues);
- StatsUtils.onLoadSettings(currentSettingsValues);
+ mStatsUtilsManager.onLoadSettings(currentSettingsValues);
}
private void refreshPersonalizationDictionarySession(
@@ -699,7 +699,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
unregisterReceiver(mConnectivityAndRingerModeChangeReceiver);
unregisterReceiver(mDictionaryPackInstallReceiver);
unregisterReceiver(mDictionaryDumpBroadcastReceiver);
- StatsUtils.onDestroy();
+ mStatsUtilsManager.onDestroy();
super.onDestroy();
}
@@ -1179,10 +1179,6 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
return mInputLogic.getCurrentRecapitalizeState();
}
- public Locale getCurrentSubtypeLocale() {
- return mSubtypeSwitcher.getCurrentSubtypeLocale();
- }
-
/**
* @param codePoints code points to get coordinates for.
* @return x,y coordinates for this keyboard, as a flattened array.
@@ -1496,7 +1492,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
}
final String wordToShow;
if (CapsModeUtils.isAutoCapsMode(mInputLogic.mLastComposedWord.mCapitalizedMode)) {
- wordToShow = word.toLowerCase(getCurrentSubtypeLocale());
+ wordToShow = word.toLowerCase(mSubtypeSwitcher.getCurrentSubtypeLocale());
} else {
wordToShow = word;
}
diff --git a/java/src/com/android/inputmethod/latin/ReadOnlyBinaryDictionary.java b/java/src/com/android/inputmethod/latin/ReadOnlyBinaryDictionary.java
index 5d4fc5861..ecf25c28b 100644
--- a/java/src/com/android/inputmethod/latin/ReadOnlyBinaryDictionary.java
+++ b/java/src/com/android/inputmethod/latin/ReadOnlyBinaryDictionary.java
@@ -40,7 +40,7 @@ public final class ReadOnlyBinaryDictionary extends Dictionary {
public ReadOnlyBinaryDictionary(final String filename, final long offset, final long length,
final boolean useFullEditDistance, final Locale locale, final String dictType) {
- super(dictType);
+ super(dictType, locale);
mBinaryDictionary = new BinaryDictionary(filename, offset, length, useFullEditDistance,
locale, dictType, false /* isUpdatable */);
}
diff --git a/java/src/com/android/inputmethod/latin/RichInputConnection.java b/java/src/com/android/inputmethod/latin/RichInputConnection.java
index f1c7f4340..6b6384c48 100644
--- a/java/src/com/android/inputmethod/latin/RichInputConnection.java
+++ b/java/src/com/android/inputmethod/latin/RichInputConnection.java
@@ -922,13 +922,13 @@ public final class RichInputConnection {
* prevents the application from fulfilling the request. (TODO: Improve the API when it turns
* out that we actually need more detailed error codes)
*/
- public boolean requestUpdateCursorAnchorInfo(final boolean enableMonitor,
+ public boolean requestCursorUpdates(final boolean enableMonitor,
final boolean requestImmediateCallback) {
mIC = mParent.getCurrentInputConnection();
final boolean scheduled;
if (null != mIC) {
- scheduled = InputConnectionCompatUtils.requestUpdateCursorAnchorInfo(mIC,
- enableMonitor, requestImmediateCallback);
+ scheduled = InputConnectionCompatUtils.requestCursorUpdates(mIC, enableMonitor,
+ requestImmediateCallback);
} else {
scheduled = false;
}
diff --git a/java/src/com/android/inputmethod/latin/Suggest.java b/java/src/com/android/inputmethod/latin/Suggest.java
index 6779351fd..9e4aa40a2 100644
--- a/java/src/com/android/inputmethod/latin/Suggest.java
+++ b/java/src/com/android/inputmethod/latin/Suggest.java
@@ -84,7 +84,7 @@ public final class Suggest {
private static ArrayList<SuggestedWordInfo> getTransformedSuggestedWordInfoList(
final WordComposer wordComposer, final SuggestionResults results,
- final int trailingSingleQuotesCount) {
+ final int trailingSingleQuotesCount, final Locale defaultLocale) {
final boolean shouldMakeSuggestionsAllUpperCase = wordComposer.isAllUpperCase()
&& !wordComposer.isResumed();
final boolean isOnlyFirstCharCapitalized =
@@ -96,9 +96,11 @@ public final class Suggest {
|| 0 != trailingSingleQuotesCount) {
for (int i = 0; i < suggestionsCount; ++i) {
final SuggestedWordInfo wordInfo = suggestionsContainer.get(i);
+ final Locale wordLocale = wordInfo.mSourceDict.mLocale;
final SuggestedWordInfo transformedWordInfo = getTransformedSuggestedWordInfo(
- wordInfo, results.mLocale, shouldMakeSuggestionsAllUpperCase,
- isOnlyFirstCharCapitalized, trailingSingleQuotesCount);
+ wordInfo, null == wordLocale ? defaultLocale : wordLocale,
+ shouldMakeSuggestionsAllUpperCase, isOnlyFirstCharCapitalized,
+ trailingSingleQuotesCount);
suggestionsContainer.set(i, transformedWordInfo);
}
}
@@ -134,7 +136,7 @@ public final class Suggest {
SESSION_ID_TYPING);
final ArrayList<SuggestedWordInfo> suggestionsContainer =
getTransformedSuggestedWordInfoList(wordComposer, suggestionResults,
- trailingSingleQuotesCount);
+ trailingSingleQuotesCount, mDictionaryFacilitator.getLocale());
final boolean didRemoveTypedWord =
SuggestedWordInfo.removeDups(wordComposer.getTypedWord(), suggestionsContainer);
@@ -208,6 +210,7 @@ public final class Suggest {
final SuggestionResults suggestionResults = mDictionaryFacilitator.getSuggestionResults(
wordComposer, prevWordsInfo, proximityInfo, settingsValuesForSuggestion,
SESSION_ID_GESTURE);
+ final Locale defaultLocale = mDictionaryFacilitator.getLocale();
final ArrayList<SuggestedWordInfo> suggestionsContainer =
new ArrayList<>(suggestionResults);
final int suggestionsCount = suggestionsContainer.size();
@@ -216,9 +219,10 @@ public final class Suggest {
if (isFirstCharCapitalized || isAllUpperCase) {
for (int i = 0; i < suggestionsCount; ++i) {
final SuggestedWordInfo wordInfo = suggestionsContainer.get(i);
+ final Locale wordlocale = wordInfo.mSourceDict.mLocale;
final SuggestedWordInfo transformedWordInfo = getTransformedSuggestedWordInfo(
- wordInfo, suggestionResults.mLocale, isAllUpperCase, isFirstCharCapitalized,
- 0 /* trailingSingleQuotesCount */);
+ wordInfo, null == wordlocale ? defaultLocale : wordlocale, isAllUpperCase,
+ isFirstCharCapitalized, 0 /* trailingSingleQuotesCount */);
suggestionsContainer.set(i, transformedWordInfo);
}
}
diff --git a/java/src/com/android/inputmethod/latin/SuggestedWords.java b/java/src/com/android/inputmethod/latin/SuggestedWords.java
index 1eebabece..6bc3da885 100644
--- a/java/src/com/android/inputmethod/latin/SuggestedWords.java
+++ b/java/src/com/android/inputmethod/latin/SuggestedWords.java
@@ -429,7 +429,7 @@ public class SuggestedWords {
*/
@UsedForTesting
public SuggestedWordInfo getTypedWordInfoOrNull() {
- if (this == EMPTY) {
+ if (SuggestedWords.INDEX_OF_TYPED_WORD >= size()) {
return null;
}
final SuggestedWordInfo info = getInfo(SuggestedWords.INDEX_OF_TYPED_WORD);
diff --git a/java/src/com/android/inputmethod/latin/SystemBroadcastReceiver.java b/java/src/com/android/inputmethod/latin/SystemBroadcastReceiver.java
index e4ee42660..123ab208c 100644
--- a/java/src/com/android/inputmethod/latin/SystemBroadcastReceiver.java
+++ b/java/src/com/android/inputmethod/latin/SystemBroadcastReceiver.java
@@ -17,21 +17,16 @@
package com.android.inputmethod.latin;
import android.content.BroadcastReceiver;
-import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
-import android.content.SharedPreferences;
-import android.content.pm.PackageManager;
import android.os.Process;
-import android.preference.PreferenceManager;
import android.util.Log;
import android.view.inputmethod.InputMethodManager;
import android.view.inputmethod.InputMethodSubtype;
import com.android.inputmethod.compat.IntentCompatUtils;
-import com.android.inputmethod.latin.settings.Settings;
+import com.android.inputmethod.keyboard.KeyboardLayoutSet;
import com.android.inputmethod.latin.setup.LauncherIconVisibilityManager;
-import com.android.inputmethod.latin.setup.SetupActivity;
import com.android.inputmethod.latin.utils.UncachedInputMethodManagerUtils;
/**
@@ -58,6 +53,9 @@ import com.android.inputmethod.latin.utils.UncachedInputMethodManagerUtils;
* When a multiuser account has been created, {@link Intent#ACTION_USER_INITIALIZE} is received
* by this receiver and it checks the whether the setup wizard's icon should be appeared or not on
* the launcher depending on which partition this IME is installed.
+ *
+ * When the system locale has been changed, {@link Intent#ACTION_LOCALE_CHANGED} is received by
+ * this receiver and the {@link KeyboardLayoutSet}'s cache is cleared.
*/
public final class SystemBroadcastReceiver extends BroadcastReceiver {
private static final String TAG = SystemBroadcastReceiver.class.getSimpleName();
@@ -67,21 +65,22 @@ public final class SystemBroadcastReceiver extends BroadcastReceiver {
final String intentAction = intent.getAction();
if (Intent.ACTION_MY_PACKAGE_REPLACED.equals(intentAction)) {
Log.i(TAG, "Package has been replaced: " + context.getPackageName());
- } else if (Intent.ACTION_BOOT_COMPLETED.equals(intentAction)) {
- Log.i(TAG, "Boot has been completed");
- } else if (IntentCompatUtils.is_ACTION_USER_INITIALIZE(intentAction)) {
- Log.i(TAG, "User initialize");
- }
-
- LauncherIconVisibilityManager.onReceiveGlobalIntent(intentAction, context);
-
- if (Intent.ACTION_MY_PACKAGE_REPLACED.equals(intentAction)) {
// Need to restore additional subtypes because system always clears additional
// subtypes when the package is replaced.
RichInputMethodManager.init(context);
final RichInputMethodManager richImm = RichInputMethodManager.getInstance();
final InputMethodSubtype[] additionalSubtypes = richImm.getAdditionalSubtypes(context);
richImm.setAdditionalInputMethodSubtypes(additionalSubtypes);
+ LauncherIconVisibilityManager.updateSetupWizardIconVisibility(context);
+ } else if (Intent.ACTION_BOOT_COMPLETED.equals(intentAction)) {
+ Log.i(TAG, "Boot has been completed");
+ LauncherIconVisibilityManager.updateSetupWizardIconVisibility(context);
+ } else if (IntentCompatUtils.is_ACTION_USER_INITIALIZE(intentAction)) {
+ Log.i(TAG, "User initialize");
+ LauncherIconVisibilityManager.updateSetupWizardIconVisibility(context);
+ } else if (Intent.ACTION_LOCALE_CHANGED.equals(intentAction)) {
+ Log.i(TAG, "System locale changed");
+ KeyboardLayoutSet.onSystemLocaleChanged();
}
// The process that hosts this broadcast receiver is invoked and remains alive even after
diff --git a/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java b/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java
index 4b5edb076..233a22512 100644
--- a/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java
+++ b/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java
@@ -167,7 +167,7 @@ public final class InputLogic {
if (ProductionFlags.ENABLE_CURSOR_ANCHOR_INFO_CALLBACK) {
// AcceptTypedWord feature relies on CursorAnchorInfo.
if (settingsValues.mShouldShowUiToAcceptTypedWord) {
- mConnection.requestUpdateCursorAnchorInfo(true /* enableMonitor */,
+ mConnection.requestCursorUpdates(true /* enableMonitor */,
true /* requestImmediateCallback */);
}
}
diff --git a/java/src/com/android/inputmethod/latin/settings/CustomInputStyleSettingsFragment.java b/java/src/com/android/inputmethod/latin/settings/CustomInputStyleSettingsFragment.java
index 6d7f53cf0..d53a61654 100644
--- a/java/src/com/android/inputmethod/latin/settings/CustomInputStyleSettingsFragment.java
+++ b/java/src/com/android/inputmethod/latin/settings/CustomInputStyleSettingsFragment.java
@@ -30,11 +30,14 @@ import android.preference.DialogPreference;
import android.preference.Preference;
import android.preference.PreferenceFragment;
import android.preference.PreferenceGroup;
+import android.support.v4.view.ViewCompat;
import android.util.Pair;
+import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
+import android.view.ViewGroup;
import android.view.inputmethod.InputMethodInfo;
import android.view.inputmethod.InputMethodSubtype;
import android.widget.ArrayAdapter;
@@ -43,6 +46,7 @@ import android.widget.SpinnerAdapter;
import android.widget.Toast;
import com.android.inputmethod.compat.InputMethodSubtypeCompatUtils;
+import com.android.inputmethod.compat.ViewCompatUtils;
import com.android.inputmethod.latin.R;
import com.android.inputmethod.latin.RichInputMethodManager;
import com.android.inputmethod.latin.utils.AdditionalSubtypeUtils;
@@ -233,6 +237,12 @@ public final class CustomInputStyleSettingsFragment extends PreferenceFragment {
mSubtypeLocaleSpinner.setAdapter(mProxy.getSubtypeLocaleAdapter());
mKeyboardLayoutSetSpinner = (Spinner) v.findViewById(R.id.keyboard_layout_set_spinner);
mKeyboardLayoutSetSpinner.setAdapter(mProxy.getKeyboardLayoutSetAdapter());
+ // All keyboard layout names are in the Latin script and thus left to right. That means
+ // the view would align them to the left even if the system locale is RTL, but that
+ // would look strange. To fix this, we align them to the view's start, which will be
+ // natural for any direction.
+ ViewCompatUtils.setTextAlignment(
+ mKeyboardLayoutSetSpinner, ViewCompatUtils.TEXT_ALIGNMENT_VIEW_START);
return v;
}
@@ -398,6 +408,16 @@ public final class CustomInputStyleSettingsFragment extends PreferenceFragment {
}
@Override
+ public View onCreateView(final LayoutInflater inflater, final ViewGroup container,
+ final Bundle savedInstanceState) {
+ final View view = super.onCreateView(inflater, container, savedInstanceState);
+ // For correct display in RTL locales, we need to set the layout direction of the
+ // fragment's top view.
+ ViewCompat.setLayoutDirection(view, ViewCompat.LAYOUT_DIRECTION_LOCALE);
+ return view;
+ }
+
+ @Override
public void onActivityCreated(final Bundle savedInstanceState) {
final Context context = getActivity();
mSubtypeLocaleAdapter = new SubtypeLocaleAdapter(context);
@@ -422,7 +442,7 @@ public final class CustomInputStyleSettingsFragment extends PreferenceFragment {
KEY_SUBTYPE_FOR_SUBTYPE_ENABLER);
final SubtypePreference subtypePref = (SubtypePreference)findPreference(
mSubtypePreferenceKeyForSubtypeEnabler);
- mSubtypeEnablerNotificationDialog = createDialog(subtypePref);
+ mSubtypeEnablerNotificationDialog = createDialog();
mSubtypeEnablerNotificationDialog.show();
}
}
@@ -476,7 +496,7 @@ public final class CustomInputStyleSettingsFragment extends PreferenceFragment {
if (findDuplicatedSubtype(subtype) == null) {
mRichImm.setAdditionalInputMethodSubtypes(getSubtypes());
mSubtypePreferenceKeyForSubtypeEnabler = subtypePref.getKey();
- mSubtypeEnablerNotificationDialog = createDialog(subtypePref);
+ mSubtypeEnablerNotificationDialog = createDialog();
mSubtypeEnablerNotificationDialog.show();
return;
}
@@ -513,7 +533,7 @@ public final class CustomInputStyleSettingsFragment extends PreferenceFragment {
localeString, keyboardLayoutSetName);
}
- private AlertDialog createDialog(final SubtypePreference subtypePref) {
+ private AlertDialog createDialog() {
final AlertDialog.Builder builder = new AlertDialog.Builder(
DialogUtils.getPlatformDialogThemeContext(getActivity()));
builder.setTitle(R.string.custom_input_styles_title)
diff --git a/java/src/com/android/inputmethod/latin/settings/DebugSettings.java b/java/src/com/android/inputmethod/latin/settings/DebugSettings.java
index 63d848e2d..48f4c758c 100644
--- a/java/src/com/android/inputmethod/latin/settings/DebugSettings.java
+++ b/java/src/com/android/inputmethod/latin/settings/DebugSettings.java
@@ -23,10 +23,16 @@ public final class DebugSettings {
"force_physical_keyboard_special_key";
public static final String PREF_SHOW_UI_TO_ACCEPT_TYPED_WORD =
"pref_show_ui_to_accept_typed_word";
- public static final String PREF_KEY_PREVIEW_SHOW_UP_START_SCALE =
- "pref_key_preview_show_up_start_scale";
- public static final String PREF_KEY_PREVIEW_DISMISS_END_SCALE =
- "pref_key_preview_dismiss_end_scale";
+ public static final String PREF_HAS_CUSTOM_KEY_PREVIEW_ANIMATION_PARAMS =
+ "pref_has_custom_key_preview_animation_params";
+ public static final String PREF_KEY_PREVIEW_SHOW_UP_START_X_SCALE =
+ "pref_key_preview_show_up_start_x_scale";
+ public static final String PREF_KEY_PREVIEW_SHOW_UP_START_Y_SCALE =
+ "pref_key_preview_show_up_start_y_scale";
+ public static final String PREF_KEY_PREVIEW_DISMISS_END_X_SCALE =
+ "pref_key_preview_dismiss_end_x_scale";
+ public static final String PREF_KEY_PREVIEW_DISMISS_END_Y_SCALE =
+ "pref_key_preview_dismiss_end_y_scale";
public static final String PREF_KEY_PREVIEW_SHOW_UP_DURATION =
"pref_key_preview_show_up_duration";
public static final String PREF_KEY_PREVIEW_DISMISS_DURATION =
diff --git a/java/src/com/android/inputmethod/latin/settings/DebugSettingsFragment.java b/java/src/com/android/inputmethod/latin/settings/DebugSettingsFragment.java
index dc2f88aa8..5640e2039 100644
--- a/java/src/com/android/inputmethod/latin/settings/DebugSettingsFragment.java
+++ b/java/src/com/android/inputmethod/latin/settings/DebugSettingsFragment.java
@@ -78,12 +78,18 @@ public final class DebugSettingsFragment extends SubScreenFragment
res.getInteger(R.integer.config_key_preview_show_up_duration));
setupKeyPreviewAnimationDuration(DebugSettings.PREF_KEY_PREVIEW_DISMISS_DURATION,
res.getInteger(R.integer.config_key_preview_dismiss_duration));
- setupKeyPreviewAnimationScale(DebugSettings.PREF_KEY_PREVIEW_SHOW_UP_START_SCALE,
- ResourceUtils.getFloatFromFraction(
- res, R.fraction.config_key_preview_show_up_start_scale));
- setupKeyPreviewAnimationScale(DebugSettings.PREF_KEY_PREVIEW_DISMISS_END_SCALE,
- ResourceUtils.getFloatFromFraction(
- res, R.fraction.config_key_preview_dismiss_end_scale));
+ final float defaultKeyPreviewShowUpStartScale = ResourceUtils.getFloatFromFraction(
+ res, R.fraction.config_key_preview_show_up_start_scale);
+ final float defaultKeyPreviewDismissEndScale = ResourceUtils.getFloatFromFraction(
+ res, R.fraction.config_key_preview_dismiss_end_scale);
+ setupKeyPreviewAnimationScale(DebugSettings.PREF_KEY_PREVIEW_SHOW_UP_START_X_SCALE,
+ defaultKeyPreviewShowUpStartScale);
+ setupKeyPreviewAnimationScale(DebugSettings.PREF_KEY_PREVIEW_SHOW_UP_START_Y_SCALE,
+ defaultKeyPreviewShowUpStartScale);
+ setupKeyPreviewAnimationScale(DebugSettings.PREF_KEY_PREVIEW_DISMISS_END_X_SCALE,
+ defaultKeyPreviewDismissEndScale);
+ setupKeyPreviewAnimationScale(DebugSettings.PREF_KEY_PREVIEW_DISMISS_END_Y_SCALE,
+ defaultKeyPreviewDismissEndScale);
mServiceNeedsRestart = false;
mDebugMode = (TwoStatePreference) findPreference(DebugSettings.PREF_DEBUG_MODE);
diff --git a/java/src/com/android/inputmethod/latin/settings/SettingsValues.java b/java/src/com/android/inputmethod/latin/settings/SettingsValues.java
index 91a2b6776..11291959c 100644
--- a/java/src/com/android/inputmethod/latin/settings/SettingsValues.java
+++ b/java/src/com/android/inputmethod/latin/settings/SettingsValues.java
@@ -104,10 +104,13 @@ public class SettingsValues {
// Debug settings
public final boolean mIsInternal;
+ public final boolean mHasCustomKeyPreviewAnimationParams;
public final int mKeyPreviewShowUpDuration;
public final int mKeyPreviewDismissDuration;
- public final float mKeyPreviewShowUpStartScale;
- public final float mKeyPreviewDismissEndScale;
+ public final float mKeyPreviewShowUpStartXScale;
+ public final float mKeyPreviewShowUpStartYScale;
+ public final float mKeyPreviewDismissEndXScale;
+ public final float mKeyPreviewDismissEndYScale;
public SettingsValues(final Context context, final SharedPreferences prefs, final Resources res,
final InputAttributes inputAttributes) {
@@ -162,8 +165,8 @@ public class SettingsValues {
autoCorrectionThresholdRawValue);
mGestureInputEnabled = Settings.readGestureInputEnabled(prefs, res);
mGestureTrailEnabled = prefs.getBoolean(Settings.PREF_GESTURE_PREVIEW_TRAIL, true);
- mGestureFloatingPreviewTextEnabled = prefs.getBoolean(
- Settings.PREF_GESTURE_FLOATING_PREVIEW_TEXT, true);
+ mGestureFloatingPreviewTextEnabled = !mInputAttributes.mDisableGestureFloatingPreviewText
+ && prefs.getBoolean(Settings.PREF_GESTURE_FLOATING_PREVIEW_TEXT, true);
mPhraseGestureEnabled = Settings.readPhraseGestureEnabled(prefs, res);
mAutoCorrectionEnabledPerUserSettings = mAutoCorrectEnabled
&& !mInputAttributes.mInputTypeNoAutoCorrect;
@@ -179,20 +182,30 @@ public class SettingsValues {
mTextHighlightColorForAddToDictionaryIndicator = res.getColor(
R.color.text_decorator_add_to_dictionary_indicator_text_highlight_color);
mIsInternal = Settings.isInternal(prefs);
+ mHasCustomKeyPreviewAnimationParams = prefs.getBoolean(
+ DebugSettings.PREF_HAS_CUSTOM_KEY_PREVIEW_ANIMATION_PARAMS, false);
mKeyPreviewShowUpDuration = Settings.readKeyPreviewAnimationDuration(
prefs, DebugSettings.PREF_KEY_PREVIEW_SHOW_UP_DURATION,
res.getInteger(R.integer.config_key_preview_show_up_duration));
mKeyPreviewDismissDuration = Settings.readKeyPreviewAnimationDuration(
prefs, DebugSettings.PREF_KEY_PREVIEW_DISMISS_DURATION,
res.getInteger(R.integer.config_key_preview_dismiss_duration));
- mKeyPreviewShowUpStartScale = Settings.readKeyPreviewAnimationScale(
- prefs, DebugSettings.PREF_KEY_PREVIEW_SHOW_UP_START_SCALE,
- ResourceUtils.getFloatFromFraction(
- res, R.fraction.config_key_preview_show_up_start_scale));
- mKeyPreviewDismissEndScale = Settings.readKeyPreviewAnimationScale(
- prefs, DebugSettings.PREF_KEY_PREVIEW_DISMISS_END_SCALE,
- ResourceUtils.getFloatFromFraction(
- res, R.fraction.config_key_preview_dismiss_end_scale));
+ final float defaultKeyPreviewShowUpStartScale = ResourceUtils.getFloatFromFraction(
+ res, R.fraction.config_key_preview_show_up_start_scale);
+ final float defaultKeyPreviewDismissEndScale = ResourceUtils.getFloatFromFraction(
+ res, R.fraction.config_key_preview_dismiss_end_scale);
+ mKeyPreviewShowUpStartXScale = Settings.readKeyPreviewAnimationScale(
+ prefs, DebugSettings.PREF_KEY_PREVIEW_SHOW_UP_START_X_SCALE,
+ defaultKeyPreviewShowUpStartScale);
+ mKeyPreviewShowUpStartYScale = Settings.readKeyPreviewAnimationScale(
+ prefs, DebugSettings.PREF_KEY_PREVIEW_SHOW_UP_START_Y_SCALE,
+ defaultKeyPreviewShowUpStartScale);
+ mKeyPreviewDismissEndXScale = Settings.readKeyPreviewAnimationScale(
+ prefs, DebugSettings.PREF_KEY_PREVIEW_DISMISS_END_X_SCALE,
+ defaultKeyPreviewDismissEndScale);
+ mKeyPreviewDismissEndYScale = Settings.readKeyPreviewAnimationScale(
+ prefs, DebugSettings.PREF_KEY_PREVIEW_DISMISS_END_Y_SCALE,
+ defaultKeyPreviewDismissEndScale);
mDisplayOrientation = res.getConfiguration().orientation;
mAppWorkarounds = new AsyncResultHolder<>();
final PackageInfo packageInfo = TargetPackageInfoGetterTask.getCachedPackageInfo(
@@ -429,10 +442,14 @@ public class SettingsValues {
sb.append("" + mKeyPreviewShowUpDuration);
sb.append("\n mKeyPreviewDismissDuration = ");
sb.append("" + mKeyPreviewDismissDuration);
- sb.append("\n mKeyPreviewShowUpStartScale = ");
- sb.append("" + mKeyPreviewShowUpStartScale);
- sb.append("\n mKeyPreviewDismissEndScale = ");
- sb.append("" + mKeyPreviewDismissEndScale);
+ sb.append("\n mKeyPreviewShowUpStartScaleX = ");
+ sb.append("" + mKeyPreviewShowUpStartXScale);
+ sb.append("\n mKeyPreviewShowUpStartScaleY = ");
+ sb.append("" + mKeyPreviewShowUpStartYScale);
+ sb.append("\n mKeyPreviewDismissEndScaleX = ");
+ sb.append("" + mKeyPreviewDismissEndXScale);
+ sb.append("\n mKeyPreviewDismissEndScaleY = ");
+ sb.append("" + mKeyPreviewDismissEndYScale);
return sb.toString();
}
}
diff --git a/java/src/com/android/inputmethod/latin/setup/LauncherIconVisibilityManager.java b/java/src/com/android/inputmethod/latin/setup/LauncherIconVisibilityManager.java
index 9585736e7..3f0b10225 100644
--- a/java/src/com/android/inputmethod/latin/setup/LauncherIconVisibilityManager.java
+++ b/java/src/com/android/inputmethod/latin/setup/LauncherIconVisibilityManager.java
@@ -24,7 +24,6 @@ import android.content.pm.PackageManager;
import android.preference.PreferenceManager;
import android.util.Log;
-import com.android.inputmethod.compat.IntentCompatUtils;
import com.android.inputmethod.latin.settings.Settings;
/**
@@ -55,14 +54,6 @@ import com.android.inputmethod.latin.settings.Settings;
public final class LauncherIconVisibilityManager {
private static final String TAG = LauncherIconVisibilityManager.class.getSimpleName();
- public static void onReceiveGlobalIntent(final String action, final Context context) {
- if (Intent.ACTION_MY_PACKAGE_REPLACED.equals(action) ||
- Intent.ACTION_BOOT_COMPLETED.equals(action) ||
- IntentCompatUtils.is_ACTION_USER_INITIALIZE(action)) {
- updateSetupWizardIconVisibility(context);
- }
- }
-
public static void updateSetupWizardIconVisibility(final Context context) {
final ComponentName setupWizardActivity = new ComponentName(context, SetupActivity.class);
final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
diff --git a/java/src/com/android/inputmethod/latin/utils/DistracterFilterCheckingExactMatchesAndSuggestions.java b/java/src/com/android/inputmethod/latin/utils/DistracterFilterCheckingExactMatchesAndSuggestions.java
index 2207ffea9..e10571e4a 100644
--- a/java/src/com/android/inputmethod/latin/utils/DistracterFilterCheckingExactMatchesAndSuggestions.java
+++ b/java/src/com/android/inputmethod/latin/utils/DistracterFilterCheckingExactMatchesAndSuggestions.java
@@ -20,13 +20,14 @@ import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
-import java.util.concurrent.TimeUnit;
+import java.util.concurrent.ConcurrentHashMap;
import android.content.Context;
import android.content.res.Resources;
import android.text.InputType;
import android.util.Log;
import android.util.LruCache;
+import android.util.Pair;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputMethodSubtype;
@@ -34,6 +35,7 @@ import com.android.inputmethod.keyboard.Keyboard;
import com.android.inputmethod.keyboard.KeyboardId;
import com.android.inputmethod.keyboard.KeyboardLayoutSet;
import com.android.inputmethod.latin.DictionaryFacilitator;
+import com.android.inputmethod.latin.DictionaryFacilitatorLruCache;
import com.android.inputmethod.latin.PrevWordsInfo;
import com.android.inputmethod.latin.RichInputMethodSubtype;
import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo;
@@ -49,15 +51,15 @@ public class DistracterFilterCheckingExactMatchesAndSuggestions implements Distr
DistracterFilterCheckingExactMatchesAndSuggestions.class.getSimpleName();
private static final boolean DEBUG = false;
- private static final long TIMEOUT_TO_WAIT_LOADING_DICTIONARIES_IN_SECONDS = 120;
- private static final int MAX_DISTRACTERS_CACHE_SIZE = 512;
+ private static final int MAX_DISTRACTERS_CACHE_SIZE = 1024;
private final Context mContext;
- private final Map<Locale, InputMethodSubtype> mLocaleToSubtypeMap;
- private final Map<Locale, Keyboard> mLocaleToKeyboardMap;
- private final DictionaryFacilitator mDictionaryFacilitator;
- private final LruCache<String, Boolean> mDistractersCache;
- private Keyboard mKeyboard;
+ private final ConcurrentHashMap<Locale, InputMethodSubtype> mLocaleToSubtypeCache;
+ private final ConcurrentHashMap<Locale, Keyboard> mLocaleToKeyboardCache;
+ private final DictionaryFacilitatorLruCache mDictionaryFacilitatorLruCache;
+ // The key is a pair of a locale and a word. The value indicates the word is a distracter to
+ // words of the locale.
+ private final LruCache<Pair<Locale, String>, Boolean> mDistractersCache;
private final Object mLock = new Object();
// If the score of the top suggestion exceeds this value, the tested word (e.g.,
@@ -71,19 +73,23 @@ public class DistracterFilterCheckingExactMatchesAndSuggestions implements Distr
* Create a DistracterFilter instance.
*
* @param context the context.
+ * @param dictionaryFacilitatorLruCache the cache of dictionaryFacilitators that are used for
+ * checking distracters.
*/
- public DistracterFilterCheckingExactMatchesAndSuggestions(final Context context) {
+ public DistracterFilterCheckingExactMatchesAndSuggestions(final Context context,
+ final DictionaryFacilitatorLruCache dictionaryFacilitatorLruCache) {
mContext = context;
- mLocaleToSubtypeMap = new HashMap<>();
- mLocaleToKeyboardMap = new HashMap<>();
- mDictionaryFacilitator = new DictionaryFacilitator();
+ mLocaleToSubtypeCache = new ConcurrentHashMap<>();
+ mLocaleToKeyboardCache = new ConcurrentHashMap<>();
+ mDictionaryFacilitatorLruCache = dictionaryFacilitatorLruCache;
mDistractersCache = new LruCache<>(MAX_DISTRACTERS_CACHE_SIZE);
- mKeyboard = null;
}
@Override
public void close() {
- mDictionaryFacilitator.closeDictionaries();
+ mLocaleToSubtypeCache.clear();
+ mLocaleToKeyboardCache.clear();
+ mDistractersCache.evictAll();
}
@Override
@@ -100,29 +106,36 @@ public class DistracterFilterCheckingExactMatchesAndSuggestions implements Distr
newLocaleToSubtypeMap.put(locale, subtype);
}
}
- if (mLocaleToSubtypeMap.equals(newLocaleToSubtypeMap)) {
+ if (mLocaleToSubtypeCache.equals(newLocaleToSubtypeMap)) {
// Enabled subtypes have not been changed.
return;
}
- synchronized (mLock) {
- mLocaleToSubtypeMap.clear();
- mLocaleToSubtypeMap.putAll(newLocaleToSubtypeMap);
- mLocaleToKeyboardMap.clear();
+ // Update subtype and keyboard map for locales that are in the current mapping.
+ for (final Locale locale: mLocaleToSubtypeCache.keySet()) {
+ if (newLocaleToSubtypeMap.containsKey(locale)) {
+ final InputMethodSubtype newSubtype = newLocaleToSubtypeMap.remove(locale);
+ if (newSubtype.equals(newLocaleToSubtypeMap.get(locale))) {
+ // Mapping has not been changed.
+ continue;
+ }
+ mLocaleToSubtypeCache.replace(locale, newSubtype);
+ } else {
+ mLocaleToSubtypeCache.remove(locale);
+ }
+ mLocaleToKeyboardCache.remove(locale);
}
+ // Add locales that are not in the current mapping.
+ mLocaleToSubtypeCache.putAll(newLocaleToSubtypeMap);
}
- private void loadKeyboardForLocale(final Locale newLocale) {
- final Keyboard cachedKeyboard = mLocaleToKeyboardMap.get(newLocale);
+ private Keyboard getKeyboardForLocale(final Locale locale) {
+ final Keyboard cachedKeyboard = mLocaleToKeyboardCache.get(locale);
if (cachedKeyboard != null) {
- mKeyboard = cachedKeyboard;
- return;
- }
- final InputMethodSubtype subtype;
- synchronized (mLock) {
- subtype = mLocaleToSubtypeMap.get(newLocale);
+ return cachedKeyboard;
}
+ final InputMethodSubtype subtype = mLocaleToSubtypeCache.get(locale);
if (subtype == null) {
- return;
+ return null;
}
final EditorInfo editorInfo = new EditorInfo();
editorInfo.inputType = InputType.TYPE_CLASS_TEXT;
@@ -135,15 +148,9 @@ public class DistracterFilterCheckingExactMatchesAndSuggestions implements Distr
builder.setSubtype(new RichInputMethodSubtype(subtype));
builder.setIsSpellChecker(false /* isSpellChecker */);
final KeyboardLayoutSet layoutSet = builder.build();
- mKeyboard = layoutSet.getKeyboard(KeyboardId.ELEMENT_ALPHABET);
- }
-
- private void loadDictionariesForLocale(final Locale newlocale) throws InterruptedException {
- mDictionaryFacilitator.resetDictionaries(mContext, newlocale,
- false /* useContactsDict */, false /* usePersonalizedDicts */,
- false /* forceReloadMainDictionary */, null /* listener */);
- mDictionaryFacilitator.waitForLoadingMainDictionary(
- TIMEOUT_TO_WAIT_LOADING_DICTIONARIES_IN_SECONDS, TimeUnit.SECONDS);
+ final Keyboard newKeyboard = layoutSet.getKeyboard(KeyboardId.ELEMENT_ALPHABET);
+ mLocaleToKeyboardCache.put(locale, newKeyboard);
+ return newKeyboard;
}
/**
@@ -161,30 +168,18 @@ public class DistracterFilterCheckingExactMatchesAndSuggestions implements Distr
if (locale == null) {
return false;
}
- if (!locale.equals(mDictionaryFacilitator.getLocale())) {
- synchronized (mLock) {
- if (!mLocaleToSubtypeMap.containsKey(locale)) {
- Log.e(TAG, "Locale " + locale + " is not enabled.");
- // TODO: Investigate what we should do for disabled locales.
- return false;
- }
- loadKeyboardForLocale(locale);
- // Reset dictionaries for the locale.
- try {
- mDistractersCache.evictAll();
- loadDictionariesForLocale(locale);
- } catch (final InterruptedException e) {
- Log.e(TAG, "Interrupted while waiting for loading dicts in DistracterFilter",
- e);
- return false;
- }
- }
+ if (!mLocaleToSubtypeCache.containsKey(locale)) {
+ Log.e(TAG, "Locale " + locale + " is not enabled.");
+ // TODO: Investigate what we should do for disabled locales.
+ return false;
}
-
+ final DictionaryFacilitator dictionaryFacilitator =
+ mDictionaryFacilitatorLruCache.get(locale);
if (DEBUG) {
Log.d(TAG, "testedWord: " + testedWord);
}
- final Boolean isCachedDistracter = mDistractersCache.get(testedWord);
+ final Pair<Locale, String> cacheKey = new Pair<>(locale, testedWord);
+ final Boolean isCachedDistracter = mDistractersCache.get(cacheKey);
if (isCachedDistracter != null && isCachedDistracter) {
if (DEBUG) {
Log.d(TAG, "isDistracter: true (cache hit)");
@@ -193,13 +188,13 @@ public class DistracterFilterCheckingExactMatchesAndSuggestions implements Distr
}
final boolean isDistracterCheckedByGetMaxFreqencyOfExactMatches =
- checkDistracterUsingMaxFreqencyOfExactMatches(testedWord);
+ checkDistracterUsingMaxFreqencyOfExactMatches(dictionaryFacilitator, testedWord);
if (isDistracterCheckedByGetMaxFreqencyOfExactMatches) {
- // Add the word to the cache.
- mDistractersCache.put(testedWord, Boolean.TRUE);
+ // Add the pair of locale and word to the cache.
+ mDistractersCache.put(cacheKey, Boolean.TRUE);
return true;
}
- final boolean isValidWord = mDictionaryFacilitator.isValidWord(testedWord,
+ final boolean isValidWord = dictionaryFacilitator.isValidWord(testedWord,
false /* ignoreCase */);
if (isValidWord) {
// Valid word is not a distractor.
@@ -209,21 +204,23 @@ public class DistracterFilterCheckingExactMatchesAndSuggestions implements Distr
return false;
}
+ final Keyboard keyboard = getKeyboardForLocale(locale);
final boolean isDistracterCheckedByGetSuggestion =
- checkDistracterUsingGetSuggestions(testedWord);
+ checkDistracterUsingGetSuggestions(dictionaryFacilitator, keyboard, testedWord);
if (isDistracterCheckedByGetSuggestion) {
- // Add the word to the cache.
- mDistractersCache.put(testedWord, Boolean.TRUE);
+ // Add the pair of locale and word to the cache.
+ mDistractersCache.put(cacheKey, Boolean.TRUE);
return true;
}
return false;
}
- private boolean checkDistracterUsingMaxFreqencyOfExactMatches(final String testedWord) {
+ private static boolean checkDistracterUsingMaxFreqencyOfExactMatches(
+ final DictionaryFacilitator dictionaryFacilitator, final String testedWord) {
// The tested word is a distracter when there is a word that is exact matched to the tested
// word and its probability is higher than the tested word's probability.
- final int perfectMatchFreq = mDictionaryFacilitator.getFrequency(testedWord);
- final int exactMatchFreq = mDictionaryFacilitator.getMaxFrequencyOfExactMatches(testedWord);
+ final int perfectMatchFreq = dictionaryFacilitator.getFrequency(testedWord);
+ final int exactMatchFreq = dictionaryFacilitator.getMaxFrequencyOfExactMatches(testedWord);
final boolean isDistracter = perfectMatchFreq < exactMatchFreq;
if (DEBUG) {
Log.d(TAG, "perfectMatchFreq: " + perfectMatchFreq);
@@ -233,8 +230,10 @@ public class DistracterFilterCheckingExactMatchesAndSuggestions implements Distr
return isDistracter;
}
- private boolean checkDistracterUsingGetSuggestions(final String testedWord) {
- if (mKeyboard == null) {
+ private boolean checkDistracterUsingGetSuggestions(
+ final DictionaryFacilitator dictionaryFacilitator, final Keyboard keyboard,
+ final String testedWord) {
+ if (keyboard == null) {
return false;
}
final SettingsValuesForSuggestion settingsValuesForSuggestion =
@@ -247,24 +246,24 @@ public class DistracterFilterCheckingExactMatchesAndSuggestions implements Distr
testedWord;
final WordComposer composer = new WordComposer();
final int[] codePoints = StringUtils.toCodePointArray(testedWord);
-
+ final int[] coordinates = keyboard.getCoordinates(codePoints);
+ composer.setComposingWord(codePoints, coordinates);
+ final SuggestionResults suggestionResults;
synchronized (mLock) {
- final int[] coordinates = mKeyboard.getCoordinates(codePoints);
- composer.setComposingWord(codePoints, coordinates);
- final SuggestionResults suggestionResults = mDictionaryFacilitator.getSuggestionResults(
- composer, PrevWordsInfo.EMPTY_PREV_WORDS_INFO, mKeyboard.getProximityInfo(),
+ suggestionResults = dictionaryFacilitator.getSuggestionResults(
+ composer, PrevWordsInfo.EMPTY_PREV_WORDS_INFO, keyboard.getProximityInfo(),
settingsValuesForSuggestion, 0 /* sessionId */);
- if (suggestionResults.isEmpty()) {
- return false;
- }
- final SuggestedWordInfo firstSuggestion = suggestionResults.first();
- final boolean isDistractor = suggestionExceedsDistracterThreshold(
- firstSuggestion, consideredWord, DISTRACTER_WORD_SCORE_THRESHOLD);
- if (DEBUG) {
- Log.d(TAG, "isDistracter: " + isDistractor);
- }
- return isDistractor;
}
+ if (suggestionResults.isEmpty()) {
+ return false;
+ }
+ final SuggestedWordInfo firstSuggestion = suggestionResults.first();
+ final boolean isDistractor = suggestionExceedsDistracterThreshold(
+ firstSuggestion, consideredWord, DISTRACTER_WORD_SCORE_THRESHOLD);
+ if (DEBUG) {
+ Log.d(TAG, "isDistracter: " + isDistractor);
+ }
+ return isDistractor;
}
private static boolean suggestionExceedsDistracterThreshold(final SuggestedWordInfo suggestion,
diff --git a/java/src/com/android/inputmethod/latin/utils/SuggestionResults.java b/java/src/com/android/inputmethod/latin/utils/SuggestionResults.java
index 7170bd789..eaa5743d4 100644
--- a/java/src/com/android/inputmethod/latin/utils/SuggestionResults.java
+++ b/java/src/com/android/inputmethod/latin/utils/SuggestionResults.java
@@ -30,18 +30,16 @@ import java.util.TreeSet;
* than its limit
*/
public final class SuggestionResults extends TreeSet<SuggestedWordInfo> {
- public final Locale mLocale;
public final ArrayList<SuggestedWordInfo> mRawSuggestions;
private final int mCapacity;
- public SuggestionResults(final Locale locale, final int capacity) {
- this(locale, sSuggestedWordInfoComparator, capacity);
+ public SuggestionResults(final int capacity) {
+ this(sSuggestedWordInfoComparator, capacity);
}
- public SuggestionResults(final Locale locale, final Comparator<SuggestedWordInfo> comparator,
+ public SuggestionResults(final Comparator<SuggestedWordInfo> comparator,
final int capacity) {
super(comparator);
- mLocale = locale;
mCapacity = capacity;
if (ProductionFlags.INCLUDE_RAW_SUGGESTIONS) {
mRawSuggestions = new ArrayList<>();