1 /*
2  * Copyright (C) 2017 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package android.view.textclassifier;
18 
19 import com.android.internal.util.IndentingPrintWriter;
20 
21 import java.util.Arrays;
22 import java.util.List;
23 import java.util.function.Supplier;
24 
25 /**
26  * TextClassifier specific settings.
27  * This is encoded as a key=value list, separated by commas.
28  * <p>
29  * Example of setting the values for testing.
30  * <p>
31  * <pre>
32  * adb shell settings put global text_classifier_constants \
33  *      model_dark_launch_enabled=true,smart_selection_enabled=true, \
34  *      entity_list_default=phone:address, \
35  *      lang_id_context_settings=20:1.0:0.4
36  * </pre>
37  * <p>
38  * Settings are also available in device config. These take precedence over those in settings
39  * global.
40  * <p>
41  * <pre>
42  * adb shell cmd device_config put textclassifier system_textclassifier_enabled true
43  * </pre>
44  *
45  * @see android.provider.Settings.Global.TEXT_CLASSIFIER_CONSTANTS
46  * @see android.provider.DeviceConfig.NAMESPACE_TEXTCLASSIFIER
47  * @hide
48  */
49 // TODO: Rename to TextClassifierSettings.
50 public final class TextClassificationConstants {
51 
52     /**
53      * Whether the smart linkify feature is enabled.
54      */
55     private static final String SMART_LINKIFY_ENABLED = "smart_linkify_enabled";
56     /**
57      * Whether SystemTextClassifier is enabled.
58      */
59     private static final String SYSTEM_TEXT_CLASSIFIER_ENABLED = "system_textclassifier_enabled";
60     /**
61      * Whether TextClassifierImpl is enabled.
62      */
63     private static final String LOCAL_TEXT_CLASSIFIER_ENABLED = "local_textclassifier_enabled";
64     /**
65      * Enable smart selection without a visible UI changes.
66      */
67     private static final String MODEL_DARK_LAUNCH_ENABLED = "model_dark_launch_enabled";
68 
69     /**
70      * Whether the smart selection feature is enabled.
71      */
72     private static final String SMART_SELECTION_ENABLED = "smart_selection_enabled";
73     /**
74      * Whether the smart text share feature is enabled.
75      */
76     private static final String SMART_TEXT_SHARE_ENABLED = "smart_text_share_enabled";
77     /**
78      * Whether animation for smart selection is enabled.
79      */
80     private static final String SMART_SELECT_ANIMATION_ENABLED =
81             "smart_select_animation_enabled";
82     /**
83      * Max length of text that suggestSelection can accept.
84      */
85     private static final String SUGGEST_SELECTION_MAX_RANGE_LENGTH =
86             "suggest_selection_max_range_length";
87     /**
88      * Max length of text that classifyText can accept.
89      */
90     private static final String CLASSIFY_TEXT_MAX_RANGE_LENGTH = "classify_text_max_range_length";
91     /**
92      * Max length of text that generateLinks can accept.
93      */
94     private static final String GENERATE_LINKS_MAX_TEXT_LENGTH = "generate_links_max_text_length";
95     /**
96      * Sampling rate for generateLinks logging.
97      */
98     private static final String GENERATE_LINKS_LOG_SAMPLE_RATE =
99             "generate_links_log_sample_rate";
100     /**
101      * A colon(:) separated string that specifies the default entities types for
102      * generateLinks when hint is not given.
103      */
104     private static final String ENTITY_LIST_DEFAULT = "entity_list_default";
105     /**
106      * A colon(:) separated string that specifies the default entities types for
107      * generateLinks when the text is in a not editable UI widget.
108      */
109     private static final String ENTITY_LIST_NOT_EDITABLE = "entity_list_not_editable";
110     /**
111      * A colon(:) separated string that specifies the default entities types for
112      * generateLinks when the text is in an editable UI widget.
113      */
114     private static final String ENTITY_LIST_EDITABLE = "entity_list_editable";
115     /**
116      * A colon(:) separated string that specifies the default action types for
117      * suggestConversationActions when the suggestions are used in an app.
118      */
119     private static final String IN_APP_CONVERSATION_ACTION_TYPES_DEFAULT =
120             "in_app_conversation_action_types_default";
121     /**
122      * A colon(:) separated string that specifies the default action types for
123      * suggestConversationActions when the suggestions are used in a notification.
124      */
125     private static final String NOTIFICATION_CONVERSATION_ACTION_TYPES_DEFAULT =
126             "notification_conversation_action_types_default";
127     /**
128      * Threshold to accept a suggested language from LangID model.
129      */
130     private static final String LANG_ID_THRESHOLD_OVERRIDE = "lang_id_threshold_override";
131     /**
132      * Whether to enable {@link android.view.textclassifier.TemplateIntentFactory}.
133      */
134     private static final String TEMPLATE_INTENT_FACTORY_ENABLED = "template_intent_factory_enabled";
135     /**
136      * Whether to enable "translate" action in classifyText.
137      */
138     private static final String TRANSLATE_IN_CLASSIFICATION_ENABLED =
139             "translate_in_classification_enabled";
140     /**
141      * Whether to detect the languages of the text in request by using langId for the native
142      * model.
143      */
144     private static final String DETECT_LANGUAGES_FROM_TEXT_ENABLED =
145             "detect_languages_from_text_enabled";
146     /**
147      * A colon(:) separated string that specifies the configuration to use when including
148      * surrounding context text in language detection queries.
149      * <p>
150      * Format= minimumTextSize<int>:penalizeRatio<float>:textScoreRatio<float>
151      * <p>
152      * e.g. 20:1.0:0.4
153      * <p>
154      * Accept all text lengths with minimumTextSize=0
155      * <p>
156      * Reject all text less than minimumTextSize with penalizeRatio=0
157      * @see {@code TextClassifierImpl#detectLanguages(String, int, int)} for reference.
158      */
159     private static final String LANG_ID_CONTEXT_SETTINGS = "lang_id_context_settings";
160 
161     private static final boolean LOCAL_TEXT_CLASSIFIER_ENABLED_DEFAULT = true;
162     private static final boolean SYSTEM_TEXT_CLASSIFIER_ENABLED_DEFAULT = true;
163     private static final boolean MODEL_DARK_LAUNCH_ENABLED_DEFAULT = false;
164     private static final boolean SMART_SELECTION_ENABLED_DEFAULT = true;
165     private static final boolean SMART_TEXT_SHARE_ENABLED_DEFAULT = true;
166     private static final boolean SMART_LINKIFY_ENABLED_DEFAULT = true;
167     private static final boolean SMART_SELECT_ANIMATION_ENABLED_DEFAULT = true;
168     private static final int SUGGEST_SELECTION_MAX_RANGE_LENGTH_DEFAULT = 10 * 1000;
169     private static final int CLASSIFY_TEXT_MAX_RANGE_LENGTH_DEFAULT = 10 * 1000;
170     private static final int GENERATE_LINKS_MAX_TEXT_LENGTH_DEFAULT = 100 * 1000;
171     private static final int GENERATE_LINKS_LOG_SAMPLE_RATE_DEFAULT = 100;
172     private static final List<String> ENTITY_LIST_DEFAULT_VALUE = Arrays.asList(
173             TextClassifier.TYPE_ADDRESS,
174             TextClassifier.TYPE_EMAIL,
175             TextClassifier.TYPE_PHONE,
176             TextClassifier.TYPE_URL,
177             TextClassifier.TYPE_DATE,
178             TextClassifier.TYPE_DATE_TIME,
179             TextClassifier.TYPE_FLIGHT_NUMBER);
180     private static final List<String> CONVERSATION_ACTIONS_TYPES_DEFAULT_VALUES = Arrays.asList(
181             ConversationAction.TYPE_TEXT_REPLY,
182             ConversationAction.TYPE_CREATE_REMINDER,
183             ConversationAction.TYPE_CALL_PHONE,
184             ConversationAction.TYPE_OPEN_URL,
185             ConversationAction.TYPE_SEND_EMAIL,
186             ConversationAction.TYPE_SEND_SMS,
187             ConversationAction.TYPE_TRACK_FLIGHT,
188             ConversationAction.TYPE_VIEW_CALENDAR,
189             ConversationAction.TYPE_VIEW_MAP,
190             ConversationAction.TYPE_ADD_CONTACT,
191             ConversationAction.TYPE_COPY);
192     /**
193      * < 0  : Not set. Use value from LangId model.
194      * 0 - 1: Override value in LangId model.
195      *
196      * @see EntityConfidence
197      */
198     private static final float LANG_ID_THRESHOLD_OVERRIDE_DEFAULT = -1f;
199     private static final boolean TEMPLATE_INTENT_FACTORY_ENABLED_DEFAULT = true;
200     private static final boolean TRANSLATE_IN_CLASSIFICATION_ENABLED_DEFAULT = true;
201     private static final boolean DETECT_LANGUAGES_FROM_TEXT_ENABLED_DEFAULT = true;
202     private static final float[] LANG_ID_CONTEXT_SETTINGS_DEFAULT = new float[] {20f, 1.0f, 0.4f};
203 
204     private final ConfigParser mConfigParser;
205 
TextClassificationConstants(Supplier<String> legacySettingsSupplier)206     public TextClassificationConstants(Supplier<String> legacySettingsSupplier) {
207         mConfigParser = new ConfigParser(legacySettingsSupplier);
208     }
209 
isLocalTextClassifierEnabled()210     public boolean isLocalTextClassifierEnabled() {
211         return mConfigParser.getBoolean(
212                 LOCAL_TEXT_CLASSIFIER_ENABLED,
213                 LOCAL_TEXT_CLASSIFIER_ENABLED_DEFAULT);
214     }
215 
isSystemTextClassifierEnabled()216     public boolean isSystemTextClassifierEnabled() {
217         return mConfigParser.getBoolean(
218                 SYSTEM_TEXT_CLASSIFIER_ENABLED,
219                 SYSTEM_TEXT_CLASSIFIER_ENABLED_DEFAULT);
220     }
221 
isModelDarkLaunchEnabled()222     public boolean isModelDarkLaunchEnabled() {
223         return mConfigParser.getBoolean(
224                 MODEL_DARK_LAUNCH_ENABLED,
225                 MODEL_DARK_LAUNCH_ENABLED_DEFAULT);
226     }
227 
isSmartSelectionEnabled()228     public boolean isSmartSelectionEnabled() {
229         return mConfigParser.getBoolean(
230                 SMART_SELECTION_ENABLED,
231                 SMART_SELECTION_ENABLED_DEFAULT);
232     }
233 
isSmartTextShareEnabled()234     public boolean isSmartTextShareEnabled() {
235         return mConfigParser.getBoolean(
236                 SMART_TEXT_SHARE_ENABLED,
237                 SMART_TEXT_SHARE_ENABLED_DEFAULT);
238     }
239 
isSmartLinkifyEnabled()240     public boolean isSmartLinkifyEnabled() {
241         return mConfigParser.getBoolean(
242                 SMART_LINKIFY_ENABLED,
243                 SMART_LINKIFY_ENABLED_DEFAULT);
244     }
245 
isSmartSelectionAnimationEnabled()246     public boolean isSmartSelectionAnimationEnabled() {
247         return mConfigParser.getBoolean(
248                 SMART_SELECT_ANIMATION_ENABLED,
249                 SMART_SELECT_ANIMATION_ENABLED_DEFAULT);
250     }
251 
getSuggestSelectionMaxRangeLength()252     public int getSuggestSelectionMaxRangeLength() {
253         return mConfigParser.getInt(
254                 SUGGEST_SELECTION_MAX_RANGE_LENGTH,
255                 SUGGEST_SELECTION_MAX_RANGE_LENGTH_DEFAULT);
256     }
257 
getClassifyTextMaxRangeLength()258     public int getClassifyTextMaxRangeLength() {
259         return mConfigParser.getInt(
260                 CLASSIFY_TEXT_MAX_RANGE_LENGTH,
261                 CLASSIFY_TEXT_MAX_RANGE_LENGTH_DEFAULT);
262     }
263 
getGenerateLinksMaxTextLength()264     public int getGenerateLinksMaxTextLength() {
265         return mConfigParser.getInt(
266                 GENERATE_LINKS_MAX_TEXT_LENGTH,
267                 GENERATE_LINKS_MAX_TEXT_LENGTH_DEFAULT);
268     }
269 
getGenerateLinksLogSampleRate()270     public int getGenerateLinksLogSampleRate() {
271         return mConfigParser.getInt(
272                 GENERATE_LINKS_LOG_SAMPLE_RATE,
273                 GENERATE_LINKS_LOG_SAMPLE_RATE_DEFAULT);
274     }
275 
getEntityListDefault()276     public List<String> getEntityListDefault() {
277         return mConfigParser.getStringList(
278                 ENTITY_LIST_DEFAULT,
279                 ENTITY_LIST_DEFAULT_VALUE);
280     }
281 
getEntityListNotEditable()282     public List<String> getEntityListNotEditable() {
283         return mConfigParser.getStringList(
284                 ENTITY_LIST_NOT_EDITABLE,
285                 ENTITY_LIST_DEFAULT_VALUE);
286     }
287 
getEntityListEditable()288     public List<String> getEntityListEditable() {
289         return mConfigParser.getStringList(
290                 ENTITY_LIST_EDITABLE,
291                 ENTITY_LIST_DEFAULT_VALUE);
292     }
293 
getInAppConversationActionTypes()294     public List<String> getInAppConversationActionTypes() {
295         return mConfigParser.getStringList(
296                 IN_APP_CONVERSATION_ACTION_TYPES_DEFAULT,
297                 CONVERSATION_ACTIONS_TYPES_DEFAULT_VALUES);
298     }
299 
getNotificationConversationActionTypes()300     public List<String> getNotificationConversationActionTypes() {
301         return mConfigParser.getStringList(
302                 NOTIFICATION_CONVERSATION_ACTION_TYPES_DEFAULT,
303                 CONVERSATION_ACTIONS_TYPES_DEFAULT_VALUES);
304     }
305 
getLangIdThresholdOverride()306     public float getLangIdThresholdOverride() {
307         return mConfigParser.getFloat(
308                 LANG_ID_THRESHOLD_OVERRIDE,
309                 LANG_ID_THRESHOLD_OVERRIDE_DEFAULT);
310     }
311 
isTemplateIntentFactoryEnabled()312     public boolean isTemplateIntentFactoryEnabled() {
313         return mConfigParser.getBoolean(
314                 TEMPLATE_INTENT_FACTORY_ENABLED,
315                 TEMPLATE_INTENT_FACTORY_ENABLED_DEFAULT);
316     }
317 
isTranslateInClassificationEnabled()318     public boolean isTranslateInClassificationEnabled() {
319         return mConfigParser.getBoolean(
320                 TRANSLATE_IN_CLASSIFICATION_ENABLED,
321                 TRANSLATE_IN_CLASSIFICATION_ENABLED_DEFAULT);
322     }
323 
isDetectLanguagesFromTextEnabled()324     public boolean isDetectLanguagesFromTextEnabled() {
325         return mConfigParser.getBoolean(
326                 DETECT_LANGUAGES_FROM_TEXT_ENABLED,
327                 DETECT_LANGUAGES_FROM_TEXT_ENABLED_DEFAULT);
328     }
329 
getLangIdContextSettings()330     public float[] getLangIdContextSettings() {
331         return mConfigParser.getFloatArray(
332                 LANG_ID_CONTEXT_SETTINGS,
333                 LANG_ID_CONTEXT_SETTINGS_DEFAULT);
334     }
335 
dump(IndentingPrintWriter pw)336     void dump(IndentingPrintWriter pw) {
337         pw.println("TextClassificationConstants:");
338         pw.increaseIndent();
339         pw.printPair("classify_text_max_range_length", getClassifyTextMaxRangeLength())
340                 .println();
341         pw.printPair("detect_language_from_text_enabled", isDetectLanguagesFromTextEnabled())
342                 .println();
343         pw.printPair("entity_list_default", getEntityListDefault())
344                 .println();
345         pw.printPair("entity_list_editable", getEntityListEditable())
346                 .println();
347         pw.printPair("entity_list_not_editable", getEntityListNotEditable())
348                 .println();
349         pw.printPair("generate_links_log_sample_rate", getGenerateLinksLogSampleRate())
350                 .println();
351         pw.printPair("generate_links_max_text_length", getGenerateLinksMaxTextLength())
352                 .println();
353         pw.printPair("in_app_conversation_action_types_default", getInAppConversationActionTypes())
354                 .println();
355         pw.printPair("lang_id_context_settings", Arrays.toString(getLangIdContextSettings()))
356                 .println();
357         pw.printPair("lang_id_threshold_override", getLangIdThresholdOverride())
358                 .println();
359         pw.printPair("local_textclassifier_enabled", isLocalTextClassifierEnabled())
360                 .println();
361         pw.printPair("model_dark_launch_enabled", isModelDarkLaunchEnabled())
362                 .println();
363         pw.printPair("notification_conversation_action_types_default",
364                 getNotificationConversationActionTypes()).println();
365         pw.printPair("smart_linkify_enabled", isSmartLinkifyEnabled())
366                 .println();
367         pw.printPair("smart_select_animation_enabled", isSmartSelectionAnimationEnabled())
368                 .println();
369         pw.printPair("smart_selection_enabled", isSmartSelectionEnabled())
370                 .println();
371         pw.printPair("smart_text_share_enabled", isSmartTextShareEnabled())
372                 .println();
373         pw.printPair("suggest_selection_max_range_length", getSuggestSelectionMaxRangeLength())
374                 .println();
375         pw.printPair("system_textclassifier_enabled", isSystemTextClassifierEnabled())
376                 .println();
377         pw.printPair("template_intent_factory_enabled", isTemplateIntentFactoryEnabled())
378                 .println();
379         pw.printPair("translate_in_classification_enabled", isTranslateInClassificationEnabled())
380                 .println();
381         pw.decreaseIndent();
382     }
383 }