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 android.annotation.Nullable;
20 import android.provider.DeviceConfig;
21 
22 import com.android.internal.annotations.VisibleForTesting;
23 import com.android.internal.util.IndentingPrintWriter;
24 
25 import java.util.Optional;
26 
27 /**
28  * TextClassifier specific settings.
29  *
30  * <p>Currently, this class does not guarantee co-diverted flags are updated atomically.
31  *
32  * <pre>
33  * adb shell cmd device_config put textclassifier system_textclassifier_enabled true
34  * </pre>
35  *
36  * @see android.provider.DeviceConfig#NAMESPACE_TEXTCLASSIFIER
37  * @hide
38  */
39 // TODO: Rename to TextClassifierSettings.
40 public final class TextClassificationConstants {
41     /** Whether the smart linkify feature is enabled. */
42     private static final String SMART_LINKIFY_ENABLED = "smart_linkify_enabled";
43 
44     /** Whether SystemTextClassifier is enabled. */
45     static final String SYSTEM_TEXT_CLASSIFIER_ENABLED = "system_textclassifier_enabled";
46 
47     /** Whether TextClassifierImpl is enabled. */
48     @VisibleForTesting
49     static final String LOCAL_TEXT_CLASSIFIER_ENABLED = "local_textclassifier_enabled";
50 
51     /** Enable smart selection without a visible UI changes. */
52     private static final String MODEL_DARK_LAUNCH_ENABLED = "model_dark_launch_enabled";
53 
54     /** Whether the smart selection feature is enabled. */
55     private static final String SMART_SELECTION_ENABLED = "smart_selection_enabled";
56 
57     /** Whether the smart text share feature is enabled. */
58     private static final String SMART_TEXT_SHARE_ENABLED = "smart_text_share_enabled";
59 
60     /** Whether animation for smart selection is enabled. */
61     private static final String SMART_SELECT_ANIMATION_ENABLED = "smart_select_animation_enabled";
62 
63     /** Max length of text that generateLinks can accept. */
64     @VisibleForTesting
65     static final String GENERATE_LINKS_MAX_TEXT_LENGTH = "generate_links_max_text_length";
66 
67     /**
68      * The TextClassifierService which would like to use. Example of setting the package:
69      *
70      * <pre>
71      * adb shell cmd device_config put textclassifier textclassifier_service_package_override \
72      *      com.android.textclassifier
73      * </pre>
74      */
75     @VisibleForTesting
76     static final String TEXT_CLASSIFIER_SERVICE_PACKAGE_OVERRIDE =
77             "textclassifier_service_package_override";
78 
79     /**
80      * The timeout value in seconds used by {@link SystemTextClassifier} for each TextClassifier API
81      * calls.
82      */
83     @VisibleForTesting
84     static final String SYSTEM_TEXT_CLASSIFIER_API_TIMEOUT_IN_SECOND =
85             "system_textclassifier_api_timeout_in_second";
86 
87     /**
88      * The maximum amount of characters before and after the selected text that is passed to the
89      * TextClassifier for the smart selection. e.g. If this value is 100, then 100 characters before
90      * the selection and 100 characters after the selection will be passed to the TextClassifier.
91      */
92     private static final String SMART_SELECTION_TRIM_DELTA = "smart_selection_trim_delta";
93 
94     private static final String DEFAULT_TEXT_CLASSIFIER_SERVICE_PACKAGE_OVERRIDE = null;
95     private static final boolean LOCAL_TEXT_CLASSIFIER_ENABLED_DEFAULT = true;
96     private static final boolean SYSTEM_TEXT_CLASSIFIER_ENABLED_DEFAULT = true;
97     private static final boolean MODEL_DARK_LAUNCH_ENABLED_DEFAULT = false;
98     private static final boolean SMART_SELECTION_ENABLED_DEFAULT = true;
99     private static final boolean SMART_TEXT_SHARE_ENABLED_DEFAULT = true;
100     private static final boolean SMART_LINKIFY_ENABLED_DEFAULT = true;
101     private static final boolean SMART_SELECT_ANIMATION_ENABLED_DEFAULT = true;
102     private static final int GENERATE_LINKS_MAX_TEXT_LENGTH_DEFAULT = 100 * 1000;
103     private static final long SYSTEM_TEXT_CLASSIFIER_API_TIMEOUT_IN_SECOND_DEFAULT = 60;
104     private static final int SMART_SELECTION_TRIM_DELTA_DEFAULT = 120;
105 
106     private static final Object sLock = new Object();
107     private static volatile boolean sMemoizedValuesInitialized;
108     private static boolean sLocalTextClassifierEnabled;
109     private static boolean sSystemTextClassifierEnabled;
110     private static boolean sModelDarkLaunchEnabled;
111     private static boolean sSmartSelectionEnabled;
112     private static boolean sSmartTextShareEnabled;
113     private static boolean sSmartLinkifyEnabled;
114     private static boolean sSmartSelectAnimationEnabled;
115     private static int sGenerateLinksMaxTextLength;
116     private static long sSystemTextClassifierApiTimeoutInSecond;
117     private static int sSmartSelectionTrimDelta;
118 
119     /**
120      * For DeviceConfig values where we don't care if they change at runtime, fetch them once and
121      * memoize their values.
122      */
ensureMemoizedValues()123     private static void ensureMemoizedValues() {
124         if (sMemoizedValuesInitialized) {
125             return;
126         }
127         synchronized (sLock) {
128             if (sMemoizedValuesInitialized) {
129                 return;
130             }
131 
132             // Read all namespace properties so we get a single snapshot (values
133             // fetched aren't updated in the interim).
134             DeviceConfig.Properties properties =
135                     DeviceConfig.getProperties(DeviceConfig.NAMESPACE_TEXTCLASSIFIER);
136             sLocalTextClassifierEnabled =
137                     properties.getBoolean(
138                             LOCAL_TEXT_CLASSIFIER_ENABLED,
139                             LOCAL_TEXT_CLASSIFIER_ENABLED_DEFAULT);
140             sModelDarkLaunchEnabled =
141                     properties.getBoolean(
142                             MODEL_DARK_LAUNCH_ENABLED,
143                             MODEL_DARK_LAUNCH_ENABLED_DEFAULT);
144             sSmartSelectionEnabled =
145                     properties.getBoolean(
146                             SMART_SELECTION_ENABLED,
147                             SMART_SELECTION_ENABLED_DEFAULT);
148             sSmartTextShareEnabled =
149                     properties.getBoolean(
150                             SMART_TEXT_SHARE_ENABLED,
151                             SMART_TEXT_SHARE_ENABLED_DEFAULT);
152             sSmartLinkifyEnabled =
153                     properties.getBoolean(
154                             SMART_LINKIFY_ENABLED,
155                             SMART_LINKIFY_ENABLED_DEFAULT);
156             sSmartSelectAnimationEnabled =
157                     properties.getBoolean(
158                             SMART_SELECT_ANIMATION_ENABLED,
159                             SMART_SELECT_ANIMATION_ENABLED_DEFAULT);
160             sGenerateLinksMaxTextLength =
161                     properties.getInt(
162                             GENERATE_LINKS_MAX_TEXT_LENGTH,
163                             GENERATE_LINKS_MAX_TEXT_LENGTH_DEFAULT);
164             sSystemTextClassifierApiTimeoutInSecond =
165                     properties.getLong(
166                             SYSTEM_TEXT_CLASSIFIER_API_TIMEOUT_IN_SECOND,
167                             SYSTEM_TEXT_CLASSIFIER_API_TIMEOUT_IN_SECOND_DEFAULT);
168             sSmartSelectionTrimDelta =
169                     properties.getInt(
170                             SMART_SELECTION_TRIM_DELTA,
171                             SMART_SELECTION_TRIM_DELTA_DEFAULT);
172 
173             sMemoizedValuesInitialized = true;
174         }
175     }
176 
177     @VisibleForTesting
resetMemoizedValues()178     public static void resetMemoizedValues() {
179       sMemoizedValuesInitialized = false;
180     }
181 
182     @Nullable
getTextClassifierServicePackageOverride()183     public String getTextClassifierServicePackageOverride() {
184         // Don't memoize this value because we want to be able to receive config
185         // updates at runtime.
186         return DeviceConfig.getString(
187                 DeviceConfig.NAMESPACE_TEXTCLASSIFIER,
188                 TEXT_CLASSIFIER_SERVICE_PACKAGE_OVERRIDE,
189                 DEFAULT_TEXT_CLASSIFIER_SERVICE_PACKAGE_OVERRIDE);
190     }
191 
isLocalTextClassifierEnabled()192     public boolean isLocalTextClassifierEnabled() {
193         ensureMemoizedValues();
194         return sLocalTextClassifierEnabled;
195     }
196 
isSystemTextClassifierEnabled()197     public boolean isSystemTextClassifierEnabled() {
198         // Don't memoize this value because we want to be able to receive config
199         // updates at runtime.
200         return DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_TEXTCLASSIFIER,
201                 SYSTEM_TEXT_CLASSIFIER_ENABLED,
202                 SYSTEM_TEXT_CLASSIFIER_ENABLED_DEFAULT);
203     }
204 
isModelDarkLaunchEnabled()205     public boolean isModelDarkLaunchEnabled() {
206         ensureMemoizedValues();
207         return sModelDarkLaunchEnabled;
208     }
209 
isSmartSelectionEnabled()210     public boolean isSmartSelectionEnabled() {
211         ensureMemoizedValues();
212         return sSmartSelectionEnabled;
213     }
214 
isSmartTextShareEnabled()215     public boolean isSmartTextShareEnabled() {
216         ensureMemoizedValues();
217         return sSmartTextShareEnabled;
218     }
219 
isSmartLinkifyEnabled()220     public boolean isSmartLinkifyEnabled() {
221         ensureMemoizedValues();
222         return sSmartLinkifyEnabled;
223     }
224 
isSmartSelectionAnimationEnabled()225     public boolean isSmartSelectionAnimationEnabled() {
226         ensureMemoizedValues();
227         return sSmartSelectAnimationEnabled;
228     }
229 
getGenerateLinksMaxTextLength()230     public int getGenerateLinksMaxTextLength() {
231         ensureMemoizedValues();
232         return sGenerateLinksMaxTextLength;
233     }
234 
getSystemTextClassifierApiTimeoutInSecond()235     public long getSystemTextClassifierApiTimeoutInSecond() {
236         ensureMemoizedValues();
237         return sSystemTextClassifierApiTimeoutInSecond;
238     }
239 
getSmartSelectionTrimDelta()240     public int getSmartSelectionTrimDelta() {
241         ensureMemoizedValues();
242         return sSmartSelectionTrimDelta;
243     }
244 
dump(IndentingPrintWriter pw)245     void dump(IndentingPrintWriter pw) {
246         pw.println("TextClassificationConstants:");
247         pw.increaseIndent();
248         pw.print(GENERATE_LINKS_MAX_TEXT_LENGTH, getGenerateLinksMaxTextLength()).println();
249         pw.print(LOCAL_TEXT_CLASSIFIER_ENABLED, isLocalTextClassifierEnabled()).println();
250         pw.print(MODEL_DARK_LAUNCH_ENABLED, isModelDarkLaunchEnabled()).println();
251         pw.print(SMART_LINKIFY_ENABLED, isSmartLinkifyEnabled()).println();
252         pw.print(SMART_SELECT_ANIMATION_ENABLED, isSmartSelectionAnimationEnabled()).println();
253         pw.print(SMART_SELECTION_ENABLED, isSmartSelectionEnabled()).println();
254         pw.print(SMART_TEXT_SHARE_ENABLED, isSmartTextShareEnabled()).println();
255         pw.print(SYSTEM_TEXT_CLASSIFIER_ENABLED, isSystemTextClassifierEnabled()).println();
256         pw.print(
257                         TEXT_CLASSIFIER_SERVICE_PACKAGE_OVERRIDE,
258                         getTextClassifierServicePackageOverride())
259                 .println();
260         pw.print(
261                         SYSTEM_TEXT_CLASSIFIER_API_TIMEOUT_IN_SECOND,
262                         getSystemTextClassifierApiTimeoutInSecond())
263                 .println();
264         pw.print(SMART_SELECTION_TRIM_DELTA, getSmartSelectionTrimDelta()).println();
265         pw.decreaseIndent();
266     }
267 }
268