TextSelection.java revision ae82e7ad280e55dca22014c6abc857372229f89c
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 17package android.view.textclassifier; 18 19import android.annotation.FloatRange; 20import android.annotation.IntRange; 21import android.annotation.NonNull; 22import android.annotation.Nullable; 23import android.os.LocaleList; 24import android.os.Parcel; 25import android.os.Parcelable; 26import android.util.ArrayMap; 27import android.view.textclassifier.TextClassifier.EntityType; 28import android.view.textclassifier.TextClassifier.Utils; 29 30import com.android.internal.util.Preconditions; 31 32import java.util.Locale; 33import java.util.Map; 34 35/** 36 * Information about where text selection should be. 37 */ 38public final class TextSelection implements Parcelable { 39 40 private final int mStartIndex; 41 private final int mEndIndex; 42 private final EntityConfidence mEntityConfidence; 43 @Nullable private final String mId; 44 45 private TextSelection( 46 int startIndex, int endIndex, Map<String, Float> entityConfidence, String id) { 47 mStartIndex = startIndex; 48 mEndIndex = endIndex; 49 mEntityConfidence = new EntityConfidence(entityConfidence); 50 mId = id; 51 } 52 53 /** 54 * Returns the start index of the text selection. 55 */ 56 public int getSelectionStartIndex() { 57 return mStartIndex; 58 } 59 60 /** 61 * Returns the end index of the text selection. 62 */ 63 public int getSelectionEndIndex() { 64 return mEndIndex; 65 } 66 67 /** 68 * Returns the number of entities found in the classified text. 69 */ 70 @IntRange(from = 0) 71 public int getEntityCount() { 72 return mEntityConfidence.getEntities().size(); 73 } 74 75 /** 76 * Returns the entity at the specified index. Entities are ordered from high confidence 77 * to low confidence. 78 * 79 * @throws IndexOutOfBoundsException if the specified index is out of range. 80 * @see #getEntityCount() for the number of entities available. 81 */ 82 @NonNull 83 @EntityType 84 public String getEntity(int index) { 85 return mEntityConfidence.getEntities().get(index); 86 } 87 88 /** 89 * Returns the confidence score for the specified entity. The value ranges from 90 * 0 (low confidence) to 1 (high confidence). 0 indicates that the entity was not found for the 91 * classified text. 92 */ 93 @FloatRange(from = 0.0, to = 1.0) 94 public float getConfidenceScore(@EntityType String entity) { 95 return mEntityConfidence.getConfidenceScore(entity); 96 } 97 98 /** 99 * Returns the id, if one exists, for this object. 100 */ 101 @Nullable 102 public String getId() { 103 return mId; 104 } 105 106 @Override 107 public String toString() { 108 return String.format( 109 Locale.US, 110 "TextSelection {id=%s, startIndex=%d, endIndex=%d, entities=%s}", 111 mId, mStartIndex, mEndIndex, mEntityConfidence); 112 } 113 114 /** 115 * Builder used to build {@link TextSelection} objects. 116 */ 117 public static final class Builder { 118 119 private final int mStartIndex; 120 private final int mEndIndex; 121 private final Map<String, Float> mEntityConfidence = new ArrayMap<>(); 122 @Nullable private String mId; 123 124 /** 125 * Creates a builder used to build {@link TextSelection} objects. 126 * 127 * @param startIndex the start index of the text selection. 128 * @param endIndex the end index of the text selection. Must be greater than startIndex 129 */ 130 public Builder(@IntRange(from = 0) int startIndex, @IntRange(from = 0) int endIndex) { 131 Preconditions.checkArgument(startIndex >= 0); 132 Preconditions.checkArgument(endIndex > startIndex); 133 mStartIndex = startIndex; 134 mEndIndex = endIndex; 135 } 136 137 /** 138 * Sets an entity type for the classified text and assigns a confidence score. 139 * 140 * @param confidenceScore a value from 0 (low confidence) to 1 (high confidence). 141 * 0 implies the entity does not exist for the classified text. 142 * Values greater than 1 are clamped to 1. 143 */ 144 @NonNull 145 public Builder setEntityType( 146 @NonNull @EntityType String type, 147 @FloatRange(from = 0.0, to = 1.0) float confidenceScore) { 148 Preconditions.checkNotNull(type); 149 mEntityConfidence.put(type, confidenceScore); 150 return this; 151 } 152 153 /** 154 * Sets an id for the TextSelection object. 155 */ 156 @NonNull 157 public Builder setId(@NonNull String id) { 158 mId = Preconditions.checkNotNull(id); 159 return this; 160 } 161 162 /** 163 * Builds and returns {@link TextSelection} object. 164 */ 165 @NonNull 166 public TextSelection build() { 167 return new TextSelection( 168 mStartIndex, mEndIndex, mEntityConfidence, mId); 169 } 170 } 171 172 /** 173 * A request object for generating TextSelection. 174 */ 175 public static final class Request implements Parcelable { 176 177 private final CharSequence mText; 178 private final int mStartIndex; 179 private final int mEndIndex; 180 @Nullable private final LocaleList mDefaultLocales; 181 private final boolean mDarkLaunchAllowed; 182 183 private Request( 184 CharSequence text, 185 int startIndex, 186 int endIndex, 187 LocaleList defaultLocales, 188 boolean darkLaunchAllowed) { 189 mText = text; 190 mStartIndex = startIndex; 191 mEndIndex = endIndex; 192 mDefaultLocales = defaultLocales; 193 mDarkLaunchAllowed = darkLaunchAllowed; 194 } 195 196 /** 197 * Returns the text providing context for the selected text (which is specified by the 198 * sub sequence starting at startIndex and ending at endIndex). 199 */ 200 @NonNull 201 public CharSequence getText() { 202 return mText; 203 } 204 205 /** 206 * Returns start index of the selected part of text. 207 */ 208 @IntRange(from = 0) 209 public int getStartIndex() { 210 return mStartIndex; 211 } 212 213 /** 214 * Returns end index of the selected part of text. 215 */ 216 @IntRange(from = 0) 217 public int getEndIndex() { 218 return mEndIndex; 219 } 220 221 /** 222 * Returns true if the TextClassifier should return selection suggestions when "dark 223 * launched". Otherwise, returns false. 224 * 225 * @hide 226 */ 227 public boolean isDarkLaunchAllowed() { 228 return mDarkLaunchAllowed; 229 } 230 231 /** 232 * @return ordered list of locale preferences that can be used to disambiguate the 233 * provided text. 234 */ 235 @Nullable 236 public LocaleList getDefaultLocales() { 237 return mDefaultLocales; 238 } 239 240 /** 241 * A builder for building TextSelection requests. 242 */ 243 public static final class Builder { 244 245 private final CharSequence mText; 246 private final int mStartIndex; 247 private final int mEndIndex; 248 249 @Nullable private LocaleList mDefaultLocales; 250 private boolean mDarkLaunchAllowed; 251 252 /** 253 * @param text text providing context for the selected text (which is specified by the 254 * sub sequence starting at selectionStartIndex and ending at selectionEndIndex) 255 * @param startIndex start index of the selected part of text 256 * @param endIndex end index of the selected part of text 257 */ 258 public Builder( 259 @NonNull CharSequence text, 260 @IntRange(from = 0) int startIndex, 261 @IntRange(from = 0) int endIndex) { 262 Utils.checkArgument(text, startIndex, endIndex); 263 mText = text; 264 mStartIndex = startIndex; 265 mEndIndex = endIndex; 266 } 267 268 /** 269 * @param defaultLocales ordered list of locale preferences that may be used to 270 * disambiguate the provided text. If no locale preferences exist, set this to null 271 * or an empty locale list. 272 * 273 * @return this builder. 274 */ 275 @NonNull 276 public Builder setDefaultLocales(@Nullable LocaleList defaultLocales) { 277 mDefaultLocales = defaultLocales; 278 return this; 279 } 280 281 /** 282 * @param allowed whether or not the TextClassifier should return selection suggestions 283 * when "dark launched". When a TextClassifier is dark launched, it can suggest 284 * selection changes that should not be used to actually change the user's 285 * selection. Instead, the suggested selection is logged, compared with the user's 286 * selection interaction, and used to generate quality metrics for the 287 * TextClassifier. Not parceled. 288 * 289 * @return this builder. 290 * @hide 291 */ 292 @NonNull 293 public Builder setDarkLaunchAllowed(boolean allowed) { 294 mDarkLaunchAllowed = allowed; 295 return this; 296 } 297 298 /** 299 * Builds and returns the request object. 300 */ 301 @NonNull 302 public Request build() { 303 return new Request(mText, mStartIndex, mEndIndex, 304 mDefaultLocales, mDarkLaunchAllowed); 305 } 306 } 307 308 @Override 309 public int describeContents() { 310 return 0; 311 } 312 313 @Override 314 public void writeToParcel(Parcel dest, int flags) { 315 dest.writeString(mText.toString()); 316 dest.writeInt(mStartIndex); 317 dest.writeInt(mEndIndex); 318 dest.writeInt(mDefaultLocales != null ? 1 : 0); 319 if (mDefaultLocales != null) { 320 mDefaultLocales.writeToParcel(dest, flags); 321 } 322 } 323 324 public static final Parcelable.Creator<Request> CREATOR = 325 new Parcelable.Creator<Request>() { 326 @Override 327 public Request createFromParcel(Parcel in) { 328 return new Request(in); 329 } 330 331 @Override 332 public Request[] newArray(int size) { 333 return new Request[size]; 334 } 335 }; 336 337 private Request(Parcel in) { 338 mText = in.readString(); 339 mStartIndex = in.readInt(); 340 mEndIndex = in.readInt(); 341 mDefaultLocales = in.readInt() == 0 ? null : LocaleList.CREATOR.createFromParcel(in); 342 mDarkLaunchAllowed = false; 343 } 344 } 345 346 @Override 347 public int describeContents() { 348 return 0; 349 } 350 351 @Override 352 public void writeToParcel(Parcel dest, int flags) { 353 dest.writeInt(mStartIndex); 354 dest.writeInt(mEndIndex); 355 mEntityConfidence.writeToParcel(dest, flags); 356 dest.writeString(mId); 357 } 358 359 public static final Parcelable.Creator<TextSelection> CREATOR = 360 new Parcelable.Creator<TextSelection>() { 361 @Override 362 public TextSelection createFromParcel(Parcel in) { 363 return new TextSelection(in); 364 } 365 366 @Override 367 public TextSelection[] newArray(int size) { 368 return new TextSelection[size]; 369 } 370 }; 371 372 private TextSelection(Parcel in) { 373 mStartIndex = in.readInt(); 374 mEndIndex = in.readInt(); 375 mEntityConfidence = EntityConfidence.CREATOR.createFromParcel(in); 376 mId = in.readString(); 377 } 378 379 380 // TODO: Remove once apps can build against the latest sdk. 381 /** 382 * Optional input parameters for generating TextSelection. 383 * @hide 384 */ 385 public static final class Options { 386 387 @Nullable private final TextClassificationSessionId mSessionId; 388 @Nullable private final Request mRequest; 389 @Nullable private LocaleList mDefaultLocales; 390 private boolean mDarkLaunchAllowed; 391 392 public Options() { 393 this(null, null); 394 } 395 396 private Options( 397 @Nullable TextClassificationSessionId sessionId, @Nullable Request request) { 398 mSessionId = sessionId; 399 mRequest = request; 400 } 401 402 /** Helper to create Options from a Request. */ 403 public static Options from(TextClassificationSessionId sessionId, Request request) { 404 final Options options = new Options(sessionId, request); 405 options.setDefaultLocales(request.getDefaultLocales()); 406 return options; 407 } 408 409 /** @param defaultLocales ordered list of locale preferences. */ 410 public Options setDefaultLocales(@Nullable LocaleList defaultLocales) { 411 mDefaultLocales = defaultLocales; 412 return this; 413 } 414 415 @Nullable 416 public LocaleList getDefaultLocales() { 417 return mDefaultLocales; 418 } 419 420 @Nullable 421 public Request getRequest() { 422 return mRequest; 423 } 424 425 @Nullable 426 public TextClassificationSessionId getSessionId() { 427 return mSessionId; 428 } 429 } 430} 431