blob: e9715c5121eb8d31bfdf910793dfa4b17b6d9158 [file] [log] [blame]
Abodunrinwa Tokif001fef2017-01-04 23:51:42 +00001/*
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
17package android.view.textclassifier;
18
Richard Ledleydb18a572017-11-30 17:33:51 +000019import android.annotation.IntDef;
Abodunrinwa Tokif001fef2017-01-04 23:51:42 +000020import android.annotation.IntRange;
21import android.annotation.NonNull;
Abodunrinwa Toki4cfda0b2017-02-28 18:56:47 +000022import android.annotation.Nullable;
Abodunrinwa Tokif001fef2017-01-04 23:51:42 +000023import android.annotation.StringDef;
Abodunrinwa Tokie0b57892017-04-28 19:59:57 +010024import android.annotation.WorkerThread;
Abodunrinwa Toki4cfda0b2017-02-28 18:56:47 +000025import android.os.LocaleList;
Jan Althaus0d9fbb92017-11-28 12:19:33 +010026import android.os.Parcel;
27import android.os.Parcelable;
Richard Ledleydb18a572017-11-30 17:33:51 +000028import android.util.ArraySet;
Abodunrinwa Tokif001fef2017-01-04 23:51:42 +000029
Abodunrinwa Toki4d232d62017-11-23 12:22:45 +000030import com.android.internal.util.Preconditions;
31
Abodunrinwa Tokif001fef2017-01-04 23:51:42 +000032import java.lang.annotation.Retention;
33import java.lang.annotation.RetentionPolicy;
Richard Ledleydb18a572017-11-30 17:33:51 +000034import java.util.ArrayList;
35import java.util.Collection;
36import java.util.Collections;
37import java.util.List;
Abodunrinwa Tokif001fef2017-01-04 23:51:42 +000038
39/**
40 * Interface for providing text classification related features.
41 *
Abodunrinwa Toki33ff2002017-10-24 00:49:27 +010042 * <p>Unless otherwise stated, methods of this interface are blocking operations.
43 * Avoid calling them on the UI thread.
Abodunrinwa Tokif001fef2017-01-04 23:51:42 +000044 */
45public interface TextClassifier {
46
Abodunrinwa Toki692b1962017-08-15 15:05:11 +010047 /** @hide */
Abodunrinwa Toki008f3872017-11-27 19:32:35 +000048 String DEFAULT_LOG_TAG = "androidtc";
Abodunrinwa Toki692b1962017-08-15 15:05:11 +010049
Abodunrinwa Toki4d232d62017-11-23 12:22:45 +000050 String TYPE_UNKNOWN = "";
Abodunrinwa Tokif001fef2017-01-04 23:51:42 +000051 String TYPE_OTHER = "other";
52 String TYPE_EMAIL = "email";
53 String TYPE_PHONE = "phone";
54 String TYPE_ADDRESS = "address";
Abodunrinwa Toki9b4c82a2017-02-06 20:29:36 +000055 String TYPE_URL = "url";
Abodunrinwa Tokif001fef2017-01-04 23:51:42 +000056
Abodunrinwa Toki45cb3e62017-03-29 21:51:45 +010057 /** @hide */
Abodunrinwa Tokif001fef2017-01-04 23:51:42 +000058 @Retention(RetentionPolicy.SOURCE)
Jeff Sharkey5db9a912017-12-08 17:32:32 -070059 @StringDef(prefix = { "TYPE_" }, value = {
60 TYPE_UNKNOWN,
61 TYPE_OTHER,
62 TYPE_EMAIL,
63 TYPE_PHONE,
64 TYPE_ADDRESS,
65 TYPE_URL,
Abodunrinwa Tokif001fef2017-01-04 23:51:42 +000066 })
67 @interface EntityType {}
68
Richard Ledleydb18a572017-11-30 17:33:51 +000069 /** Designates that the TextClassifier should identify all entity types it can. **/
70 int ENTITY_PRESET_ALL = 0;
71 /** Designates that the TextClassifier should identify no entities. **/
72 int ENTITY_PRESET_NONE = 1;
73 /** Designates that the TextClassifier should identify a base set of entities determined by the
74 * TextClassifier. **/
75 int ENTITY_PRESET_BASE = 2;
76
77 /** @hide */
78 @Retention(RetentionPolicy.SOURCE)
79 @IntDef(prefix = { "ENTITY_CONFIG_" },
80 value = {ENTITY_PRESET_ALL, ENTITY_PRESET_NONE, ENTITY_PRESET_BASE})
81 @interface EntityPreset {}
82
Abodunrinwa Tokif001fef2017-01-04 23:51:42 +000083 /**
84 * No-op TextClassifier.
85 * This may be used to turn off TextClassifier features.
86 */
Abodunrinwa Toki2b6020f2017-10-28 02:28:45 +010087 TextClassifier NO_OP = new TextClassifier() {};
Abodunrinwa Tokif001fef2017-01-04 23:51:42 +000088
89 /**
Abodunrinwa Toki33ff2002017-10-24 00:49:27 +010090 * Returns suggested text selection start and end indices, recognized entity types, and their
91 * associated confidence scores. The entity types are ordered from highest to lowest scoring.
Abodunrinwa Tokif001fef2017-01-04 23:51:42 +000092 *
93 * @param text text providing context for the selected text (which is specified
94 * by the sub sequence starting at selectionStartIndex and ending at selectionEndIndex)
95 * @param selectionStartIndex start index of the selected part of text
96 * @param selectionEndIndex end index of the selected part of text
Abodunrinwa Toki2b6020f2017-10-28 02:28:45 +010097 * @param options optional input parameters
Abodunrinwa Tokif001fef2017-01-04 23:51:42 +000098 *
99 * @throws IllegalArgumentException if text is null; selectionStartIndex is negative;
Abodunrinwa Toki4cfda0b2017-02-28 18:56:47 +0000100 * selectionEndIndex is greater than text.length() or not greater than selectionStartIndex
Abodunrinwa Toki4d232d62017-11-23 12:22:45 +0000101 *
102 * @see #suggestSelection(CharSequence, int, int)
Abodunrinwa Tokif001fef2017-01-04 23:51:42 +0000103 */
Abodunrinwa Tokie0b57892017-04-28 19:59:57 +0100104 @WorkerThread
Abodunrinwa Tokif001fef2017-01-04 23:51:42 +0000105 @NonNull
Abodunrinwa Toki2b6020f2017-10-28 02:28:45 +0100106 default TextSelection suggestSelection(
Abodunrinwa Tokif001fef2017-01-04 23:51:42 +0000107 @NonNull CharSequence text,
108 @IntRange(from = 0) int selectionStartIndex,
Abodunrinwa Toki4cfda0b2017-02-28 18:56:47 +0000109 @IntRange(from = 0) int selectionEndIndex,
Abodunrinwa Toki2b6020f2017-10-28 02:28:45 +0100110 @Nullable TextSelection.Options options) {
Abodunrinwa Toki4d232d62017-11-23 12:22:45 +0000111 Utils.validateInput(text, selectionStartIndex, selectionEndIndex);
Abodunrinwa Toki2b6020f2017-10-28 02:28:45 +0100112 return new TextSelection.Builder(selectionStartIndex, selectionEndIndex).build();
113 }
114
115 /**
Abodunrinwa Toki4d232d62017-11-23 12:22:45 +0000116 * Returns suggested text selection start and end indices, recognized entity types, and their
117 * associated confidence scores. The entity types are ordered from highest to lowest scoring.
118 *
119 * <p><b>NOTE:</b> Do not implement. The default implementation of this method calls
120 * {@link #suggestSelection(CharSequence, int, int, TextSelection.Options)}. If that method
121 * calls this method, a stack overflow error will happen.
122 *
123 * @param text text providing context for the selected text (which is specified
124 * by the sub sequence starting at selectionStartIndex and ending at selectionEndIndex)
125 * @param selectionStartIndex start index of the selected part of text
126 * @param selectionEndIndex end index of the selected part of text
127 *
128 * @throws IllegalArgumentException if text is null; selectionStartIndex is negative;
129 * selectionEndIndex is greater than text.length() or not greater than selectionStartIndex
130 *
Abodunrinwa Toki2b6020f2017-10-28 02:28:45 +0100131 * @see #suggestSelection(CharSequence, int, int, TextSelection.Options)
132 */
Abodunrinwa Toki4d232d62017-11-23 12:22:45 +0000133 @WorkerThread
134 @NonNull
135 default TextSelection suggestSelection(
136 @NonNull CharSequence text,
137 @IntRange(from = 0) int selectionStartIndex,
138 @IntRange(from = 0) int selectionEndIndex) {
139 return suggestSelection(text, selectionStartIndex, selectionEndIndex,
140 (TextSelection.Options) null);
141 }
142
143 /**
144 * See {@link #suggestSelection(CharSequence, int, int)} or
145 * {@link #suggestSelection(CharSequence, int, int, TextSelection.Options)}.
146 *
147 * <p><b>NOTE:</b> Do not implement. The default implementation of this method calls
148 * {@link #suggestSelection(CharSequence, int, int, TextSelection.Options)}. If that method
149 * calls this method, a stack overflow error will happen.
150 */
Abodunrinwa Toki2b6020f2017-10-28 02:28:45 +0100151 @WorkerThread
152 @NonNull
153 default TextSelection suggestSelection(
154 @NonNull CharSequence text,
155 @IntRange(from = 0) int selectionStartIndex,
156 @IntRange(from = 0) int selectionEndIndex,
157 @Nullable LocaleList defaultLocales) {
Abodunrinwa Toki4d232d62017-11-23 12:22:45 +0000158 final TextSelection.Options options = (defaultLocales != null)
159 ? new TextSelection.Options().setDefaultLocales(defaultLocales)
160 : null;
161 return suggestSelection(text, selectionStartIndex, selectionEndIndex, options);
Abodunrinwa Toki2b6020f2017-10-28 02:28:45 +0100162 }
Abodunrinwa Tokif001fef2017-01-04 23:51:42 +0000163
164 /**
Abodunrinwa Tokie0b57892017-04-28 19:59:57 +0100165 * Classifies the specified text and returns a {@link TextClassification} object that can be
166 * used to generate a widget for handling the classified text.
Abodunrinwa Tokif001fef2017-01-04 23:51:42 +0000167 *
168 * @param text text providing context for the text to classify (which is specified
169 * by the sub sequence starting at startIndex and ending at endIndex)
170 * @param startIndex start index of the text to classify
171 * @param endIndex end index of the text to classify
Abodunrinwa Toki2b6020f2017-10-28 02:28:45 +0100172 * @param options optional input parameters
Abodunrinwa Tokif001fef2017-01-04 23:51:42 +0000173 *
174 * @throws IllegalArgumentException if text is null; startIndex is negative;
Abodunrinwa Toki4cfda0b2017-02-28 18:56:47 +0000175 * endIndex is greater than text.length() or not greater than startIndex
Abodunrinwa Toki4d232d62017-11-23 12:22:45 +0000176 *
177 * @see #classifyText(CharSequence, int, int)
Abodunrinwa Tokif001fef2017-01-04 23:51:42 +0000178 */
Abodunrinwa Tokie0b57892017-04-28 19:59:57 +0100179 @WorkerThread
Abodunrinwa Tokif001fef2017-01-04 23:51:42 +0000180 @NonNull
Abodunrinwa Toki2b6020f2017-10-28 02:28:45 +0100181 default TextClassification classifyText(
Abodunrinwa Toki4cfda0b2017-02-28 18:56:47 +0000182 @NonNull CharSequence text,
183 @IntRange(from = 0) int startIndex,
184 @IntRange(from = 0) int endIndex,
Abodunrinwa Toki2b6020f2017-10-28 02:28:45 +0100185 @Nullable TextClassification.Options options) {
Abodunrinwa Toki4d232d62017-11-23 12:22:45 +0000186 Utils.validateInput(text, startIndex, endIndex);
Abodunrinwa Toki2b6020f2017-10-28 02:28:45 +0100187 return TextClassification.EMPTY;
188 }
189
190 /**
Abodunrinwa Toki4d232d62017-11-23 12:22:45 +0000191 * Classifies the specified text and returns a {@link TextClassification} object that can be
192 * used to generate a widget for handling the classified text.
193 *
194 * <p><b>NOTE:</b> Do not implement. The default implementation of this method calls
195 * {@link #classifyText(CharSequence, int, int, TextClassification.Options)}. If that method
196 * calls this method, a stack overflow error will happen.
197 *
198 * @param text text providing context for the text to classify (which is specified
199 * by the sub sequence starting at startIndex and ending at endIndex)
200 * @param startIndex start index of the text to classify
201 * @param endIndex end index of the text to classify
202 *
203 * @throws IllegalArgumentException if text is null; startIndex is negative;
204 * endIndex is greater than text.length() or not greater than startIndex
205 *
Abodunrinwa Toki2b6020f2017-10-28 02:28:45 +0100206 * @see #classifyText(CharSequence, int, int, TextClassification.Options)
207 */
Abodunrinwa Toki4d232d62017-11-23 12:22:45 +0000208 @WorkerThread
209 @NonNull
210 default TextClassification classifyText(
211 @NonNull CharSequence text,
212 @IntRange(from = 0) int startIndex,
213 @IntRange(from = 0) int endIndex) {
214 return classifyText(text, startIndex, endIndex, (TextClassification.Options) null);
215 }
216
217 /**
218 * See {@link #classifyText(CharSequence, int, int, TextClassification.Options)} or
219 * {@link #classifyText(CharSequence, int, int)}.
220 *
221 * <p><b>NOTE:</b> Do not implement. The default implementation of this method calls
222 * {@link #classifyText(CharSequence, int, int, TextClassification.Options)}. If that method
223 * calls this method, a stack overflow error will happen.
224 */
Abodunrinwa Toki2b6020f2017-10-28 02:28:45 +0100225 @WorkerThread
226 @NonNull
227 default TextClassification classifyText(
228 @NonNull CharSequence text,
229 @IntRange(from = 0) int startIndex,
230 @IntRange(from = 0) int endIndex,
231 @Nullable LocaleList defaultLocales) {
Abodunrinwa Toki4d232d62017-11-23 12:22:45 +0000232 final TextClassification.Options options = (defaultLocales != null)
233 ? new TextClassification.Options().setDefaultLocales(defaultLocales)
234 : null;
235 return classifyText(text, startIndex, endIndex, options);
Abodunrinwa Toki2b6020f2017-10-28 02:28:45 +0100236 }
Abodunrinwa Tokif001fef2017-01-04 23:51:42 +0000237
238 /**
Richard Ledley68d94522017-10-05 10:52:19 +0100239 * Returns a {@link TextLinks} that may be applied to the text to annotate it with links
240 * information.
241 *
Richard Ledleydb18a572017-11-30 17:33:51 +0000242 * If no options are supplied, default values will be used, determined by the TextClassifier.
243 *
Richard Ledley68d94522017-10-05 10:52:19 +0100244 * @param text the text to generate annotations for
Abodunrinwa Toki4d232d62017-11-23 12:22:45 +0000245 * @param options configuration for link generation
Richard Ledley68d94522017-10-05 10:52:19 +0100246 *
247 * @throws IllegalArgumentException if text is null
Abodunrinwa Toki4d232d62017-11-23 12:22:45 +0000248 *
249 * @see #generateLinks(CharSequence)
Richard Ledley68d94522017-10-05 10:52:19 +0100250 */
251 @WorkerThread
252 default TextLinks generateLinks(
253 @NonNull CharSequence text, @Nullable TextLinks.Options options) {
Abodunrinwa Toki4d232d62017-11-23 12:22:45 +0000254 Utils.validateInput(text);
Richard Ledley68d94522017-10-05 10:52:19 +0100255 return new TextLinks.Builder(text.toString()).build();
256 }
257
258 /**
Abodunrinwa Toki4d232d62017-11-23 12:22:45 +0000259 * Returns a {@link TextLinks} that may be applied to the text to annotate it with links
260 * information.
261 *
262 * <p><b>NOTE:</b> Do not implement. The default implementation of this method calls
263 * {@link #generateLinks(CharSequence, TextLinks.Options)}. If that method calls this method,
264 * a stack overflow error will happen.
265 *
266 * @param text the text to generate annotations for
267 *
268 * @throws IllegalArgumentException if text is null
269 *
270 * @see #generateLinks(CharSequence, TextLinks.Options)
271 */
272 @WorkerThread
273 default TextLinks generateLinks(@NonNull CharSequence text) {
274 return generateLinks(text, null);
275 }
276
277 /**
Richard Ledleydb18a572017-11-30 17:33:51 +0000278 * Returns a {@link Collection} of the entity types in the specified preset.
279 *
Jan Althaus13310682018-01-18 10:50:32 +0100280 * @see #ENTITY_PRESET_ALL
281 * @see #ENTITY_PRESET_NONE
Richard Ledleydb18a572017-11-30 17:33:51 +0000282 */
283 default Collection<String> getEntitiesForPreset(@EntityPreset int entityPreset) {
284 return Collections.EMPTY_LIST;
285 }
286
287 /**
Abodunrinwa Toki1d775572017-05-08 16:03:01 +0100288 * Logs a TextClassifier event.
289 *
290 * @param source the text classifier used to generate this event
291 * @param event the text classifier related event
292 * @hide
293 */
294 @WorkerThread
295 default void logEvent(String source, String event) {}
Abodunrinwa Toki0e6b43e2017-09-19 23:18:40 +0100296
297 /**
298 * Returns this TextClassifier's settings.
299 * @hide
300 */
301 default TextClassifierConstants getSettings() {
302 return TextClassifierConstants.DEFAULT;
303 }
Abodunrinwa Toki4d232d62017-11-23 12:22:45 +0000304
Richard Ledleydb18a572017-11-30 17:33:51 +0000305 /**
306 * Configuration object for specifying what entities to identify.
307 *
308 * Configs are initially based on a predefined preset, and can be modified from there.
309 */
Jan Althaus0d9fbb92017-11-28 12:19:33 +0100310 final class EntityConfig implements Parcelable {
Richard Ledleydb18a572017-11-30 17:33:51 +0000311 private final @TextClassifier.EntityPreset int mEntityPreset;
312 private final Collection<String> mExcludedEntityTypes;
313 private final Collection<String> mIncludedEntityTypes;
314
315 public EntityConfig(@TextClassifier.EntityPreset int mEntityPreset) {
316 this.mEntityPreset = mEntityPreset;
317 mExcludedEntityTypes = new ArraySet<>();
318 mIncludedEntityTypes = new ArraySet<>();
319 }
320
321 /**
322 * Specifies an entity to include in addition to any specified by the enity preset.
323 *
324 * Note that if an entity has been excluded, the exclusion will take precedence.
325 */
326 public EntityConfig includeEntities(String... entities) {
327 for (String entity : entities) {
328 mIncludedEntityTypes.add(entity);
329 }
330 return this;
331 }
332
333 /**
334 * Specifies an entity to be excluded.
335 */
336 public EntityConfig excludeEntities(String... entities) {
337 for (String entity : entities) {
338 mExcludedEntityTypes.add(entity);
339 }
340 return this;
341 }
342
343 /**
344 * Returns an unmodifiable list of the final set of entities to find.
345 */
346 public List<String> getEntities(TextClassifier textClassifier) {
347 ArrayList<String> entities = new ArrayList<>();
348 for (String entity : textClassifier.getEntitiesForPreset(mEntityPreset)) {
349 if (!mExcludedEntityTypes.contains(entity)) {
350 entities.add(entity);
351 }
352 }
353 for (String entity : mIncludedEntityTypes) {
354 if (!mExcludedEntityTypes.contains(entity) && !entities.contains(entity)) {
355 entities.add(entity);
356 }
357 }
358 return Collections.unmodifiableList(entities);
359 }
Jan Althaus0d9fbb92017-11-28 12:19:33 +0100360
361 @Override
362 public int describeContents() {
363 return 0;
364 }
365
366 @Override
367 public void writeToParcel(Parcel dest, int flags) {
368 dest.writeInt(mEntityPreset);
369 dest.writeStringList(new ArrayList<>(mExcludedEntityTypes));
370 dest.writeStringList(new ArrayList<>(mIncludedEntityTypes));
371 }
372
373 public static final Parcelable.Creator<EntityConfig> CREATOR =
374 new Parcelable.Creator<EntityConfig>() {
375 @Override
376 public EntityConfig createFromParcel(Parcel in) {
377 return new EntityConfig(in);
378 }
379
380 @Override
381 public EntityConfig[] newArray(int size) {
382 return new EntityConfig[size];
383 }
384 };
385
386 private EntityConfig(Parcel in) {
387 mEntityPreset = in.readInt();
388 mExcludedEntityTypes = new ArraySet<>(in.createStringArrayList());
389 mIncludedEntityTypes = new ArraySet<>(in.createStringArrayList());
390 }
Richard Ledleydb18a572017-11-30 17:33:51 +0000391 }
Abodunrinwa Toki4d232d62017-11-23 12:22:45 +0000392
393 /**
394 * Utility functions for TextClassifier methods.
395 *
396 * <ul>
397 * <li>Provides validation of input parameters to TextClassifier methods
398 * </ul>
399 *
400 * Intended to be used only in this package.
401 * @hide
402 */
403 final class Utils {
404
405 /**
406 * @throws IllegalArgumentException if text is null; startIndex is negative;
407 * endIndex is greater than text.length() or is not greater than startIndex;
408 * options is null
409 */
410 static void validateInput(
411 @NonNull CharSequence text, int startIndex, int endIndex) {
412 Preconditions.checkArgument(text != null);
413 Preconditions.checkArgument(startIndex >= 0);
414 Preconditions.checkArgument(endIndex <= text.length());
415 Preconditions.checkArgument(endIndex > startIndex);
416 }
417
418 /**
419 * @throws IllegalArgumentException if text is null or options is null
420 */
421 static void validateInput(@NonNull CharSequence text) {
422 Preconditions.checkArgument(text != null);
423 }
424 }
Abodunrinwa Tokif001fef2017-01-04 23:51:42 +0000425}