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;