Merge "Lazy-load textclassifier settings." into qt-dev am: 9829cf5451
am: 772447f0bd
Change-Id: Ia1e191f134c94e0dcfd08b92e58f2f53b7a6eebe
diff --git a/apct-tests/perftests/textclassifier/src/android/view/textclassifier/TextClassificationManagerPerfTest.java b/apct-tests/perftests/textclassifier/src/android/view/textclassifier/TextClassificationManagerPerfTest.java
index c149195..bd3b673 100644
--- a/apct-tests/perftests/textclassifier/src/android/view/textclassifier/TextClassificationManagerPerfTest.java
+++ b/apct-tests/perftests/textclassifier/src/android/view/textclassifier/TextClassificationManagerPerfTest.java
@@ -52,7 +52,7 @@
BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
textClassificationManager.getTextClassifier();
- textClassificationManager.invalidate();
+ textClassificationManager.invalidateForTesting();
}
}
@@ -68,7 +68,7 @@
BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
textClassificationManager.getTextClassifier();
- textClassificationManager.invalidate();
+ textClassificationManager.invalidateForTesting();
}
}
}
diff --git a/core/java/android/provider/DeviceConfig.java b/core/java/android/provider/DeviceConfig.java
index 9b25a01..ea397cc 100644
--- a/core/java/android/provider/DeviceConfig.java
+++ b/core/java/android/provider/DeviceConfig.java
@@ -271,6 +271,7 @@
* Namespace for TextClassifier related features.
*
* @hide
+ * @see android.provider.Settings.Global.TEXT_CLASSIFIER_CONSTANTS
*/
@SystemApi
public static final String NAMESPACE_TEXTCLASSIFIER = "textclassifier";
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 52508f7..e0602cf 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -12034,26 +12034,27 @@
* entity_list_default use ":" as delimiter for values. Ex:
*
* <pre>
- * smart_linkify_enabled (boolean)
- * system_textclassifier_enabled (boolean)
+ * classify_text_max_range_length (int)
+ * detect_language_from_text_enabled (boolean)
+ * entity_list_default (String[])
+ * entity_list_editable (String[])
+ * entity_list_not_editable (String[])
+ * generate_links_log_sample_rate (int)
+ * generate_links_max_text_length (int)
+ * in_app_conversation_action_types_default (String[])
+ * lang_id_context_settings (float[])
+ * lang_id_threshold_override (float)
+ * local_textclassifier_enabled (boolean)
* model_dark_launch_enabled (boolean)
- * smart_selection_enabled (boolean)
- * smart_text_share_enabled (boolean)
+ * notification_conversation_action_types_default (String[])
* smart_linkify_enabled (boolean)
* smart_select_animation_enabled (boolean)
+ * smart_selection_enabled (boolean)
+ * smart_text_share_enabled (boolean)
* suggest_selection_max_range_length (int)
- * classify_text_max_range_length (int)
- * generate_links_max_text_length (int)
- * generate_links_log_sample_rate (int)
- * entity_list_default (String[])
- * entity_list_not_editable (String[])
- * entity_list_editable (String[])
- * in_app_conversation_action_types_default (String[])
- * notification_conversation_action_types_default (String[])
- * lang_id_threshold_override (float)
+ * system_textclassifier_enabled (boolean)
* template_intent_factory_enabled (boolean)
* translate_in_classification_enabled (boolean)
- * detect_language_from_text_enabled (boolean)
* </pre>
*
* <p>
diff --git a/core/java/android/view/textclassifier/ConfigParser.java b/core/java/android/view/textclassifier/ConfigParser.java
index b475412..63de059 100644
--- a/core/java/android/view/textclassifier/ConfigParser.java
+++ b/core/java/android/view/textclassifier/ConfigParser.java
@@ -17,9 +17,19 @@
import android.annotation.Nullable;
import android.provider.DeviceConfig;
+import android.util.ArrayMap;
import android.util.KeyValueListParser;
+import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.annotations.VisibleForTesting.Visibility;
+import com.android.internal.util.Preconditions;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.function.Supplier;
/**
* Retrieves settings from {@link DeviceConfig} and {@link android.provider.Settings}.
@@ -27,80 +37,228 @@
*
* @hide
*/
-@VisibleForTesting
+@VisibleForTesting(visibility = Visibility.PACKAGE)
public final class ConfigParser {
private static final String TAG = "ConfigParser";
- private final KeyValueListParser mParser;
+ static final boolean ENABLE_DEVICE_CONFIG = true;
- // TODO: Re-enable DeviceConfig when it has reasonable performance or just delete the
- // option of using DeviceConfig entirely.
- static final boolean ENABLE_DEVICE_CONFIG = false;
+ private static final String STRING_LIST_DELIMITER = ":";
- public ConfigParser(@Nullable String textClassifierConstants) {
- final KeyValueListParser parser = new KeyValueListParser(',');
- try {
- parser.setString(textClassifierConstants);
- } catch (IllegalArgumentException e) {
- // Failed to parse the settings string, log this and move on with defaults.
- Log.w(TAG, "Bad text_classifier_constants: " + textClassifierConstants);
+ private final Supplier<String> mLegacySettingsSupplier;
+ private final Object mLock = new Object();
+ @GuardedBy("mLock")
+ private final Map<String, Object> mCache = new ArrayMap<>();
+ @GuardedBy("mLock")
+ private @Nullable KeyValueListParser mSettingsParser; // Call getLegacySettings() instead.
+
+ public ConfigParser(Supplier<String> legacySettingsSupplier) {
+ mLegacySettingsSupplier = Preconditions.checkNotNull(legacySettingsSupplier);
+ }
+
+ private KeyValueListParser getLegacySettings() {
+ synchronized (mLock) {
+ if (mSettingsParser == null) {
+ final String legacySettings = mLegacySettingsSupplier.get();
+ try {
+ mSettingsParser = new KeyValueListParser(',');
+ mSettingsParser.setString(legacySettings);
+ } catch (IllegalArgumentException e) {
+ // Failed to parse the settings string, log this and move on with defaults.
+ Log.w(TAG, "Bad text_classifier_constants: " + legacySettings);
+ }
+ }
+ return mSettingsParser;
}
- mParser = parser;
}
/**
- * Reads a boolean flag.
+ * Reads a boolean setting through the cache.
*/
public boolean getBoolean(String key, boolean defaultValue) {
- if (ENABLE_DEVICE_CONFIG) {
- return DeviceConfig.getBoolean(
- DeviceConfig.NAMESPACE_TEXTCLASSIFIER,
- key,
- mParser.getBoolean(key, defaultValue));
- } else {
- return mParser.getBoolean(key, defaultValue);
+ synchronized (mLock) {
+ final Object cached = mCache.get(key);
+ if (cached instanceof Boolean) {
+ return (boolean) cached;
+ }
+ final boolean value;
+ if (ENABLE_DEVICE_CONFIG) {
+ value = DeviceConfig.getBoolean(
+ DeviceConfig.NAMESPACE_TEXTCLASSIFIER,
+ key,
+ getLegacySettings().getBoolean(key, defaultValue));
+ } else {
+ value = getLegacySettings().getBoolean(key, defaultValue);
+ }
+ mCache.put(key, value);
+ return value;
}
}
/**
- * Reads an integer flag.
+ * Reads an integer setting through the cache.
*/
public int getInt(String key, int defaultValue) {
- if (ENABLE_DEVICE_CONFIG) {
- return DeviceConfig.getInt(
- DeviceConfig.NAMESPACE_TEXTCLASSIFIER,
- key,
- mParser.getInt(key, defaultValue));
- } else {
- return mParser.getInt(key, defaultValue);
+ synchronized (mLock) {
+ final Object cached = mCache.get(key);
+ if (cached instanceof Integer) {
+ return (int) cached;
+ }
+ final int value;
+ if (ENABLE_DEVICE_CONFIG) {
+ value = DeviceConfig.getInt(
+ DeviceConfig.NAMESPACE_TEXTCLASSIFIER,
+ key,
+ getLegacySettings().getInt(key, defaultValue));
+ } else {
+ value = getLegacySettings().getInt(key, defaultValue);
+ }
+ mCache.put(key, value);
+ return value;
}
}
/**
- * Reads a float flag.
+ * Reads a float setting through the cache.
*/
public float getFloat(String key, float defaultValue) {
- if (ENABLE_DEVICE_CONFIG) {
- return DeviceConfig.getFloat(
- DeviceConfig.NAMESPACE_TEXTCLASSIFIER,
- key,
- mParser.getFloat(key, defaultValue));
- } else {
- return mParser.getFloat(key, defaultValue);
+ synchronized (mLock) {
+ final Object cached = mCache.get(key);
+ if (cached instanceof Float) {
+ return (float) cached;
+ }
+ final float value;
+ if (ENABLE_DEVICE_CONFIG) {
+ value = DeviceConfig.getFloat(
+ DeviceConfig.NAMESPACE_TEXTCLASSIFIER,
+ key,
+ getLegacySettings().getFloat(key, defaultValue));
+ } else {
+ value = getLegacySettings().getFloat(key, defaultValue);
+ }
+ mCache.put(key, value);
+ return value;
}
}
/**
- * Reads a string flag.
+ * Reads a string setting through the cache.
*/
public String getString(String key, String defaultValue) {
- if (ENABLE_DEVICE_CONFIG) {
- return DeviceConfig.getString(
- DeviceConfig.NAMESPACE_TEXTCLASSIFIER,
- key,
- mParser.getString(key, defaultValue));
+ synchronized (mLock) {
+ final Object cached = mCache.get(key);
+ if (cached instanceof String) {
+ return (String) cached;
+ }
+ final String value;
+ if (ENABLE_DEVICE_CONFIG) {
+ value = DeviceConfig.getString(
+ DeviceConfig.NAMESPACE_TEXTCLASSIFIER,
+ key,
+ getLegacySettings().getString(key, defaultValue));
+ } else {
+ value = getLegacySettings().getString(key, defaultValue);
+ }
+ mCache.put(key, value);
+ return value;
+ }
+ }
+
+ /**
+ * Reads a string list setting through the cache.
+ */
+ public List<String> getStringList(String key, List<String> defaultValue) {
+ synchronized (mLock) {
+ final Object cached = mCache.get(key);
+ if (cached instanceof List) {
+ final List asList = (List) cached;
+ if (asList.isEmpty()) {
+ return Collections.emptyList();
+ } else if (asList.get(0) instanceof String) {
+ return (List<String>) cached;
+ }
+ }
+ final List<String> value;
+ if (ENABLE_DEVICE_CONFIG) {
+ value = getDeviceConfigStringList(
+ key,
+ getSettingsStringList(key, defaultValue));
+ } else {
+ value = getSettingsStringList(key, defaultValue);
+ }
+ mCache.put(key, value);
+ return value;
+ }
+ }
+
+ /**
+ * Reads a float array through the cache. The returned array should be expected to be of the
+ * same length as that of the defaultValue.
+ */
+ public float[] getFloatArray(String key, float[] defaultValue) {
+ synchronized (mLock) {
+ final Object cached = mCache.get(key);
+ if (cached instanceof float[]) {
+ return (float[]) cached;
+ }
+ final float[] value;
+ if (ENABLE_DEVICE_CONFIG) {
+ value = getDeviceConfigFloatArray(
+ key,
+ getSettingsFloatArray(key, defaultValue));
+ } else {
+ value = getSettingsFloatArray(key, defaultValue);
+ }
+ mCache.put(key, value);
+ return value;
+ }
+ }
+
+ private List<String> getSettingsStringList(String key, List<String> defaultValue) {
+ return parse(mSettingsParser.getString(key, null), defaultValue);
+ }
+
+ private static List<String> getDeviceConfigStringList(String key, List<String> defaultValue) {
+ return parse(
+ DeviceConfig.getString(DeviceConfig.NAMESPACE_TEXTCLASSIFIER, key, null),
+ defaultValue);
+ }
+
+ private static float[] getDeviceConfigFloatArray(String key, float[] defaultValue) {
+ return parse(
+ DeviceConfig.getString(DeviceConfig.NAMESPACE_TEXTCLASSIFIER, key, null),
+ defaultValue);
+ }
+
+ private float[] getSettingsFloatArray(String key, float[] defaultValue) {
+ return parse(mSettingsParser.getString(key, null), defaultValue);
+ }
+
+ private static List<String> parse(@Nullable String listStr, List<String> defaultValue) {
+ if (listStr != null) {
+ return Collections.unmodifiableList(
+ Arrays.asList(listStr.split(STRING_LIST_DELIMITER)));
+ }
+ return defaultValue;
+ }
+
+ private static float[] parse(@Nullable String arrayStr, float[] defaultValue) {
+ if (arrayStr != null) {
+ final String[] split = arrayStr.split(STRING_LIST_DELIMITER);
+ if (split.length != defaultValue.length) {
+ return defaultValue;
+ }
+ final float[] result = new float[split.length];
+ for (int i = 0; i < split.length; i++) {
+ try {
+ result[i] = Float.parseFloat(split[i]);
+ } catch (NumberFormatException e) {
+ return defaultValue;
+ }
+ }
+ return result;
} else {
- return mParser.getString(key, defaultValue);
+ return defaultValue;
}
}
}
diff --git a/core/java/android/view/textclassifier/TextClassificationConstants.java b/core/java/android/view/textclassifier/TextClassificationConstants.java
index 876e5cc..2964f51 100644
--- a/core/java/android/view/textclassifier/TextClassificationConstants.java
+++ b/core/java/android/view/textclassifier/TextClassificationConstants.java
@@ -16,58 +16,39 @@
package android.view.textclassifier;
-import android.annotation.Nullable;
-
import com.android.internal.util.IndentingPrintWriter;
import java.util.Arrays;
-import java.util.Collections;
import java.util.List;
-import java.util.StringJoiner;
+import java.util.function.Supplier;
/**
* TextClassifier specific settings.
- * This is encoded as a key=value list, separated by commas. Ex:
- *
- * <pre>
- * smart_linkify_enabled (boolean)
- * system_textclassifier_enabled (boolean)
- * model_dark_launch_enabled (boolean)
- * smart_selection_enabled (boolean)
- * smart_text_share_enabled (boolean)
- * smart_linkify_enabled (boolean)
- * smart_select_animation_enabled (boolean)
- * suggest_selection_max_range_length (int)
- * classify_text_max_range_length (int)
- * generate_links_max_text_length (int)
- * generate_links_log_sample_rate (int)
- * entity_list_default (String[])
- * entity_list_not_editable (String[])
- * entity_list_editable (String[])
- * in_app_conversation_action_types_default (String[])
- * notification_conversation_action_types_default (String[])
- * lang_id_threshold_override (float)
- * template_intent_factory_enabled (boolean)
- * translate_in_classification_enabled (boolean)
- * detect_languages_from_text_enabled (boolean)
- * lang_id_context_settings (float[])
- * </pre>
- *
+ * This is encoded as a key=value list, separated by commas.
* <p>
- * Type: string
- * see also android.provider.Settings.Global.TEXT_CLASSIFIER_CONSTANTS
- *
* Example of setting the values for testing.
+ * <p>
+ * <pre>
* adb shell settings put global text_classifier_constants \
* model_dark_launch_enabled=true,smart_selection_enabled=true, \
* entity_list_default=phone:address, \
* lang_id_context_settings=20:1.0:0.4
+ * </pre>
+ * <p>
+ * Settings are also available in device config. These take precedence over those in settings
+ * global.
+ * <p>
+ * <pre>
+ * adb shell cmd device_config put textclassifier system_textclassifier_enabled true
+ * </pre>
+ *
+ * @see android.provider.Settings.Global.TEXT_CLASSIFIER_CONSTANTS
+ * @see android.provider.DeviceConfig.NAMESPACE_TEXTCLASSIFIER
* @hide
*/
+// TODO: Rename to TextClassifierSettings.
public final class TextClassificationConstants {
- private static final String LOG_TAG = TextClassifier.DEFAULT_LOG_TAG;
-
/**
* Whether the smart linkify feature is enabled.
*/
@@ -188,29 +169,26 @@
private static final int CLASSIFY_TEXT_MAX_RANGE_LENGTH_DEFAULT = 10 * 1000;
private static final int GENERATE_LINKS_MAX_TEXT_LENGTH_DEFAULT = 100 * 1000;
private static final int GENERATE_LINKS_LOG_SAMPLE_RATE_DEFAULT = 100;
- private static final String STRING_LIST_DELIMITER = ":";
- private static final String ENTITY_LIST_DEFAULT_VALUE = new StringJoiner(STRING_LIST_DELIMITER)
- .add(TextClassifier.TYPE_ADDRESS)
- .add(TextClassifier.TYPE_EMAIL)
- .add(TextClassifier.TYPE_PHONE)
- .add(TextClassifier.TYPE_URL)
- .add(TextClassifier.TYPE_DATE)
- .add(TextClassifier.TYPE_DATE_TIME)
- .add(TextClassifier.TYPE_FLIGHT_NUMBER).toString();
- private static final String CONVERSATION_ACTIONS_TYPES_DEFAULT_VALUES =
- new StringJoiner(STRING_LIST_DELIMITER)
- .add(ConversationAction.TYPE_TEXT_REPLY)
- .add(ConversationAction.TYPE_CREATE_REMINDER)
- .add(ConversationAction.TYPE_CALL_PHONE)
- .add(ConversationAction.TYPE_OPEN_URL)
- .add(ConversationAction.TYPE_SEND_EMAIL)
- .add(ConversationAction.TYPE_SEND_SMS)
- .add(ConversationAction.TYPE_TRACK_FLIGHT)
- .add(ConversationAction.TYPE_VIEW_CALENDAR)
- .add(ConversationAction.TYPE_VIEW_MAP)
- .add(ConversationAction.TYPE_ADD_CONTACT)
- .add(ConversationAction.TYPE_COPY)
- .toString();
+ private static final List<String> ENTITY_LIST_DEFAULT_VALUE = Arrays.asList(
+ TextClassifier.TYPE_ADDRESS,
+ TextClassifier.TYPE_EMAIL,
+ TextClassifier.TYPE_PHONE,
+ TextClassifier.TYPE_URL,
+ TextClassifier.TYPE_DATE,
+ TextClassifier.TYPE_DATE_TIME,
+ TextClassifier.TYPE_FLIGHT_NUMBER);
+ private static final List<String> CONVERSATION_ACTIONS_TYPES_DEFAULT_VALUES = Arrays.asList(
+ ConversationAction.TYPE_TEXT_REPLY,
+ ConversationAction.TYPE_CREATE_REMINDER,
+ ConversationAction.TYPE_CALL_PHONE,
+ ConversationAction.TYPE_OPEN_URL,
+ ConversationAction.TYPE_SEND_EMAIL,
+ ConversationAction.TYPE_SEND_SMS,
+ ConversationAction.TYPE_TRACK_FLIGHT,
+ ConversationAction.TYPE_VIEW_CALENDAR,
+ ConversationAction.TYPE_VIEW_MAP,
+ ConversationAction.TYPE_ADD_CONTACT,
+ ConversationAction.TYPE_COPY);
/**
* < 0 : Not set. Use value from LangId model.
* 0 - 1: Override value in LangId model.
@@ -221,259 +199,185 @@
private static final boolean TEMPLATE_INTENT_FACTORY_ENABLED_DEFAULT = true;
private static final boolean TRANSLATE_IN_CLASSIFICATION_ENABLED_DEFAULT = true;
private static final boolean DETECT_LANGUAGES_FROM_TEXT_ENABLED_DEFAULT = true;
- private static final String LANG_ID_CONTEXT_SETTINGS_DEFAULT =
- new StringJoiner(STRING_LIST_DELIMITER).add("20").add("1.0").add("0.4").toString();
+ private static final float[] LANG_ID_CONTEXT_SETTINGS_DEFAULT = new float[] {20f, 1.0f, 0.4f};
- private final boolean mSystemTextClassifierEnabled;
- private final boolean mLocalTextClassifierEnabled;
- private final boolean mModelDarkLaunchEnabled;
- private final boolean mSmartSelectionEnabled;
- private final boolean mSmartTextShareEnabled;
- private final boolean mSmartLinkifyEnabled;
- private final boolean mSmartSelectionAnimationEnabled;
- private final int mSuggestSelectionMaxRangeLength;
- private final int mClassifyTextMaxRangeLength;
- private final int mGenerateLinksMaxTextLength;
- private final int mGenerateLinksLogSampleRate;
- private final List<String> mEntityListDefault;
- private final List<String> mEntityListNotEditable;
- private final List<String> mEntityListEditable;
- private final List<String> mInAppConversationActionTypesDefault;
- private final List<String> mNotificationConversationActionTypesDefault;
- private final float mLangIdThresholdOverride;
- private final boolean mTemplateIntentFactoryEnabled;
- private final boolean mTranslateInClassificationEnabled;
- private final boolean mDetectLanguagesFromTextEnabled;
- private final float[] mLangIdContextSettings;
+ private final ConfigParser mConfigParser;
- private TextClassificationConstants(@Nullable String settings) {
- ConfigParser configParser = new ConfigParser(settings);
- mSystemTextClassifierEnabled =
- configParser.getBoolean(
- SYSTEM_TEXT_CLASSIFIER_ENABLED,
- SYSTEM_TEXT_CLASSIFIER_ENABLED_DEFAULT);
- mLocalTextClassifierEnabled =
- configParser.getBoolean(
- LOCAL_TEXT_CLASSIFIER_ENABLED,
- LOCAL_TEXT_CLASSIFIER_ENABLED_DEFAULT);
- mModelDarkLaunchEnabled =
- configParser.getBoolean(
- MODEL_DARK_LAUNCH_ENABLED,
- MODEL_DARK_LAUNCH_ENABLED_DEFAULT);
- mSmartSelectionEnabled =
- configParser.getBoolean(
- SMART_SELECTION_ENABLED,
- SMART_SELECTION_ENABLED_DEFAULT);
- mSmartTextShareEnabled =
- configParser.getBoolean(
- SMART_TEXT_SHARE_ENABLED,
- SMART_TEXT_SHARE_ENABLED_DEFAULT);
- mSmartLinkifyEnabled =
- configParser.getBoolean(
- SMART_LINKIFY_ENABLED,
- SMART_LINKIFY_ENABLED_DEFAULT);
- mSmartSelectionAnimationEnabled =
- configParser.getBoolean(
- SMART_SELECT_ANIMATION_ENABLED,
- SMART_SELECT_ANIMATION_ENABLED_DEFAULT);
- mSuggestSelectionMaxRangeLength =
- configParser.getInt(
- SUGGEST_SELECTION_MAX_RANGE_LENGTH,
- SUGGEST_SELECTION_MAX_RANGE_LENGTH_DEFAULT);
- mClassifyTextMaxRangeLength =
- configParser.getInt(
- CLASSIFY_TEXT_MAX_RANGE_LENGTH,
- CLASSIFY_TEXT_MAX_RANGE_LENGTH_DEFAULT);
- mGenerateLinksMaxTextLength =
- configParser.getInt(
- GENERATE_LINKS_MAX_TEXT_LENGTH,
- GENERATE_LINKS_MAX_TEXT_LENGTH_DEFAULT);
- mGenerateLinksLogSampleRate =
- configParser.getInt(
- GENERATE_LINKS_LOG_SAMPLE_RATE,
- GENERATE_LINKS_LOG_SAMPLE_RATE_DEFAULT);
- mEntityListDefault = parseStringList(
- configParser.getString(
- ENTITY_LIST_DEFAULT,
- ENTITY_LIST_DEFAULT_VALUE));
- mEntityListNotEditable = parseStringList(
- configParser.getString(
- ENTITY_LIST_NOT_EDITABLE,
- ENTITY_LIST_DEFAULT_VALUE));
- mEntityListEditable = parseStringList(
- configParser.getString(
- ENTITY_LIST_EDITABLE,
- ENTITY_LIST_DEFAULT_VALUE));
- mInAppConversationActionTypesDefault = parseStringList(
- configParser.getString(
- IN_APP_CONVERSATION_ACTION_TYPES_DEFAULT,
- CONVERSATION_ACTIONS_TYPES_DEFAULT_VALUES));
- mNotificationConversationActionTypesDefault = parseStringList(
- configParser.getString(
- NOTIFICATION_CONVERSATION_ACTION_TYPES_DEFAULT,
- CONVERSATION_ACTIONS_TYPES_DEFAULT_VALUES));
- mLangIdThresholdOverride =
- configParser.getFloat(
- LANG_ID_THRESHOLD_OVERRIDE,
- LANG_ID_THRESHOLD_OVERRIDE_DEFAULT);
- mTemplateIntentFactoryEnabled =
- configParser.getBoolean(
- TEMPLATE_INTENT_FACTORY_ENABLED,
- TEMPLATE_INTENT_FACTORY_ENABLED_DEFAULT);
- mTranslateInClassificationEnabled =
- configParser.getBoolean(
- TRANSLATE_IN_CLASSIFICATION_ENABLED,
- TRANSLATE_IN_CLASSIFICATION_ENABLED_DEFAULT);
- mDetectLanguagesFromTextEnabled =
- configParser.getBoolean(
- DETECT_LANGUAGES_FROM_TEXT_ENABLED,
- DETECT_LANGUAGES_FROM_TEXT_ENABLED_DEFAULT);
- mLangIdContextSettings = parseFloatArray(
- configParser,
- LANG_ID_CONTEXT_SETTINGS,
- LANG_ID_CONTEXT_SETTINGS_DEFAULT);
- }
-
- /** Load from a settings string. */
- public static TextClassificationConstants loadFromString(String settings) {
- return new TextClassificationConstants(settings);
+ public TextClassificationConstants(Supplier<String> legacySettingsSupplier) {
+ mConfigParser = new ConfigParser(legacySettingsSupplier);
}
public boolean isLocalTextClassifierEnabled() {
- return mLocalTextClassifierEnabled;
+ return mConfigParser.getBoolean(
+ LOCAL_TEXT_CLASSIFIER_ENABLED,
+ LOCAL_TEXT_CLASSIFIER_ENABLED_DEFAULT);
}
public boolean isSystemTextClassifierEnabled() {
- return mSystemTextClassifierEnabled;
+ return mConfigParser.getBoolean(
+ SYSTEM_TEXT_CLASSIFIER_ENABLED,
+ SYSTEM_TEXT_CLASSIFIER_ENABLED_DEFAULT);
}
public boolean isModelDarkLaunchEnabled() {
- return mModelDarkLaunchEnabled;
+ return mConfigParser.getBoolean(
+ MODEL_DARK_LAUNCH_ENABLED,
+ MODEL_DARK_LAUNCH_ENABLED_DEFAULT);
}
public boolean isSmartSelectionEnabled() {
- return mSmartSelectionEnabled;
+ return mConfigParser.getBoolean(
+ SMART_SELECTION_ENABLED,
+ SMART_SELECTION_ENABLED_DEFAULT);
}
public boolean isSmartTextShareEnabled() {
- return mSmartTextShareEnabled;
+ return mConfigParser.getBoolean(
+ SMART_TEXT_SHARE_ENABLED,
+ SMART_TEXT_SHARE_ENABLED_DEFAULT);
}
public boolean isSmartLinkifyEnabled() {
- return mSmartLinkifyEnabled;
+ return mConfigParser.getBoolean(
+ SMART_LINKIFY_ENABLED,
+ SMART_LINKIFY_ENABLED_DEFAULT);
}
public boolean isSmartSelectionAnimationEnabled() {
- return mSmartSelectionAnimationEnabled;
+ return mConfigParser.getBoolean(
+ SMART_SELECT_ANIMATION_ENABLED,
+ SMART_SELECT_ANIMATION_ENABLED_DEFAULT);
}
public int getSuggestSelectionMaxRangeLength() {
- return mSuggestSelectionMaxRangeLength;
+ return mConfigParser.getInt(
+ SUGGEST_SELECTION_MAX_RANGE_LENGTH,
+ SUGGEST_SELECTION_MAX_RANGE_LENGTH_DEFAULT);
}
public int getClassifyTextMaxRangeLength() {
- return mClassifyTextMaxRangeLength;
+ return mConfigParser.getInt(
+ CLASSIFY_TEXT_MAX_RANGE_LENGTH,
+ CLASSIFY_TEXT_MAX_RANGE_LENGTH_DEFAULT);
}
public int getGenerateLinksMaxTextLength() {
- return mGenerateLinksMaxTextLength;
+ return mConfigParser.getInt(
+ GENERATE_LINKS_MAX_TEXT_LENGTH,
+ GENERATE_LINKS_MAX_TEXT_LENGTH_DEFAULT);
}
public int getGenerateLinksLogSampleRate() {
- return mGenerateLinksLogSampleRate;
+ return mConfigParser.getInt(
+ GENERATE_LINKS_LOG_SAMPLE_RATE,
+ GENERATE_LINKS_LOG_SAMPLE_RATE_DEFAULT);
}
public List<String> getEntityListDefault() {
- return mEntityListDefault;
+ return mConfigParser.getStringList(
+ ENTITY_LIST_DEFAULT,
+ ENTITY_LIST_DEFAULT_VALUE);
}
public List<String> getEntityListNotEditable() {
- return mEntityListNotEditable;
+ return mConfigParser.getStringList(
+ ENTITY_LIST_NOT_EDITABLE,
+ ENTITY_LIST_DEFAULT_VALUE);
}
public List<String> getEntityListEditable() {
- return mEntityListEditable;
+ return mConfigParser.getStringList(
+ ENTITY_LIST_EDITABLE,
+ ENTITY_LIST_DEFAULT_VALUE);
}
public List<String> getInAppConversationActionTypes() {
- return mInAppConversationActionTypesDefault;
+ return mConfigParser.getStringList(
+ IN_APP_CONVERSATION_ACTION_TYPES_DEFAULT,
+ CONVERSATION_ACTIONS_TYPES_DEFAULT_VALUES);
}
public List<String> getNotificationConversationActionTypes() {
- return mNotificationConversationActionTypesDefault;
+ return mConfigParser.getStringList(
+ NOTIFICATION_CONVERSATION_ACTION_TYPES_DEFAULT,
+ CONVERSATION_ACTIONS_TYPES_DEFAULT_VALUES);
}
public float getLangIdThresholdOverride() {
- return mLangIdThresholdOverride;
+ return mConfigParser.getFloat(
+ LANG_ID_THRESHOLD_OVERRIDE,
+ LANG_ID_THRESHOLD_OVERRIDE_DEFAULT);
}
public boolean isTemplateIntentFactoryEnabled() {
- return mTemplateIntentFactoryEnabled;
+ return mConfigParser.getBoolean(
+ TEMPLATE_INTENT_FACTORY_ENABLED,
+ TEMPLATE_INTENT_FACTORY_ENABLED_DEFAULT);
}
public boolean isTranslateInClassificationEnabled() {
- return mTranslateInClassificationEnabled;
+ return mConfigParser.getBoolean(
+ TRANSLATE_IN_CLASSIFICATION_ENABLED,
+ TRANSLATE_IN_CLASSIFICATION_ENABLED_DEFAULT);
}
public boolean isDetectLanguagesFromTextEnabled() {
- return mDetectLanguagesFromTextEnabled;
+ return mConfigParser.getBoolean(
+ DETECT_LANGUAGES_FROM_TEXT_ENABLED,
+ DETECT_LANGUAGES_FROM_TEXT_ENABLED_DEFAULT);
}
public float[] getLangIdContextSettings() {
- return mLangIdContextSettings;
- }
-
- private static List<String> parseStringList(String listStr) {
- return Collections.unmodifiableList(Arrays.asList(listStr.split(STRING_LIST_DELIMITER)));
- }
-
- private static float[] parseFloatArray(
- ConfigParser configParser, String key, String defaultStr) {
- final String str = configParser.getString(key, defaultStr);
- final String[] defaultSplit = defaultStr.split(STRING_LIST_DELIMITER);
- String[] split = str.split(STRING_LIST_DELIMITER);
- if (split.length != defaultSplit.length) {
- Log.v(LOG_TAG, "Error parsing " + key + " flag. Using defaults.");
- split = defaultSplit;
- }
- final float[] result = new float[split.length];
- for (int i = 0; i < split.length; i++) {
- try {
- result[i] = Float.parseFloat(split[i]);
- } catch (NumberFormatException e) {
- Log.v(LOG_TAG, "Error parsing part of " + key + " flag. Using defaults.");
- result[i] = Float.parseFloat(defaultSplit[i]);
- }
- }
- return result;
+ return mConfigParser.getFloatArray(
+ LANG_ID_CONTEXT_SETTINGS,
+ LANG_ID_CONTEXT_SETTINGS_DEFAULT);
}
void dump(IndentingPrintWriter pw) {
pw.println("TextClassificationConstants:");
pw.increaseIndent();
- pw.printPair("isLocalTextClassifierEnabled", mLocalTextClassifierEnabled);
- pw.printPair("isSystemTextClassifierEnabled", mSystemTextClassifierEnabled);
- pw.printPair("isModelDarkLaunchEnabled", mModelDarkLaunchEnabled);
- pw.printPair("isSmartSelectionEnabled", mSmartSelectionEnabled);
- pw.printPair("isSmartTextShareEnabled", mSmartTextShareEnabled);
- pw.printPair("isSmartLinkifyEnabled", mSmartLinkifyEnabled);
- pw.printPair("isSmartSelectionAnimationEnabled", mSmartSelectionAnimationEnabled);
- pw.printPair("getSuggestSelectionMaxRangeLength", mSuggestSelectionMaxRangeLength);
- pw.printPair("getClassifyTextMaxRangeLength", mClassifyTextMaxRangeLength);
- pw.printPair("getGenerateLinksMaxTextLength", mGenerateLinksMaxTextLength);
- pw.printPair("getGenerateLinksLogSampleRate", mGenerateLinksLogSampleRate);
- pw.printPair("getEntityListDefault", mEntityListDefault);
- pw.printPair("getEntityListNotEditable", mEntityListNotEditable);
- pw.printPair("getEntityListEditable", mEntityListEditable);
- pw.printPair("getInAppConversationActionTypes", mInAppConversationActionTypesDefault);
- pw.printPair("getNotificationConversationActionTypes",
- mNotificationConversationActionTypesDefault);
- pw.printPair("getLangIdThresholdOverride", mLangIdThresholdOverride);
- pw.printPair("isTemplateIntentFactoryEnabled", mTemplateIntentFactoryEnabled);
- pw.printPair("isTranslateInClassificationEnabled", mTranslateInClassificationEnabled);
- pw.printPair("isDetectLanguageFromTextEnabled", mDetectLanguagesFromTextEnabled);
- pw.printPair("getLangIdContextSettings", Arrays.toString(mLangIdContextSettings));
+ pw.printPair("classify_text_max_range_length", getClassifyTextMaxRangeLength())
+ .println();
+ pw.printPair("detect_language_from_text_enabled", isDetectLanguagesFromTextEnabled())
+ .println();
+ pw.printPair("entity_list_default", getEntityListDefault())
+ .println();
+ pw.printPair("entity_list_editable", getEntityListEditable())
+ .println();
+ pw.printPair("entity_list_not_editable", getEntityListNotEditable())
+ .println();
+ pw.printPair("generate_links_log_sample_rate", getGenerateLinksLogSampleRate())
+ .println();
+ pw.printPair("generate_links_max_text_length", getGenerateLinksMaxTextLength())
+ .println();
+ pw.printPair("in_app_conversation_action_types_default", getInAppConversationActionTypes())
+ .println();
+ pw.printPair("lang_id_context_settings", Arrays.toString(getLangIdContextSettings()))
+ .println();
+ pw.printPair("lang_id_threshold_override", getLangIdThresholdOverride())
+ .println();
+ pw.printPair("local_textclassifier_enabled", isLocalTextClassifierEnabled())
+ .println();
+ pw.printPair("model_dark_launch_enabled", isModelDarkLaunchEnabled())
+ .println();
+ pw.printPair("notification_conversation_action_types_default",
+ getNotificationConversationActionTypes()).println();
+ pw.printPair("smart_linkify_enabled", isSmartLinkifyEnabled())
+ .println();
+ pw.printPair("smart_select_animation_enabled", isSmartSelectionAnimationEnabled())
+ .println();
+ pw.printPair("smart_selection_enabled", isSmartSelectionEnabled())
+ .println();
+ pw.printPair("smart_text_share_enabled", isSmartTextShareEnabled())
+ .println();
+ pw.printPair("suggest_selection_max_range_length", getSuggestSelectionMaxRangeLength())
+ .println();
+ pw.printPair("system_textclassifier_enabled", isSystemTextClassifierEnabled())
+ .println();
+ pw.printPair("template_intent_factory_enabled", isTemplateIntentFactoryEnabled())
+ .println();
+ pw.printPair("translate_in_classification_enabled", isTranslateInClassificationEnabled())
+ .println();
pw.decreaseIndent();
- pw.println();
}
-}
+}
\ No newline at end of file
diff --git a/core/java/android/view/textclassifier/TextClassificationManager.java b/core/java/android/view/textclassifier/TextClassificationManager.java
index 042b943..95ca9de 100644
--- a/core/java/android/view/textclassifier/TextClassificationManager.java
+++ b/core/java/android/view/textclassifier/TextClassificationManager.java
@@ -45,6 +45,9 @@
private static final String LOG_TAG = "TextClassificationManager";
+ private static final TextClassificationConstants sDefaultSettings =
+ new TextClassificationConstants(() -> null);
+
private final Object mLock = new Object();
private final TextClassificationSessionFactory mDefaultSessionFactory =
classificationContext -> new TextClassificationSession(
@@ -129,9 +132,10 @@
private TextClassificationConstants getSettings() {
synchronized (mLock) {
if (mSettings == null) {
- mSettings = TextClassificationConstants.loadFromString(Settings.Global.getString(
- getApplicationContext().getContentResolver(),
- Settings.Global.TEXT_CLASSIFIER_CONSTANTS));
+ mSettings = new TextClassificationConstants(
+ () -> Settings.Global.getString(
+ getApplicationContext().getContentResolver(),
+ Settings.Global.TEXT_CLASSIFIER_CONSTANTS));
}
return mSettings;
}
@@ -251,7 +255,11 @@
/** @hide */
@VisibleForTesting
- public void invalidate() {
+ public void invalidateForTesting() {
+ invalidate();
+ }
+
+ private void invalidate() {
synchronized (mLock) {
mSettings = null;
mLocalTextClassifier = null;
@@ -280,9 +288,8 @@
if (tcm != null) {
return tcm.getSettings();
} else {
- return TextClassificationConstants.loadFromString(Settings.Global.getString(
- context.getApplicationContext().getContentResolver(),
- Settings.Global.TEXT_CLASSIFIER_CONSTANTS));
+ // Use default settings if there is no tcm.
+ return sDefaultSettings;
}
}
diff --git a/core/java/android/view/textclassifier/TextClassifierImpl.java b/core/java/android/view/textclassifier/TextClassifierImpl.java
index 3297523..3e95f1b 100644
--- a/core/java/android/view/textclassifier/TextClassifierImpl.java
+++ b/core/java/android/view/textclassifier/TextClassifierImpl.java
@@ -301,7 +301,7 @@
final ZonedDateTime refTime = ZonedDateTime.now();
final Collection<String> entitiesToIdentify = request.getEntityConfig() != null
? request.getEntityConfig().resolveEntityListModifications(
- getEntitiesForHints(request.getEntityConfig().getHints()))
+ getEntitiesForHints(request.getEntityConfig().getHints()))
: mSettings.getEntityListDefault();
final String localesString = concatenateLocales(request.getDefaultLocales());
final String detectLanguageTags = detectLanguageTagsFromText(request.getText());
@@ -779,8 +779,8 @@
final float moreTextScoreRatio = 1f - subjectTextScoreRatio;
Log.v(LOG_TAG,
String.format(Locale.US, "LangIdContextSettings: "
- + "minimumTextSize=%d, penalizeRatio=%.2f, "
- + "subjectTextScoreRatio=%.2f, moreTextScoreRatio=%.2f",
+ + "minimumTextSize=%d, penalizeRatio=%.2f, "
+ + "subjectTextScoreRatio=%.2f, moreTextScoreRatio=%.2f",
minimumTextSize, penalizeRatio, subjectTextScoreRatio, moreTextScoreRatio));
if (end - start < minimumTextSize && penalizeRatio <= 0) {
@@ -903,4 +903,3 @@
}
}
}
-
diff --git a/core/tests/coretests/src/android/view/textclassifier/ConfigParserTest.java b/core/tests/coretests/src/android/view/textclassifier/ConfigParserTest.java
index f1cfe24..d54ce51 100644
--- a/core/tests/coretests/src/android/view/textclassifier/ConfigParserTest.java
+++ b/core/tests/coretests/src/android/view/textclassifier/ConfigParserTest.java
@@ -26,16 +26,17 @@
import org.junit.After;
import org.junit.Before;
-import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import java.io.IOException;
+import java.util.function.Supplier;
@SmallTest
@RunWith(AndroidJUnit4.class)
public class ConfigParserTest {
- private static final String SETTINGS = "int=42,float=12.3,boolean=true,string=abc";
+ private static final Supplier<String> SETTINGS =
+ () -> "int=42,float=12.3,boolean=true,string=abc";
private static final String CLEAR_DEVICE_CONFIG_KEY_CMD =
"device_config delete " + DeviceConfig.NAMESPACE_TEXTCLASSIFIER;
private static final String[] DEVICE_CONFIG_KEYS = new String[]{
@@ -59,7 +60,6 @@
}
@Test
- @Ignore // TODO: Re-enable once ConfigParser#ENABLE_DEVICE_CONFIG is finalized
public void getBoolean_deviceConfig() {
DeviceConfig.setProperty(
DeviceConfig.NAMESPACE_TEXTCLASSIFIER,
@@ -79,7 +79,6 @@
}
@Test
- @Ignore // TODO: Re-enable once ConfigParser#ENABLE_DEVICE_CONFIG is finalized
public void getInt_deviceConfig() {
DeviceConfig.setProperty(
DeviceConfig.NAMESPACE_TEXTCLASSIFIER,
@@ -97,7 +96,6 @@
}
@Test
- @Ignore // TODO: Re-enable once ConfigParser#ENABLE_DEVICE_CONFIG is finalized
public void getFloat_deviceConfig() {
DeviceConfig.setProperty(
DeviceConfig.NAMESPACE_TEXTCLASSIFIER,
@@ -115,7 +113,6 @@
}
@Test
- @Ignore // TODO: Re-enable once ConfigParser#ENABLE_DEVICE_CONFIG is finalized
public void getString_deviceConfig() {
DeviceConfig.setProperty(
DeviceConfig.NAMESPACE_TEXTCLASSIFIER,
diff --git a/core/tests/coretests/src/android/view/textclassifier/TextClassificationConstantsTest.java b/core/tests/coretests/src/android/view/textclassifier/TextClassificationConstantsTest.java
index f6bb1bf..789b829 100644
--- a/core/tests/coretests/src/android/view/textclassifier/TextClassificationConstantsTest.java
+++ b/core/tests/coretests/src/android/view/textclassifier/TextClassificationConstantsTest.java
@@ -50,9 +50,11 @@
+ "in_app_conversation_action_types_default=text_reply,"
+ "notification_conversation_action_types_default=send_email:call_phone,"
+ "lang_id_threshold_override=0.3,"
- + "lang_id_context_settings=10:1:0.5";
- final TextClassificationConstants constants =
- TextClassificationConstants.loadFromString(s);
+ + "lang_id_context_settings=10:1:0.5,"
+ + "detect_language_from_text_enabled=true,"
+ + "template_intent_factory_enabled=true,"
+ + "translate_in_classification_enabled=true";
+ final TextClassificationConstants constants = new TextClassificationConstants(() -> s);
assertWithMessage("local_textclassifier_enabled")
.that(constants.isLocalTextClassifierEnabled()).isTrue();
@@ -95,6 +97,12 @@
.that(constants.getLangIdThresholdOverride()).isWithin(EPSILON).of(0.3f);
Assert.assertArrayEquals("lang_id_context_settings",
constants.getLangIdContextSettings(), new float[]{10, 1, 0.5f}, EPSILON);
+ assertWithMessage("detect_language_from_text_enabled")
+ .that(constants.isLocalTextClassifierEnabled()).isTrue();
+ assertWithMessage("template_intent_factory_enabled")
+ .that(constants.isLocalTextClassifierEnabled()).isTrue();
+ assertWithMessage("translate_in_classification_enabled")
+ .that(constants.isLocalTextClassifierEnabled()).isTrue();
}
@Test
@@ -116,9 +124,11 @@
+ "in_app_conversation_action_types_default=view_map:track_flight,"
+ "notification_conversation_action_types_default=share_location,"
+ "lang_id_threshold_override=2,"
- + "lang_id_context_settings=30:0.5:0.3";
- final TextClassificationConstants constants =
- TextClassificationConstants.loadFromString(s);
+ + "lang_id_context_settings=30:0.5:0.3,"
+ + "detect_language_from_text_enabled=false,"
+ + "template_intent_factory_enabled=false,"
+ + "translate_in_classification_enabled=false";
+ final TextClassificationConstants constants = new TextClassificationConstants(() -> s);
assertWithMessage("local_textclassifier_enabled")
.that(constants.isLocalTextClassifierEnabled()).isFalse();
@@ -161,12 +171,17 @@
.that(constants.getLangIdThresholdOverride()).isWithin(EPSILON).of(2f);
Assert.assertArrayEquals("lang_id_context_settings",
constants.getLangIdContextSettings(), new float[]{30, 0.5f, 0.3f}, EPSILON);
+ assertWithMessage("detect_language_from_text_enabled")
+ .that(constants.isLocalTextClassifierEnabled()).isFalse();
+ assertWithMessage("template_intent_factory_enabled")
+ .that(constants.isLocalTextClassifierEnabled()).isFalse();
+ assertWithMessage("translate_in_classification_enabled")
+ .that(constants.isLocalTextClassifierEnabled()).isFalse();
}
@Test
public void testLoadFromString_defaultValues() {
- final TextClassificationConstants constants =
- TextClassificationConstants.loadFromString("");
+ final TextClassificationConstants constants = new TextClassificationConstants(() -> "");
assertWithMessage("local_textclassifier_enabled")
.that(constants.isLocalTextClassifierEnabled()).isTrue();
@@ -213,5 +228,11 @@
.that(constants.getLangIdThresholdOverride()).isWithin(EPSILON).of(-1f);
Assert.assertArrayEquals("lang_id_context_settings",
constants.getLangIdContextSettings(), new float[]{20, 1, 0.4f}, EPSILON);
+ assertWithMessage("detect_language_from_text_enabled")
+ .that(constants.isLocalTextClassifierEnabled()).isTrue();
+ assertWithMessage("template_intent_factory_enabled")
+ .that(constants.isLocalTextClassifierEnabled()).isTrue();
+ assertWithMessage("translate_in_classification_enabled")
+ .that(constants.isLocalTextClassifierEnabled()).isTrue();
}
}
diff --git a/core/tests/coretests/src/android/view/textclassifier/TextClassificationManagerTest.java b/core/tests/coretests/src/android/view/textclassifier/TextClassificationManagerTest.java
index 4fcd51c..9148185 100644
--- a/core/tests/coretests/src/android/view/textclassifier/TextClassificationManagerTest.java
+++ b/core/tests/coretests/src/android/view/textclassifier/TextClassificationManagerTest.java
@@ -77,7 +77,7 @@
TextClassifier fallback = TextClassifier.NO_OP;
TextClassifier classifier = new TextClassifierImpl(
- fakeContext, TextClassificationConstants.loadFromString(null), fallback);
+ fakeContext, new TextClassificationConstants(() -> null), fallback);
String text = "Contact me at +12122537077";
String classifiedText = "+12122537077";
diff --git a/core/tests/coretests/src/android/view/textclassifier/TextClassifierTest.java b/core/tests/coretests/src/android/view/textclassifier/TextClassifierTest.java
index aeb8949..e3eb2a3 100644
--- a/core/tests/coretests/src/android/view/textclassifier/TextClassifierTest.java
+++ b/core/tests/coretests/src/android/view/textclassifier/TextClassifierTest.java
@@ -59,7 +59,7 @@
// TODO: Implement TextClassifierService testing.
private static final TextClassificationConstants TC_CONSTANTS =
- TextClassificationConstants.loadFromString("");
+ new TextClassificationConstants(() -> "");
private static final LocaleList LOCALES = LocaleList.forLanguageTags("en-US");
private static final String NO_TYPE = null;