blob: 4a6f3e53b223b515111fc40cf1130e76aef1f153 [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
19import android.annotation.FloatRange;
20import android.annotation.IntRange;
21import android.annotation.NonNull;
Abodunrinwa Toki2b6020f2017-10-28 02:28:45 +010022import android.annotation.Nullable;
Tony Mak916bb9e2018-11-08 20:45:20 +000023import android.os.Bundle;
Abodunrinwa Toki2b6020f2017-10-28 02:28:45 +010024import android.os.LocaleList;
Jan Althaus0d9fbb92017-11-28 12:19:33 +010025import android.os.Parcel;
26import android.os.Parcelable;
Abodunrinwa Toki0f138962018-12-03 22:35:10 +000027import android.text.SpannedString;
Jan Althausbbe43df2017-11-30 15:01:40 +010028import android.util.ArrayMap;
Abodunrinwa Tokif001fef2017-01-04 23:51:42 +000029import android.view.textclassifier.TextClassifier.EntityType;
Abodunrinwa Toki080c8542018-03-27 00:04:06 +010030import android.view.textclassifier.TextClassifier.Utils;
Abodunrinwa Tokif001fef2017-01-04 23:51:42 +000031
Abodunrinwa Toki0f138962018-12-03 22:35:10 +000032import com.android.internal.annotations.VisibleForTesting;
Abodunrinwa Tokif001fef2017-01-04 23:51:42 +000033import com.android.internal.util.Preconditions;
34
Abodunrinwa Toki4d232d62017-11-23 12:22:45 +000035import java.util.Locale;
Jan Althausbbe43df2017-11-30 15:01:40 +010036import java.util.Map;
Abodunrinwa Tokif001fef2017-01-04 23:51:42 +000037
38/**
39 * Information about where text selection should be.
40 */
Abodunrinwa Tokid32906c2018-01-18 04:34:44 -080041public final class TextSelection implements Parcelable {
Abodunrinwa Tokif001fef2017-01-04 23:51:42 +000042
43 private final int mStartIndex;
44 private final int mEndIndex;
Abodunrinwa Toki080c8542018-03-27 00:04:06 +010045 private final EntityConfidence mEntityConfidence;
46 @Nullable private final String mId;
Tony Mak916bb9e2018-11-08 20:45:20 +000047 private final Bundle mExtras;
Abodunrinwa Tokif001fef2017-01-04 23:51:42 +000048
49 private TextSelection(
Tony Mak916bb9e2018-11-08 20:45:20 +000050 int startIndex, int endIndex, Map<String, Float> entityConfidence, String id,
51 Bundle extras) {
Abodunrinwa Tokif001fef2017-01-04 23:51:42 +000052 mStartIndex = startIndex;
53 mEndIndex = endIndex;
Jan Althaus0d9fbb92017-11-28 12:19:33 +010054 mEntityConfidence = new EntityConfidence(entityConfidence);
Abodunrinwa Toki080c8542018-03-27 00:04:06 +010055 mId = id;
Tony Mak916bb9e2018-11-08 20:45:20 +000056 mExtras = extras;
Abodunrinwa Tokif001fef2017-01-04 23:51:42 +000057 }
58
59 /**
60 * Returns the start index of the text selection.
61 */
62 public int getSelectionStartIndex() {
63 return mStartIndex;
64 }
65
66 /**
67 * Returns the end index of the text selection.
68 */
69 public int getSelectionEndIndex() {
70 return mEndIndex;
71 }
72
73 /**
74 * Returns the number of entities found in the classified text.
75 */
76 @IntRange(from = 0)
77 public int getEntityCount() {
Jan Althausbbe43df2017-11-30 15:01:40 +010078 return mEntityConfidence.getEntities().size();
Abodunrinwa Tokif001fef2017-01-04 23:51:42 +000079 }
80
81 /**
82 * Returns the entity at the specified index. Entities are ordered from high confidence
83 * to low confidence.
84 *
85 * @throws IndexOutOfBoundsException if the specified index is out of range.
86 * @see #getEntityCount() for the number of entities available.
87 */
88 @NonNull
Abodunrinwa Toki080c8542018-03-27 00:04:06 +010089 @EntityType
90 public String getEntity(int index) {
Jan Althausbbe43df2017-11-30 15:01:40 +010091 return mEntityConfidence.getEntities().get(index);
Abodunrinwa Tokif001fef2017-01-04 23:51:42 +000092 }
93
94 /**
95 * Returns the confidence score for the specified entity. The value ranges from
96 * 0 (low confidence) to 1 (high confidence). 0 indicates that the entity was not found for the
97 * classified text.
98 */
99 @FloatRange(from = 0.0, to = 1.0)
100 public float getConfidenceScore(@EntityType String entity) {
101 return mEntityConfidence.getConfidenceScore(entity);
102 }
103
Abodunrinwa Toki1d775572017-05-08 16:03:01 +0100104 /**
Abodunrinwa Toki080c8542018-03-27 00:04:06 +0100105 * Returns the id, if one exists, for this object.
Abodunrinwa Toki1d775572017-05-08 16:03:01 +0100106 */
Abodunrinwa Toki080c8542018-03-27 00:04:06 +0100107 @Nullable
108 public String getId() {
109 return mId;
Abodunrinwa Toki692b1962017-08-15 15:05:11 +0100110 }
111
Tony Mak916bb9e2018-11-08 20:45:20 +0000112 /**
113 * Returns the extended data.
114 *
115 * <p><b>NOTE: </b>Each call to this method returns a new bundle copy so clients should
116 * prefer to hold a reference to the returned bundle rather than frequently calling this
117 * method.
118 */
119 @NonNull
120 public Bundle getExtras() {
121 return mExtras.deepCopy();
122 }
123
Abodunrinwa Tokif001fef2017-01-04 23:51:42 +0000124 @Override
125 public String toString() {
Abodunrinwa Toki008f3872017-11-27 19:32:35 +0000126 return String.format(
127 Locale.US,
Abodunrinwa Toki080c8542018-03-27 00:04:06 +0100128 "TextSelection {id=%s, startIndex=%d, endIndex=%d, entities=%s}",
129 mId, mStartIndex, mEndIndex, mEntityConfidence);
Abodunrinwa Tokif001fef2017-01-04 23:51:42 +0000130 }
131
132 /**
133 * Builder used to build {@link TextSelection} objects.
134 */
135 public static final class Builder {
136
137 private final int mStartIndex;
138 private final int mEndIndex;
Abodunrinwa Toki080c8542018-03-27 00:04:06 +0100139 private final Map<String, Float> mEntityConfidence = new ArrayMap<>();
140 @Nullable private String mId;
Tony Mak916bb9e2018-11-08 20:45:20 +0000141 @Nullable
142 private Bundle mExtras;
Abodunrinwa Tokif001fef2017-01-04 23:51:42 +0000143
144 /**
145 * Creates a builder used to build {@link TextSelection} objects.
146 *
147 * @param startIndex the start index of the text selection.
148 * @param endIndex the end index of the text selection. Must be greater than startIndex
149 */
150 public Builder(@IntRange(from = 0) int startIndex, @IntRange(from = 0) int endIndex) {
151 Preconditions.checkArgument(startIndex >= 0);
152 Preconditions.checkArgument(endIndex > startIndex);
153 mStartIndex = startIndex;
154 mEndIndex = endIndex;
155 }
156
157 /**
158 * Sets an entity type for the classified text and assigns a confidence score.
159 *
160 * @param confidenceScore a value from 0 (low confidence) to 1 (high confidence).
161 * 0 implies the entity does not exist for the classified text.
162 * Values greater than 1 are clamped to 1.
163 */
Abodunrinwa Toki080c8542018-03-27 00:04:06 +0100164 @NonNull
Abodunrinwa Tokif001fef2017-01-04 23:51:42 +0000165 public Builder setEntityType(
166 @NonNull @EntityType String type,
167 @FloatRange(from = 0.0, to = 1.0) float confidenceScore) {
Abodunrinwa Toki080c8542018-03-27 00:04:06 +0100168 Preconditions.checkNotNull(type);
Jan Althausbbe43df2017-11-30 15:01:40 +0100169 mEntityConfidence.put(type, confidenceScore);
Abodunrinwa Tokif001fef2017-01-04 23:51:42 +0000170 return this;
171 }
172
173 /**
Abodunrinwa Toki080c8542018-03-27 00:04:06 +0100174 * Sets an id for the TextSelection object.
Abodunrinwa Toki1d775572017-05-08 16:03:01 +0100175 */
Abodunrinwa Toki080c8542018-03-27 00:04:06 +0100176 @NonNull
Tony Mak84368782018-05-15 16:43:44 +0800177 public Builder setId(@Nullable String id) {
178 mId = id;
Abodunrinwa Toki692b1962017-08-15 15:05:11 +0100179 return this;
180 }
181
182 /**
Tony Mak916bb9e2018-11-08 20:45:20 +0000183 * Sets the extended data.
184 *
185 * @return this builder
186 */
187 public Builder setExtras(@Nullable Bundle extras) {
188 mExtras = extras;
189 return this;
190 }
191
192 /**
Abodunrinwa Tokif001fef2017-01-04 23:51:42 +0000193 * Builds and returns {@link TextSelection} object.
194 */
Abodunrinwa Toki080c8542018-03-27 00:04:06 +0100195 @NonNull
Abodunrinwa Tokif001fef2017-01-04 23:51:42 +0000196 public TextSelection build() {
Abodunrinwa Toki692b1962017-08-15 15:05:11 +0100197 return new TextSelection(
Tony Mak916bb9e2018-11-08 20:45:20 +0000198 mStartIndex, mEndIndex, mEntityConfidence, mId,
199 mExtras == null ? Bundle.EMPTY : mExtras.deepCopy());
Abodunrinwa Tokif001fef2017-01-04 23:51:42 +0000200 }
201 }
Abodunrinwa Toki2b6020f2017-10-28 02:28:45 +0100202
203 /**
Abodunrinwa Toki080c8542018-03-27 00:04:06 +0100204 * A request object for generating TextSelection.
Abodunrinwa Toki2b6020f2017-10-28 02:28:45 +0100205 */
Abodunrinwa Toki080c8542018-03-27 00:04:06 +0100206 public static final class Request implements Parcelable {
Abodunrinwa Toki2b6020f2017-10-28 02:28:45 +0100207
Abodunrinwa Toki080c8542018-03-27 00:04:06 +0100208 private final CharSequence mText;
209 private final int mStartIndex;
210 private final int mEndIndex;
211 @Nullable private final LocaleList mDefaultLocales;
212 private final boolean mDarkLaunchAllowed;
Tony Mak916bb9e2018-11-08 20:45:20 +0000213 private final Bundle mExtras;
Abodunrinwa Toki0f138962018-12-03 22:35:10 +0000214 @Nullable private String mCallingPackageName;
Abodunrinwa Toki2b6020f2017-10-28 02:28:45 +0100215
Abodunrinwa Toki080c8542018-03-27 00:04:06 +0100216 private Request(
217 CharSequence text,
218 int startIndex,
219 int endIndex,
220 LocaleList defaultLocales,
Tony Mak916bb9e2018-11-08 20:45:20 +0000221 boolean darkLaunchAllowed,
222 Bundle extras) {
Abodunrinwa Toki080c8542018-03-27 00:04:06 +0100223 mText = text;
224 mStartIndex = startIndex;
225 mEndIndex = endIndex;
Abodunrinwa Toki2b6020f2017-10-28 02:28:45 +0100226 mDefaultLocales = defaultLocales;
Abodunrinwa Toki080c8542018-03-27 00:04:06 +0100227 mDarkLaunchAllowed = darkLaunchAllowed;
Tony Mak916bb9e2018-11-08 20:45:20 +0000228 mExtras = extras;
Abodunrinwa Toki2b6020f2017-10-28 02:28:45 +0100229 }
230
231 /**
Abodunrinwa Toki080c8542018-03-27 00:04:06 +0100232 * Returns the text providing context for the selected text (which is specified by the
233 * sub sequence starting at startIndex and ending at endIndex).
234 */
235 @NonNull
236 public CharSequence getText() {
237 return mText;
238 }
239
240 /**
241 * Returns start index of the selected part of text.
242 */
243 @IntRange(from = 0)
244 public int getStartIndex() {
245 return mStartIndex;
246 }
247
248 /**
249 * Returns end index of the selected part of text.
250 */
251 @IntRange(from = 0)
252 public int getEndIndex() {
253 return mEndIndex;
254 }
255
256 /**
257 * Returns true if the TextClassifier should return selection suggestions when "dark
258 * launched". Otherwise, returns false.
259 *
260 * @hide
261 */
262 public boolean isDarkLaunchAllowed() {
263 return mDarkLaunchAllowed;
264 }
265
266 /**
267 * @return ordered list of locale preferences that can be used to disambiguate the
268 * provided text.
Abodunrinwa Toki2b6020f2017-10-28 02:28:45 +0100269 */
270 @Nullable
271 public LocaleList getDefaultLocales() {
272 return mDefaultLocales;
273 }
274
275 /**
Abodunrinwa Toki0f138962018-12-03 22:35:10 +0000276 * Sets the name of the package that is sending this request.
277 * <p>
278 * Package-private for SystemTextClassifier's use.
279 * @hide
280 */
281 @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
282 public void setCallingPackageName(@Nullable String callingPackageName) {
283 mCallingPackageName = callingPackageName;
284 }
285
286 /**
287 * Returns the name of the package that sent this request.
288 * This returns {@code null} if no calling package name is set.
289 */
290 @Nullable
291 public String getCallingPackageName() {
292 return mCallingPackageName;
293 }
294
295 /**
Tony Mak916bb9e2018-11-08 20:45:20 +0000296 * Returns the extended data.
297 *
298 * <p><b>NOTE: </b>Each call to this method returns a new bundle copy so clients should
299 * prefer to hold a reference to the returned bundle rather than frequently calling this
300 * method.
301 */
302 @NonNull
303 public Bundle getExtras() {
304 return mExtras.deepCopy();
305 }
306
307 /**
Abodunrinwa Toki080c8542018-03-27 00:04:06 +0100308 * A builder for building TextSelection requests.
Abodunrinwa Toki2b6020f2017-10-28 02:28:45 +0100309 */
Abodunrinwa Toki080c8542018-03-27 00:04:06 +0100310 public static final class Builder {
Abodunrinwa Toki2b6020f2017-10-28 02:28:45 +0100311
Abodunrinwa Toki080c8542018-03-27 00:04:06 +0100312 private final CharSequence mText;
313 private final int mStartIndex;
314 private final int mEndIndex;
315
316 @Nullable private LocaleList mDefaultLocales;
317 private boolean mDarkLaunchAllowed;
Tony Mak916bb9e2018-11-08 20:45:20 +0000318 private Bundle mExtras;
Abodunrinwa Toki080c8542018-03-27 00:04:06 +0100319
320 /**
321 * @param text text providing context for the selected text (which is specified by the
322 * sub sequence starting at selectionStartIndex and ending at selectionEndIndex)
323 * @param startIndex start index of the selected part of text
324 * @param endIndex end index of the selected part of text
325 */
326 public Builder(
327 @NonNull CharSequence text,
328 @IntRange(from = 0) int startIndex,
329 @IntRange(from = 0) int endIndex) {
330 Utils.checkArgument(text, startIndex, endIndex);
331 mText = text;
332 mStartIndex = startIndex;
333 mEndIndex = endIndex;
334 }
335
336 /**
337 * @param defaultLocales ordered list of locale preferences that may be used to
338 * disambiguate the provided text. If no locale preferences exist, set this to null
339 * or an empty locale list.
340 *
341 * @return this builder.
342 */
343 @NonNull
344 public Builder setDefaultLocales(@Nullable LocaleList defaultLocales) {
345 mDefaultLocales = defaultLocales;
346 return this;
347 }
348
349 /**
350 * @param allowed whether or not the TextClassifier should return selection suggestions
351 * when "dark launched". When a TextClassifier is dark launched, it can suggest
352 * selection changes that should not be used to actually change the user's
353 * selection. Instead, the suggested selection is logged, compared with the user's
354 * selection interaction, and used to generate quality metrics for the
355 * TextClassifier. Not parceled.
356 *
357 * @return this builder.
358 * @hide
359 */
360 @NonNull
361 public Builder setDarkLaunchAllowed(boolean allowed) {
362 mDarkLaunchAllowed = allowed;
363 return this;
364 }
365
366 /**
Tony Mak916bb9e2018-11-08 20:45:20 +0000367 * Sets the extended data.
368 *
369 * @return this builder
370 */
371 public Builder setExtras(@Nullable Bundle extras) {
372 mExtras = extras;
373 return this;
374 }
375
376 /**
Abodunrinwa Toki080c8542018-03-27 00:04:06 +0100377 * Builds and returns the request object.
378 */
379 @NonNull
380 public Request build() {
Abodunrinwa Toki0f138962018-12-03 22:35:10 +0000381 return new Request(new SpannedString(mText), mStartIndex, mEndIndex,
Tony Mak916bb9e2018-11-08 20:45:20 +0000382 mDefaultLocales, mDarkLaunchAllowed,
383 mExtras == null ? Bundle.EMPTY : mExtras.deepCopy());
Abodunrinwa Toki080c8542018-03-27 00:04:06 +0100384 }
Abodunrinwa Toki2b6020f2017-10-28 02:28:45 +0100385 }
Jan Althaus0d9fbb92017-11-28 12:19:33 +0100386
387 @Override
388 public int describeContents() {
389 return 0;
390 }
391
392 @Override
393 public void writeToParcel(Parcel dest, int flags) {
Abodunrinwa Toki0f138962018-12-03 22:35:10 +0000394 dest.writeCharSequence(mText);
Abodunrinwa Toki080c8542018-03-27 00:04:06 +0100395 dest.writeInt(mStartIndex);
396 dest.writeInt(mEndIndex);
Abodunrinwa Toki0f138962018-12-03 22:35:10 +0000397 dest.writeParcelable(mDefaultLocales, flags);
398 dest.writeString(mCallingPackageName);
Tony Mak916bb9e2018-11-08 20:45:20 +0000399 dest.writeBundle(mExtras);
Jan Althaus0d9fbb92017-11-28 12:19:33 +0100400 }
401
Abodunrinwa Toki0f138962018-12-03 22:35:10 +0000402 private static Request readFromParcel(Parcel in) {
403 final CharSequence text = in.readCharSequence();
404 final int startIndex = in.readInt();
405 final int endIndex = in.readInt();
406 final LocaleList defaultLocales = in.readParcelable(null);
407 final String callingPackageName = in.readString();
408 final Bundle extras = in.readBundle();
409
410 final Request request = new Request(text, startIndex, endIndex, defaultLocales,
411 /* darkLaunchAllowed= */ false, extras);
412 request.setCallingPackageName(callingPackageName);
413 return request;
414 }
415
Abodunrinwa Toki080c8542018-03-27 00:04:06 +0100416 public static final Parcelable.Creator<Request> CREATOR =
417 new Parcelable.Creator<Request>() {
Jan Althaus0d9fbb92017-11-28 12:19:33 +0100418 @Override
Abodunrinwa Toki080c8542018-03-27 00:04:06 +0100419 public Request createFromParcel(Parcel in) {
Abodunrinwa Toki0f138962018-12-03 22:35:10 +0000420 return readFromParcel(in);
Jan Althaus0d9fbb92017-11-28 12:19:33 +0100421 }
422
423 @Override
Abodunrinwa Toki080c8542018-03-27 00:04:06 +0100424 public Request[] newArray(int size) {
425 return new Request[size];
Jan Althaus0d9fbb92017-11-28 12:19:33 +0100426 }
427 };
Jan Althaus0d9fbb92017-11-28 12:19:33 +0100428 }
429
Abodunrinwa Tokid32906c2018-01-18 04:34:44 -0800430 @Override
431 public int describeContents() {
432 return 0;
433 }
Jan Althaus0d9fbb92017-11-28 12:19:33 +0100434
Abodunrinwa Tokid32906c2018-01-18 04:34:44 -0800435 @Override
436 public void writeToParcel(Parcel dest, int flags) {
437 dest.writeInt(mStartIndex);
438 dest.writeInt(mEndIndex);
439 mEntityConfidence.writeToParcel(dest, flags);
Abodunrinwa Toki080c8542018-03-27 00:04:06 +0100440 dest.writeString(mId);
Tony Mak916bb9e2018-11-08 20:45:20 +0000441 dest.writeBundle(mExtras);
Abodunrinwa Tokid32906c2018-01-18 04:34:44 -0800442 }
Jan Althaus0d9fbb92017-11-28 12:19:33 +0100443
Abodunrinwa Tokid32906c2018-01-18 04:34:44 -0800444 public static final Parcelable.Creator<TextSelection> CREATOR =
445 new Parcelable.Creator<TextSelection>() {
446 @Override
447 public TextSelection createFromParcel(Parcel in) {
448 return new TextSelection(in);
449 }
Jan Althaus0d9fbb92017-11-28 12:19:33 +0100450
Abodunrinwa Tokid32906c2018-01-18 04:34:44 -0800451 @Override
452 public TextSelection[] newArray(int size) {
453 return new TextSelection[size];
454 }
455 };
Jan Althaus0d9fbb92017-11-28 12:19:33 +0100456
Abodunrinwa Tokid32906c2018-01-18 04:34:44 -0800457 private TextSelection(Parcel in) {
458 mStartIndex = in.readInt();
459 mEndIndex = in.readInt();
460 mEntityConfidence = EntityConfidence.CREATOR.createFromParcel(in);
Abodunrinwa Toki080c8542018-03-27 00:04:06 +0100461 mId = in.readString();
Tony Mak916bb9e2018-11-08 20:45:20 +0000462 mExtras = in.readBundle();
Abodunrinwa Toki2b6020f2017-10-28 02:28:45 +0100463 }
Abodunrinwa Tokif001fef2017-01-04 23:51:42 +0000464}