Loading core/java/android/provider/Settings.java +1 −0 Original line number Diff line number Diff line Loading @@ -11723,6 +11723,7 @@ public final class Settings { * entity_list_default (String[]) * entity_list_not_editable (String[]) * entity_list_editable (String[]) * lang_id_threshold_override (float) * </pre> * * <p> Loading core/java/android/view/textclassifier/TextClassificationConstants.java +29 −10 Original line number Diff line number Diff line Loading @@ -46,6 +46,7 @@ import java.util.StringJoiner; * entity_list_default (String[]) * entity_list_not_editable (String[]) * entity_list_editable (String[]) * lang_id_threshold_override (float) * </pre> * * <p> Loading Loading @@ -94,6 +95,8 @@ public final class TextClassificationConstants { "in_app_conversation_action_types_default"; private static final String NOTIFICATION_CONVERSATION_ACTION_TYPES_DEFAULT = "notification_conversation_action_types_default"; private static final String LANG_ID_THRESHOLD_OVERRIDE = "lang_id_threshold_override"; private static final boolean LOCAL_TEXT_CLASSIFIER_ENABLED_DEFAULT = true; private static final boolean SYSTEM_TEXT_CLASSIFIER_ENABLED_DEFAULT = true; Loading @@ -106,8 +109,8 @@ public final class TextClassificationConstants { 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 ENTITY_LIST_DELIMITER = ":"; private static final String ENTITY_LIST_DEFAULT_VALUE = new StringJoiner(ENTITY_LIST_DELIMITER) 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) Loading @@ -116,7 +119,7 @@ public final class TextClassificationConstants { .add(TextClassifier.TYPE_DATE_TIME) .add(TextClassifier.TYPE_FLIGHT_NUMBER).toString(); private static final String CONVERSATION_ACTIONS_TYPES_DEFAULT_VALUES = new StringJoiner(ENTITY_LIST_DELIMITER) new StringJoiner(STRING_LIST_DELIMITER) .add(ConversationAction.TYPE_TEXT_REPLY) .add(ConversationAction.TYPE_CREATE_REMINDER) .add(ConversationAction.TYPE_CALL_PHONE) Loading @@ -127,6 +130,13 @@ public final class TextClassificationConstants { .add(ConversationAction.TYPE_VIEW_CALENDAR) .add(ConversationAction.TYPE_VIEW_MAP) .toString(); /** * < 0 : Not set. Use value from LangId model. * 0 - 1: Override value in LangId model. * > 1 : Effectively turns off the foreign language detection. Scores should never be > 1. * @see EntityConfidence */ private static final float LANG_ID_THRESHOLD_OVERRIDE_DEFAULT = -1f; private final boolean mSystemTextClassifierEnabled; private final boolean mLocalTextClassifierEnabled; Loading @@ -144,6 +154,7 @@ public final class TextClassificationConstants { private final List<String> mEntityListEditable; private final List<String> mInAppConversationActionTypesDefault; private final List<String> mNotificationConversationActionTypesDefault; private final float mLangIdThresholdOverride; private TextClassificationConstants(@Nullable String settings) { final KeyValueListParser parser = new KeyValueListParser(','); Loading Loading @@ -186,21 +197,24 @@ public final class TextClassificationConstants { mGenerateLinksLogSampleRate = parser.getInt( GENERATE_LINKS_LOG_SAMPLE_RATE, GENERATE_LINKS_LOG_SAMPLE_RATE_DEFAULT); mEntityListDefault = parseEntityList(parser.getString( mEntityListDefault = parseStringList(parser.getString( ENTITY_LIST_DEFAULT, ENTITY_LIST_DEFAULT_VALUE)); mEntityListNotEditable = parseEntityList(parser.getString( mEntityListNotEditable = parseStringList(parser.getString( ENTITY_LIST_NOT_EDITABLE, ENTITY_LIST_DEFAULT_VALUE)); mEntityListEditable = parseEntityList(parser.getString( mEntityListEditable = parseStringList(parser.getString( ENTITY_LIST_EDITABLE, ENTITY_LIST_DEFAULT_VALUE)); mInAppConversationActionTypesDefault = parseEntityList(parser.getString( mInAppConversationActionTypesDefault = parseStringList(parser.getString( IN_APP_CONVERSATION_ACTION_TYPES_DEFAULT, CONVERSATION_ACTIONS_TYPES_DEFAULT_VALUES)); mNotificationConversationActionTypesDefault = parseEntityList(parser.getString( mNotificationConversationActionTypesDefault = parseStringList(parser.getString( NOTIFICATION_CONVERSATION_ACTION_TYPES_DEFAULT, CONVERSATION_ACTIONS_TYPES_DEFAULT_VALUES)); mLangIdThresholdOverride = parser.getFloat( LANG_ID_THRESHOLD_OVERRIDE, LANG_ID_THRESHOLD_OVERRIDE_DEFAULT); } /** Load from a settings string. */ Loading Loading @@ -272,8 +286,12 @@ public final class TextClassificationConstants { return mNotificationConversationActionTypesDefault; } private static List<String> parseEntityList(String listStr) { return Collections.unmodifiableList(Arrays.asList(listStr.split(ENTITY_LIST_DELIMITER))); public float getLangIdThresholdOverride() { return mLangIdThresholdOverride; } private static List<String> parseStringList(String listStr) { return Collections.unmodifiableList(Arrays.asList(listStr.split(STRING_LIST_DELIMITER))); } void dump(IndentingPrintWriter pw) { Loading @@ -296,6 +314,7 @@ public final class TextClassificationConstants { pw.printPair("getInAppConversationActionTypes", mInAppConversationActionTypesDefault); pw.printPair("getNotificationConversationActionTypes", mNotificationConversationActionTypesDefault); pw.printPair("getLangIdThresholdOverride", mLangIdThresholdOverride); pw.decreaseIndent(); pw.println(); } Loading core/java/android/view/textclassifier/TextClassifierImpl.java +7 −2 Original line number Diff line number Diff line Loading @@ -567,8 +567,9 @@ public final class TextClassifierImpl implements TextClassifier { } } // TODO: Make this configurable. final float foreignTextThreshold = typeCount == 0 ? 0.5f : 0.7f; final float foreignTextThreshold = mSettings.getLangIdThresholdOverride() >= 0 ? mSettings.getLangIdThresholdOverride() : 0.5f /* TODO: Load this from the langId model. */; boolean isPrimaryAction = true; final ArrayList<Intent> sourceIntents = new ArrayList<>(); for (LabeledIntent labeledIntent : IntentFactory.create( Loading Loading @@ -602,6 +603,10 @@ public final class TextClassifierImpl implements TextClassifier { } private boolean isForeignText(String text, float threshold) { if (threshold > 1) { return false; } // TODO: Revisit this algorithm. try { final LangIdModel.LanguageResult[] langResults = getLangIdImpl().detectLanguages(text); Loading core/java/android/view/textclassifier/TextLanguage.java +4 −2 Original line number Diff line number Diff line Loading @@ -89,9 +89,10 @@ public final class TextLanguage implements Parcelable { /** * Returns the language locale at the specified index. Locales are ordered from high * confidence to low confidence. * <p> * See {@link #getLocaleHypothesisCount()} for the number of locales available. * * @throws IndexOutOfBoundsException if the specified index is out of range. * @see #getLocaleHypothesisCount() for the number of locales available. */ @NonNull public ULocale getLocale(int index) { Loading @@ -109,7 +110,8 @@ public final class TextLanguage implements Parcelable { } /** * Returns a bundle containing non-structured extra information about this result. * Returns a bundle containing non-structured extra information about this result. What is * returned in the extras is specific to the {@link TextClassifier} implementation. * * <p><b>NOTE: </b>Each call to this method returns a new bundle copy so clients should prefer * to hold a reference to the returned bundle rather than frequently calling this method. Loading core/tests/coretests/src/android/view/textclassifier/TextClassificationConstantsTest.java +142 −53 Original line number Diff line number Diff line Loading @@ -16,9 +16,7 @@ package android.view.textclassifier; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import static com.google.common.truth.Truth.assertWithMessage; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; Loading @@ -30,6 +28,8 @@ import org.junit.runner.RunWith; @RunWith(AndroidJUnit4.class) public class TextClassificationConstantsTest { private static final float EPSILON = 0.0001f; @Test public void testLoadFromString() { final String s = "local_textclassifier_enabled=true," Loading @@ -42,26 +42,55 @@ public class TextClassificationConstantsTest { + "suggest_selection_max_range_length=10," + "classify_text_max_range_length=11," + "generate_links_max_text_length=12," + "generate_links_log_sample_rate=13"; + "generate_links_log_sample_rate=13," + "entity_list_default=phone," + "entity_list_not_editable=address:flight," + "entity_list_editable=date:datetime," + "in_app_conversation_action_types_default=text_reply," + "notification_conversation_action_types_default=send_email:call_phone," + "lang_id_threshold_override=0.3"; final TextClassificationConstants constants = TextClassificationConstants.loadFromString(s); assertTrue("local_textclassifier_enabled", constants.isLocalTextClassifierEnabled()); assertTrue("system_textclassifier_enabled", constants.isSystemTextClassifierEnabled()); assertTrue("model_dark_launch_enabled", constants.isModelDarkLaunchEnabled()); assertTrue("smart_selection_enabled", constants.isSmartSelectionEnabled()); assertTrue("smart_text_share_enabled", constants.isSmartTextShareEnabled()); assertTrue("smart_linkify_enabled", constants.isSmartLinkifyEnabled()); assertTrue("smart_select_animation_enabled", constants.isSmartSelectionAnimationEnabled()); assertEquals("suggest_selection_max_range_length", 10, constants.getSuggestSelectionMaxRangeLength()); assertEquals("classify_text_max_range_length", 11, constants.getClassifyTextMaxRangeLength()); assertEquals("generate_links_max_text_length", 12, constants.getGenerateLinksMaxTextLength()); assertEquals("generate_links_log_sample_rate", 13, constants.getGenerateLinksLogSampleRate()); assertWithMessage("local_textclassifier_enabled") .that(constants.isLocalTextClassifierEnabled()).isTrue(); assertWithMessage("system_textclassifier_enabled") .that(constants.isSystemTextClassifierEnabled()).isTrue(); assertWithMessage("model_dark_launch_enabled") .that(constants.isModelDarkLaunchEnabled()).isTrue(); assertWithMessage("smart_selection_enabled") .that(constants.isSmartSelectionEnabled()).isTrue(); assertWithMessage("smart_text_share_enabled") .that(constants.isSmartTextShareEnabled()).isTrue(); assertWithMessage("smart_linkify_enabled") .that(constants.isSmartLinkifyEnabled()).isTrue(); assertWithMessage("smart_select_animation_enabled") .that(constants.isSmartSelectionAnimationEnabled()).isTrue(); assertWithMessage("suggest_selection_max_range_length") .that(constants.getSuggestSelectionMaxRangeLength()).isEqualTo(10); assertWithMessage("classify_text_max_range_length") .that(constants.getClassifyTextMaxRangeLength()).isEqualTo(11); assertWithMessage("generate_links_max_text_length") .that(constants.getGenerateLinksMaxTextLength()).isEqualTo(12); assertWithMessage("generate_links_log_sample_rate") .that(constants.getGenerateLinksLogSampleRate()).isEqualTo(13); assertWithMessage("entity_list_default") .that(constants.getEntityListDefault()) .containsExactly("phone"); assertWithMessage("entity_list_not_editable") .that(constants.getEntityListNotEditable()) .containsExactly("address", "flight"); assertWithMessage("entity_list_editable") .that(constants.getEntityListEditable()) .containsExactly("date", "datetime"); assertWithMessage("in_app_conversation_action_types_default") .that(constants.getInAppConversationActionTypes()) .containsExactly("text_reply"); assertWithMessage("notification_conversation_action_types_default") .that(constants.getNotificationConversationActionTypes()) .containsExactly("send_email", "call_phone"); assertWithMessage("lang_id_threshold_override") .that(constants.getLangIdThresholdOverride()).isWithin(EPSILON).of(0.3f); } @Test Loading @@ -76,42 +105,102 @@ public class TextClassificationConstantsTest { + "suggest_selection_max_range_length=8," + "classify_text_max_range_length=7," + "generate_links_max_text_length=6," + "generate_links_log_sample_rate=5"; + "generate_links_log_sample_rate=5," + "entity_list_default=email:url," + "entity_list_not_editable=date," + "entity_list_editable=flight," + "in_app_conversation_action_types_default=view_map:track_flight," + "notification_conversation_action_types_default=share_location," + "lang_id_threshold_override=2"; final TextClassificationConstants constants = TextClassificationConstants.loadFromString(s); assertFalse("local_textclassifier_enabled", constants.isLocalTextClassifierEnabled()); assertFalse("system_textclassifier_enabled", constants.isSystemTextClassifierEnabled()); assertFalse("model_dark_launch_enabled", constants.isModelDarkLaunchEnabled()); assertFalse("smart_selection_enabled", constants.isSmartSelectionEnabled()); assertFalse("smart_text_share_enabled", constants.isSmartTextShareEnabled()); assertFalse("smart_linkify_enabled", constants.isSmartLinkifyEnabled()); assertFalse("smart_select_animation_enabled", constants.isSmartSelectionAnimationEnabled()); assertEquals("suggest_selection_max_range_length", 8, constants.getSuggestSelectionMaxRangeLength()); assertEquals("classify_text_max_range_length", 7, constants.getClassifyTextMaxRangeLength()); assertEquals("generate_links_max_text_length", 6, constants.getGenerateLinksMaxTextLength()); assertEquals("generate_links_log_sample_rate", 5, constants.getGenerateLinksLogSampleRate()); assertWithMessage("local_textclassifier_enabled") .that(constants.isLocalTextClassifierEnabled()).isFalse(); assertWithMessage("system_textclassifier_enabled") .that(constants.isSystemTextClassifierEnabled()).isFalse(); assertWithMessage("model_dark_launch_enabled") .that(constants.isModelDarkLaunchEnabled()).isFalse(); assertWithMessage("smart_selection_enabled") .that(constants.isSmartSelectionEnabled()).isFalse(); assertWithMessage("smart_text_share_enabled") .that(constants.isSmartTextShareEnabled()).isFalse(); assertWithMessage("smart_linkify_enabled") .that(constants.isSmartLinkifyEnabled()).isFalse(); assertWithMessage("smart_select_animation_enabled") .that(constants.isSmartSelectionAnimationEnabled()).isFalse(); assertWithMessage("suggest_selection_max_range_length") .that(constants.getSuggestSelectionMaxRangeLength()).isEqualTo(8); assertWithMessage("classify_text_max_range_length") .that(constants.getClassifyTextMaxRangeLength()).isEqualTo(7); assertWithMessage("generate_links_max_text_length") .that(constants.getGenerateLinksMaxTextLength()).isEqualTo(6); assertWithMessage("generate_links_log_sample_rate") .that(constants.getGenerateLinksLogSampleRate()).isEqualTo(5); assertWithMessage("entity_list_default") .that(constants.getEntityListDefault()) .containsExactly("email", "url"); assertWithMessage("entity_list_not_editable") .that(constants.getEntityListNotEditable()) .containsExactly("date"); assertWithMessage("entity_list_editable") .that(constants.getEntityListEditable()) .containsExactly("flight"); assertWithMessage("in_app_conversation_action_types_default") .that(constants.getInAppConversationActionTypes()) .containsExactly("view_map", "track_flight"); assertWithMessage("notification_conversation_action_types_default") .that(constants.getNotificationConversationActionTypes()) .containsExactly("share_location"); assertWithMessage("lang_id_threshold_override") .that(constants.getLangIdThresholdOverride()).isWithin(EPSILON).of(2f); } @Test public void testEntityListParsing() { final TextClassificationConstants constants = TextClassificationConstants.loadFromString( "entity_list_default=phone," + "entity_list_not_editable=address:flight," + "entity_list_editable=date:datetime"); assertEquals(1, constants.getEntityListDefault().size()); assertEquals("phone", constants.getEntityListDefault().get(0)); assertEquals(2, constants.getEntityListNotEditable().size()); assertEquals("address", constants.getEntityListNotEditable().get(0)); assertEquals("flight", constants.getEntityListNotEditable().get(1)); assertEquals(2, constants.getEntityListEditable().size()); assertEquals("date", constants.getEntityListEditable().get(0)); assertEquals("datetime", constants.getEntityListEditable().get(1)); public void testLoadFromString_defaultValues() { final TextClassificationConstants constants = TextClassificationConstants.loadFromString(""); assertWithMessage("local_textclassifier_enabled") .that(constants.isLocalTextClassifierEnabled()).isTrue(); assertWithMessage("system_textclassifier_enabled") .that(constants.isSystemTextClassifierEnabled()).isTrue(); assertWithMessage("model_dark_launch_enabled") .that(constants.isModelDarkLaunchEnabled()).isFalse(); assertWithMessage("smart_selection_enabled") .that(constants.isSmartSelectionEnabled()).isTrue(); assertWithMessage("smart_text_share_enabled") .that(constants.isSmartTextShareEnabled()).isTrue(); assertWithMessage("smart_linkify_enabled") .that(constants.isSmartLinkifyEnabled()).isTrue(); assertWithMessage("smart_select_animation_enabled") .that(constants.isSmartSelectionAnimationEnabled()).isTrue(); assertWithMessage("suggest_selection_max_range_length") .that(constants.getSuggestSelectionMaxRangeLength()).isEqualTo(10 * 1000); assertWithMessage("classify_text_max_range_length") .that(constants.getClassifyTextMaxRangeLength()).isEqualTo(10 * 1000); assertWithMessage("generate_links_max_text_length") .that(constants.getGenerateLinksMaxTextLength()).isEqualTo(100 * 1000); assertWithMessage("generate_links_log_sample_rate") .that(constants.getGenerateLinksLogSampleRate()).isEqualTo(100); assertWithMessage("entity_list_default") .that(constants.getEntityListDefault()) .containsExactly("address", "email", "url", "phone", "date", "datetime", "flight"); assertWithMessage("entity_list_not_editable") .that(constants.getEntityListNotEditable()) .containsExactly("address", "email", "url", "phone", "date", "datetime", "flight"); assertWithMessage("entity_list_editable") .that(constants.getEntityListEditable()) .containsExactly("address", "email", "url", "phone", "date", "datetime", "flight"); assertWithMessage("in_app_conversation_action_types_default") .that(constants.getInAppConversationActionTypes()) .containsExactly("text_reply", "create_reminder", "call_phone", "open_url", "send_email", "send_sms", "track_flight", "view_calendar", "view_map"); assertWithMessage("notification_conversation_action_types_default") .that(constants.getNotificationConversationActionTypes()) .containsExactly("text_reply", "create_reminder", "call_phone", "open_url", "send_email", "send_sms", "track_flight", "view_calendar", "view_map"); assertWithMessage("lang_id_threshold_override") .that(constants.getLangIdThresholdOverride()).isWithin(EPSILON).of(-1f); } } Loading
core/java/android/provider/Settings.java +1 −0 Original line number Diff line number Diff line Loading @@ -11723,6 +11723,7 @@ public final class Settings { * entity_list_default (String[]) * entity_list_not_editable (String[]) * entity_list_editable (String[]) * lang_id_threshold_override (float) * </pre> * * <p> Loading
core/java/android/view/textclassifier/TextClassificationConstants.java +29 −10 Original line number Diff line number Diff line Loading @@ -46,6 +46,7 @@ import java.util.StringJoiner; * entity_list_default (String[]) * entity_list_not_editable (String[]) * entity_list_editable (String[]) * lang_id_threshold_override (float) * </pre> * * <p> Loading Loading @@ -94,6 +95,8 @@ public final class TextClassificationConstants { "in_app_conversation_action_types_default"; private static final String NOTIFICATION_CONVERSATION_ACTION_TYPES_DEFAULT = "notification_conversation_action_types_default"; private static final String LANG_ID_THRESHOLD_OVERRIDE = "lang_id_threshold_override"; private static final boolean LOCAL_TEXT_CLASSIFIER_ENABLED_DEFAULT = true; private static final boolean SYSTEM_TEXT_CLASSIFIER_ENABLED_DEFAULT = true; Loading @@ -106,8 +109,8 @@ public final class TextClassificationConstants { 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 ENTITY_LIST_DELIMITER = ":"; private static final String ENTITY_LIST_DEFAULT_VALUE = new StringJoiner(ENTITY_LIST_DELIMITER) 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) Loading @@ -116,7 +119,7 @@ public final class TextClassificationConstants { .add(TextClassifier.TYPE_DATE_TIME) .add(TextClassifier.TYPE_FLIGHT_NUMBER).toString(); private static final String CONVERSATION_ACTIONS_TYPES_DEFAULT_VALUES = new StringJoiner(ENTITY_LIST_DELIMITER) new StringJoiner(STRING_LIST_DELIMITER) .add(ConversationAction.TYPE_TEXT_REPLY) .add(ConversationAction.TYPE_CREATE_REMINDER) .add(ConversationAction.TYPE_CALL_PHONE) Loading @@ -127,6 +130,13 @@ public final class TextClassificationConstants { .add(ConversationAction.TYPE_VIEW_CALENDAR) .add(ConversationAction.TYPE_VIEW_MAP) .toString(); /** * < 0 : Not set. Use value from LangId model. * 0 - 1: Override value in LangId model. * > 1 : Effectively turns off the foreign language detection. Scores should never be > 1. * @see EntityConfidence */ private static final float LANG_ID_THRESHOLD_OVERRIDE_DEFAULT = -1f; private final boolean mSystemTextClassifierEnabled; private final boolean mLocalTextClassifierEnabled; Loading @@ -144,6 +154,7 @@ public final class TextClassificationConstants { private final List<String> mEntityListEditable; private final List<String> mInAppConversationActionTypesDefault; private final List<String> mNotificationConversationActionTypesDefault; private final float mLangIdThresholdOverride; private TextClassificationConstants(@Nullable String settings) { final KeyValueListParser parser = new KeyValueListParser(','); Loading Loading @@ -186,21 +197,24 @@ public final class TextClassificationConstants { mGenerateLinksLogSampleRate = parser.getInt( GENERATE_LINKS_LOG_SAMPLE_RATE, GENERATE_LINKS_LOG_SAMPLE_RATE_DEFAULT); mEntityListDefault = parseEntityList(parser.getString( mEntityListDefault = parseStringList(parser.getString( ENTITY_LIST_DEFAULT, ENTITY_LIST_DEFAULT_VALUE)); mEntityListNotEditable = parseEntityList(parser.getString( mEntityListNotEditable = parseStringList(parser.getString( ENTITY_LIST_NOT_EDITABLE, ENTITY_LIST_DEFAULT_VALUE)); mEntityListEditable = parseEntityList(parser.getString( mEntityListEditable = parseStringList(parser.getString( ENTITY_LIST_EDITABLE, ENTITY_LIST_DEFAULT_VALUE)); mInAppConversationActionTypesDefault = parseEntityList(parser.getString( mInAppConversationActionTypesDefault = parseStringList(parser.getString( IN_APP_CONVERSATION_ACTION_TYPES_DEFAULT, CONVERSATION_ACTIONS_TYPES_DEFAULT_VALUES)); mNotificationConversationActionTypesDefault = parseEntityList(parser.getString( mNotificationConversationActionTypesDefault = parseStringList(parser.getString( NOTIFICATION_CONVERSATION_ACTION_TYPES_DEFAULT, CONVERSATION_ACTIONS_TYPES_DEFAULT_VALUES)); mLangIdThresholdOverride = parser.getFloat( LANG_ID_THRESHOLD_OVERRIDE, LANG_ID_THRESHOLD_OVERRIDE_DEFAULT); } /** Load from a settings string. */ Loading Loading @@ -272,8 +286,12 @@ public final class TextClassificationConstants { return mNotificationConversationActionTypesDefault; } private static List<String> parseEntityList(String listStr) { return Collections.unmodifiableList(Arrays.asList(listStr.split(ENTITY_LIST_DELIMITER))); public float getLangIdThresholdOverride() { return mLangIdThresholdOverride; } private static List<String> parseStringList(String listStr) { return Collections.unmodifiableList(Arrays.asList(listStr.split(STRING_LIST_DELIMITER))); } void dump(IndentingPrintWriter pw) { Loading @@ -296,6 +314,7 @@ public final class TextClassificationConstants { pw.printPair("getInAppConversationActionTypes", mInAppConversationActionTypesDefault); pw.printPair("getNotificationConversationActionTypes", mNotificationConversationActionTypesDefault); pw.printPair("getLangIdThresholdOverride", mLangIdThresholdOverride); pw.decreaseIndent(); pw.println(); } Loading
core/java/android/view/textclassifier/TextClassifierImpl.java +7 −2 Original line number Diff line number Diff line Loading @@ -567,8 +567,9 @@ public final class TextClassifierImpl implements TextClassifier { } } // TODO: Make this configurable. final float foreignTextThreshold = typeCount == 0 ? 0.5f : 0.7f; final float foreignTextThreshold = mSettings.getLangIdThresholdOverride() >= 0 ? mSettings.getLangIdThresholdOverride() : 0.5f /* TODO: Load this from the langId model. */; boolean isPrimaryAction = true; final ArrayList<Intent> sourceIntents = new ArrayList<>(); for (LabeledIntent labeledIntent : IntentFactory.create( Loading Loading @@ -602,6 +603,10 @@ public final class TextClassifierImpl implements TextClassifier { } private boolean isForeignText(String text, float threshold) { if (threshold > 1) { return false; } // TODO: Revisit this algorithm. try { final LangIdModel.LanguageResult[] langResults = getLangIdImpl().detectLanguages(text); Loading
core/java/android/view/textclassifier/TextLanguage.java +4 −2 Original line number Diff line number Diff line Loading @@ -89,9 +89,10 @@ public final class TextLanguage implements Parcelable { /** * Returns the language locale at the specified index. Locales are ordered from high * confidence to low confidence. * <p> * See {@link #getLocaleHypothesisCount()} for the number of locales available. * * @throws IndexOutOfBoundsException if the specified index is out of range. * @see #getLocaleHypothesisCount() for the number of locales available. */ @NonNull public ULocale getLocale(int index) { Loading @@ -109,7 +110,8 @@ public final class TextLanguage implements Parcelable { } /** * Returns a bundle containing non-structured extra information about this result. * Returns a bundle containing non-structured extra information about this result. What is * returned in the extras is specific to the {@link TextClassifier} implementation. * * <p><b>NOTE: </b>Each call to this method returns a new bundle copy so clients should prefer * to hold a reference to the returned bundle rather than frequently calling this method. Loading
core/tests/coretests/src/android/view/textclassifier/TextClassificationConstantsTest.java +142 −53 Original line number Diff line number Diff line Loading @@ -16,9 +16,7 @@ package android.view.textclassifier; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import static com.google.common.truth.Truth.assertWithMessage; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; Loading @@ -30,6 +28,8 @@ import org.junit.runner.RunWith; @RunWith(AndroidJUnit4.class) public class TextClassificationConstantsTest { private static final float EPSILON = 0.0001f; @Test public void testLoadFromString() { final String s = "local_textclassifier_enabled=true," Loading @@ -42,26 +42,55 @@ public class TextClassificationConstantsTest { + "suggest_selection_max_range_length=10," + "classify_text_max_range_length=11," + "generate_links_max_text_length=12," + "generate_links_log_sample_rate=13"; + "generate_links_log_sample_rate=13," + "entity_list_default=phone," + "entity_list_not_editable=address:flight," + "entity_list_editable=date:datetime," + "in_app_conversation_action_types_default=text_reply," + "notification_conversation_action_types_default=send_email:call_phone," + "lang_id_threshold_override=0.3"; final TextClassificationConstants constants = TextClassificationConstants.loadFromString(s); assertTrue("local_textclassifier_enabled", constants.isLocalTextClassifierEnabled()); assertTrue("system_textclassifier_enabled", constants.isSystemTextClassifierEnabled()); assertTrue("model_dark_launch_enabled", constants.isModelDarkLaunchEnabled()); assertTrue("smart_selection_enabled", constants.isSmartSelectionEnabled()); assertTrue("smart_text_share_enabled", constants.isSmartTextShareEnabled()); assertTrue("smart_linkify_enabled", constants.isSmartLinkifyEnabled()); assertTrue("smart_select_animation_enabled", constants.isSmartSelectionAnimationEnabled()); assertEquals("suggest_selection_max_range_length", 10, constants.getSuggestSelectionMaxRangeLength()); assertEquals("classify_text_max_range_length", 11, constants.getClassifyTextMaxRangeLength()); assertEquals("generate_links_max_text_length", 12, constants.getGenerateLinksMaxTextLength()); assertEquals("generate_links_log_sample_rate", 13, constants.getGenerateLinksLogSampleRate()); assertWithMessage("local_textclassifier_enabled") .that(constants.isLocalTextClassifierEnabled()).isTrue(); assertWithMessage("system_textclassifier_enabled") .that(constants.isSystemTextClassifierEnabled()).isTrue(); assertWithMessage("model_dark_launch_enabled") .that(constants.isModelDarkLaunchEnabled()).isTrue(); assertWithMessage("smart_selection_enabled") .that(constants.isSmartSelectionEnabled()).isTrue(); assertWithMessage("smart_text_share_enabled") .that(constants.isSmartTextShareEnabled()).isTrue(); assertWithMessage("smart_linkify_enabled") .that(constants.isSmartLinkifyEnabled()).isTrue(); assertWithMessage("smart_select_animation_enabled") .that(constants.isSmartSelectionAnimationEnabled()).isTrue(); assertWithMessage("suggest_selection_max_range_length") .that(constants.getSuggestSelectionMaxRangeLength()).isEqualTo(10); assertWithMessage("classify_text_max_range_length") .that(constants.getClassifyTextMaxRangeLength()).isEqualTo(11); assertWithMessage("generate_links_max_text_length") .that(constants.getGenerateLinksMaxTextLength()).isEqualTo(12); assertWithMessage("generate_links_log_sample_rate") .that(constants.getGenerateLinksLogSampleRate()).isEqualTo(13); assertWithMessage("entity_list_default") .that(constants.getEntityListDefault()) .containsExactly("phone"); assertWithMessage("entity_list_not_editable") .that(constants.getEntityListNotEditable()) .containsExactly("address", "flight"); assertWithMessage("entity_list_editable") .that(constants.getEntityListEditable()) .containsExactly("date", "datetime"); assertWithMessage("in_app_conversation_action_types_default") .that(constants.getInAppConversationActionTypes()) .containsExactly("text_reply"); assertWithMessage("notification_conversation_action_types_default") .that(constants.getNotificationConversationActionTypes()) .containsExactly("send_email", "call_phone"); assertWithMessage("lang_id_threshold_override") .that(constants.getLangIdThresholdOverride()).isWithin(EPSILON).of(0.3f); } @Test Loading @@ -76,42 +105,102 @@ public class TextClassificationConstantsTest { + "suggest_selection_max_range_length=8," + "classify_text_max_range_length=7," + "generate_links_max_text_length=6," + "generate_links_log_sample_rate=5"; + "generate_links_log_sample_rate=5," + "entity_list_default=email:url," + "entity_list_not_editable=date," + "entity_list_editable=flight," + "in_app_conversation_action_types_default=view_map:track_flight," + "notification_conversation_action_types_default=share_location," + "lang_id_threshold_override=2"; final TextClassificationConstants constants = TextClassificationConstants.loadFromString(s); assertFalse("local_textclassifier_enabled", constants.isLocalTextClassifierEnabled()); assertFalse("system_textclassifier_enabled", constants.isSystemTextClassifierEnabled()); assertFalse("model_dark_launch_enabled", constants.isModelDarkLaunchEnabled()); assertFalse("smart_selection_enabled", constants.isSmartSelectionEnabled()); assertFalse("smart_text_share_enabled", constants.isSmartTextShareEnabled()); assertFalse("smart_linkify_enabled", constants.isSmartLinkifyEnabled()); assertFalse("smart_select_animation_enabled", constants.isSmartSelectionAnimationEnabled()); assertEquals("suggest_selection_max_range_length", 8, constants.getSuggestSelectionMaxRangeLength()); assertEquals("classify_text_max_range_length", 7, constants.getClassifyTextMaxRangeLength()); assertEquals("generate_links_max_text_length", 6, constants.getGenerateLinksMaxTextLength()); assertEquals("generate_links_log_sample_rate", 5, constants.getGenerateLinksLogSampleRate()); assertWithMessage("local_textclassifier_enabled") .that(constants.isLocalTextClassifierEnabled()).isFalse(); assertWithMessage("system_textclassifier_enabled") .that(constants.isSystemTextClassifierEnabled()).isFalse(); assertWithMessage("model_dark_launch_enabled") .that(constants.isModelDarkLaunchEnabled()).isFalse(); assertWithMessage("smart_selection_enabled") .that(constants.isSmartSelectionEnabled()).isFalse(); assertWithMessage("smart_text_share_enabled") .that(constants.isSmartTextShareEnabled()).isFalse(); assertWithMessage("smart_linkify_enabled") .that(constants.isSmartLinkifyEnabled()).isFalse(); assertWithMessage("smart_select_animation_enabled") .that(constants.isSmartSelectionAnimationEnabled()).isFalse(); assertWithMessage("suggest_selection_max_range_length") .that(constants.getSuggestSelectionMaxRangeLength()).isEqualTo(8); assertWithMessage("classify_text_max_range_length") .that(constants.getClassifyTextMaxRangeLength()).isEqualTo(7); assertWithMessage("generate_links_max_text_length") .that(constants.getGenerateLinksMaxTextLength()).isEqualTo(6); assertWithMessage("generate_links_log_sample_rate") .that(constants.getGenerateLinksLogSampleRate()).isEqualTo(5); assertWithMessage("entity_list_default") .that(constants.getEntityListDefault()) .containsExactly("email", "url"); assertWithMessage("entity_list_not_editable") .that(constants.getEntityListNotEditable()) .containsExactly("date"); assertWithMessage("entity_list_editable") .that(constants.getEntityListEditable()) .containsExactly("flight"); assertWithMessage("in_app_conversation_action_types_default") .that(constants.getInAppConversationActionTypes()) .containsExactly("view_map", "track_flight"); assertWithMessage("notification_conversation_action_types_default") .that(constants.getNotificationConversationActionTypes()) .containsExactly("share_location"); assertWithMessage("lang_id_threshold_override") .that(constants.getLangIdThresholdOverride()).isWithin(EPSILON).of(2f); } @Test public void testEntityListParsing() { final TextClassificationConstants constants = TextClassificationConstants.loadFromString( "entity_list_default=phone," + "entity_list_not_editable=address:flight," + "entity_list_editable=date:datetime"); assertEquals(1, constants.getEntityListDefault().size()); assertEquals("phone", constants.getEntityListDefault().get(0)); assertEquals(2, constants.getEntityListNotEditable().size()); assertEquals("address", constants.getEntityListNotEditable().get(0)); assertEquals("flight", constants.getEntityListNotEditable().get(1)); assertEquals(2, constants.getEntityListEditable().size()); assertEquals("date", constants.getEntityListEditable().get(0)); assertEquals("datetime", constants.getEntityListEditable().get(1)); public void testLoadFromString_defaultValues() { final TextClassificationConstants constants = TextClassificationConstants.loadFromString(""); assertWithMessage("local_textclassifier_enabled") .that(constants.isLocalTextClassifierEnabled()).isTrue(); assertWithMessage("system_textclassifier_enabled") .that(constants.isSystemTextClassifierEnabled()).isTrue(); assertWithMessage("model_dark_launch_enabled") .that(constants.isModelDarkLaunchEnabled()).isFalse(); assertWithMessage("smart_selection_enabled") .that(constants.isSmartSelectionEnabled()).isTrue(); assertWithMessage("smart_text_share_enabled") .that(constants.isSmartTextShareEnabled()).isTrue(); assertWithMessage("smart_linkify_enabled") .that(constants.isSmartLinkifyEnabled()).isTrue(); assertWithMessage("smart_select_animation_enabled") .that(constants.isSmartSelectionAnimationEnabled()).isTrue(); assertWithMessage("suggest_selection_max_range_length") .that(constants.getSuggestSelectionMaxRangeLength()).isEqualTo(10 * 1000); assertWithMessage("classify_text_max_range_length") .that(constants.getClassifyTextMaxRangeLength()).isEqualTo(10 * 1000); assertWithMessage("generate_links_max_text_length") .that(constants.getGenerateLinksMaxTextLength()).isEqualTo(100 * 1000); assertWithMessage("generate_links_log_sample_rate") .that(constants.getGenerateLinksLogSampleRate()).isEqualTo(100); assertWithMessage("entity_list_default") .that(constants.getEntityListDefault()) .containsExactly("address", "email", "url", "phone", "date", "datetime", "flight"); assertWithMessage("entity_list_not_editable") .that(constants.getEntityListNotEditable()) .containsExactly("address", "email", "url", "phone", "date", "datetime", "flight"); assertWithMessage("entity_list_editable") .that(constants.getEntityListEditable()) .containsExactly("address", "email", "url", "phone", "date", "datetime", "flight"); assertWithMessage("in_app_conversation_action_types_default") .that(constants.getInAppConversationActionTypes()) .containsExactly("text_reply", "create_reminder", "call_phone", "open_url", "send_email", "send_sms", "track_flight", "view_calendar", "view_map"); assertWithMessage("notification_conversation_action_types_default") .that(constants.getNotificationConversationActionTypes()) .containsExactly("text_reply", "create_reminder", "call_phone", "open_url", "send_email", "send_sms", "track_flight", "view_calendar", "view_map"); assertWithMessage("lang_id_threshold_override") .that(constants.getLangIdThresholdOverride()).isWithin(EPSILON).of(-1f); } }