Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 92fd2908 authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Add threshold flag for foreign language detection."

parents 530c508e a77dba6a
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -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>
+29 −10
Original line number Diff line number Diff line
@@ -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>
@@ -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;
@@ -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)
@@ -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)
@@ -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;
@@ -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(',');
@@ -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. */
@@ -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) {
@@ -296,6 +314,7 @@ public final class TextClassificationConstants {
        pw.printPair("getInAppConversationActionTypes", mInAppConversationActionTypesDefault);
        pw.printPair("getNotificationConversationActionTypes",
                mNotificationConversationActionTypesDefault);
        pw.printPair("getLangIdThresholdOverride", mLangIdThresholdOverride);
        pw.decreaseIndent();
        pw.println();
    }
+7 −2
Original line number Diff line number Diff line
@@ -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(
@@ -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);
+4 −2
Original line number Diff line number Diff line
@@ -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) {
@@ -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.
+142 −53
Original line number Diff line number Diff line
@@ -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;
@@ -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,"
@@ -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
@@ -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);
    }
}