1 /* 2 * Copyright (C) 2018 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.FloatRange; 20 import android.annotation.IntRange; 21 import android.annotation.NonNull; 22 import android.annotation.Nullable; 23 import android.icu.util.ULocale; 24 import android.os.Bundle; 25 import android.os.Parcel; 26 import android.os.Parcelable; 27 import android.util.ArrayMap; 28 29 import com.android.internal.annotations.VisibleForTesting; 30 31 import java.util.Locale; 32 import java.util.Map; 33 import java.util.Objects; 34 35 /** 36 * Represents the result of language detection of a piece of text. 37 * <p> 38 * This contains a list of locales, each paired with a confidence score, sorted in decreasing 39 * order of those scores. E.g., for a given input text, the model may return 40 * {@code [<"en", 0.85>, <"fr", 0.15>]}. This sample result means the model reports that it is 41 * 85% likely that the entire text is in English and 15% likely that the entire text is in French, 42 * etc. It does not mean that 85% of the input is in English and 15% is in French. 43 */ 44 public final class TextLanguage implements Parcelable { 45 46 public static final @android.annotation.NonNull Creator<TextLanguage> CREATOR = new Creator<TextLanguage>() { 47 @Override 48 public TextLanguage createFromParcel(Parcel in) { 49 return readFromParcel(in); 50 } 51 52 @Override 53 public TextLanguage[] newArray(int size) { 54 return new TextLanguage[size]; 55 } 56 }; 57 58 static final TextLanguage EMPTY = new Builder().build(); 59 60 @Nullable private final String mId; 61 private final EntityConfidence mEntityConfidence; 62 private final Bundle mBundle; 63 TextLanguage( @ullable String id, EntityConfidence entityConfidence, Bundle bundle)64 private TextLanguage( 65 @Nullable String id, 66 EntityConfidence entityConfidence, 67 Bundle bundle) { 68 mId = id; 69 mEntityConfidence = entityConfidence; 70 mBundle = bundle; 71 } 72 73 /** 74 * Returns the id, if one exists, for this object. 75 */ 76 @Nullable getId()77 public String getId() { 78 return mId; 79 } 80 81 /** 82 * Returns the number of possible locales for the processed text. 83 */ 84 @IntRange(from = 0) getLocaleHypothesisCount()85 public int getLocaleHypothesisCount() { 86 return mEntityConfidence.getEntities().size(); 87 } 88 89 /** 90 * Returns the language locale at the specified index. Locales are ordered from high 91 * confidence to low confidence. 92 * <p> 93 * See {@link #getLocaleHypothesisCount()} for the number of locales available. 94 * 95 * @throws IndexOutOfBoundsException if the specified index is out of range. 96 */ 97 @NonNull getLocale(int index)98 public ULocale getLocale(int index) { 99 return ULocale.forLanguageTag(mEntityConfidence.getEntities().get(index)); 100 } 101 102 /** 103 * Returns the confidence score for the specified language locale. The value ranges from 104 * 0 (low confidence) to 1 (high confidence). 0 indicates that the locale was not found for 105 * the processed text. 106 */ 107 @FloatRange(from = 0.0, to = 1.0) getConfidenceScore(@onNull ULocale locale)108 public float getConfidenceScore(@NonNull ULocale locale) { 109 return mEntityConfidence.getConfidenceScore(locale.toLanguageTag()); 110 } 111 112 /** 113 * Returns a bundle containing non-structured extra information about this result. What is 114 * returned in the extras is specific to the {@link TextClassifier} implementation. 115 * 116 * <p><b>NOTE: </b>Do not modify this bundle. 117 */ 118 @NonNull getExtras()119 public Bundle getExtras() { 120 return mBundle; 121 } 122 123 @Override toString()124 public String toString() { 125 return String.format( 126 Locale.US, 127 "TextLanguage {id=%s, locales=%s, bundle=%s}", 128 mId, mEntityConfidence, mBundle); 129 } 130 131 @Override describeContents()132 public int describeContents() { 133 return 0; 134 } 135 136 @Override writeToParcel(Parcel dest, int flags)137 public void writeToParcel(Parcel dest, int flags) { 138 dest.writeString(mId); 139 mEntityConfidence.writeToParcel(dest, flags); 140 dest.writeBundle(mBundle); 141 } 142 readFromParcel(Parcel in)143 private static TextLanguage readFromParcel(Parcel in) { 144 return new TextLanguage( 145 in.readString(), 146 EntityConfidence.CREATOR.createFromParcel(in), 147 in.readBundle()); 148 } 149 150 /** 151 * Builder used to build TextLanguage objects. 152 */ 153 public static final class Builder { 154 155 @Nullable private String mId; 156 private final Map<String, Float> mEntityConfidenceMap = new ArrayMap<>(); 157 @Nullable private Bundle mBundle; 158 159 /** 160 * Sets a language locale for the processed text and assigns a confidence score. If the 161 * locale has already been set, this updates it. 162 * 163 * @param confidenceScore a value from 0 (low confidence) to 1 (high confidence). 164 * 0 implies the locale does not exist for the processed text. 165 * Values greater than 1 are clamped to 1. 166 */ 167 @NonNull putLocale( @onNull ULocale locale, @FloatRange(from = 0.0, to = 1.0) float confidenceScore)168 public Builder putLocale( 169 @NonNull ULocale locale, 170 @FloatRange(from = 0.0, to = 1.0) float confidenceScore) { 171 Objects.requireNonNull(locale); 172 mEntityConfidenceMap.put(locale.toLanguageTag(), confidenceScore); 173 return this; 174 } 175 176 /** 177 * Sets an optional id for the TextLanguage object. 178 */ 179 @NonNull setId(@ullable String id)180 public Builder setId(@Nullable String id) { 181 mId = id; 182 return this; 183 } 184 185 /** 186 * Sets a bundle containing non-structured extra information about the TextLanguage object. 187 */ 188 @NonNull setExtras(@onNull Bundle bundle)189 public Builder setExtras(@NonNull Bundle bundle) { 190 mBundle = Objects.requireNonNull(bundle); 191 return this; 192 } 193 194 /** 195 * Builds and returns a new TextLanguage object. 196 * <p> 197 * If necessary, this method will verify fields, clamp them, and make them immutable. 198 */ 199 @NonNull build()200 public TextLanguage build() { 201 mBundle = mBundle == null ? Bundle.EMPTY : mBundle; 202 return new TextLanguage( 203 mId, 204 new EntityConfidence(mEntityConfidenceMap), 205 mBundle); 206 } 207 } 208 209 /** 210 * A request object for detecting the language of a piece of text. 211 */ 212 public static final class Request implements Parcelable { 213 214 public static final @android.annotation.NonNull Creator<Request> CREATOR = new Creator<Request>() { 215 @Override 216 public Request createFromParcel(Parcel in) { 217 return readFromParcel(in); 218 } 219 220 @Override 221 public Request[] newArray(int size) { 222 return new Request[size]; 223 } 224 }; 225 226 private final CharSequence mText; 227 private final Bundle mExtra; 228 @Nullable private SystemTextClassifierMetadata mSystemTcMetadata; 229 Request(CharSequence text, Bundle bundle)230 private Request(CharSequence text, Bundle bundle) { 231 mText = text; 232 mExtra = bundle; 233 } 234 235 /** 236 * Returns the text to process. 237 */ 238 @NonNull getText()239 public CharSequence getText() { 240 return mText; 241 } 242 243 /** 244 * Returns the name of the package that sent this request. 245 * This returns null if no calling package name is set. 246 */ 247 @Nullable getCallingPackageName()248 public String getCallingPackageName() { 249 return mSystemTcMetadata != null ? mSystemTcMetadata.getCallingPackageName() : null; 250 } 251 252 /** 253 * Sets the information about the {@link SystemTextClassifier} that sent this request. 254 * 255 * @hide 256 */ 257 @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) setSystemTextClassifierMetadata( @ullable SystemTextClassifierMetadata systemTcMetadata)258 public void setSystemTextClassifierMetadata( 259 @Nullable SystemTextClassifierMetadata systemTcMetadata) { 260 mSystemTcMetadata = systemTcMetadata; 261 } 262 263 /** 264 * Returns the information about the {@link SystemTextClassifier} that sent this request. 265 * 266 * @hide 267 */ 268 @Nullable getSystemTextClassifierMetadata()269 public SystemTextClassifierMetadata getSystemTextClassifierMetadata() { 270 return mSystemTcMetadata; 271 } 272 273 /** 274 * Returns a bundle containing non-structured extra information about this request. 275 * 276 * <p><b>NOTE: </b>Do not modify this bundle. 277 */ 278 @NonNull getExtras()279 public Bundle getExtras() { 280 return mExtra; 281 } 282 283 @Override describeContents()284 public int describeContents() { 285 return 0; 286 } 287 288 @Override writeToParcel(Parcel dest, int flags)289 public void writeToParcel(Parcel dest, int flags) { 290 dest.writeCharSequence(mText); 291 dest.writeBundle(mExtra); 292 dest.writeParcelable(mSystemTcMetadata, flags); 293 } 294 readFromParcel(Parcel in)295 private static Request readFromParcel(Parcel in) { 296 final CharSequence text = in.readCharSequence(); 297 final Bundle extra = in.readBundle(); 298 final SystemTextClassifierMetadata systemTcMetadata = in.readParcelable(null, android.view.textclassifier.SystemTextClassifierMetadata.class); 299 300 final Request request = new Request(text, extra); 301 request.setSystemTextClassifierMetadata(systemTcMetadata); 302 return request; 303 } 304 305 /** 306 * A builder for building TextLanguage requests. 307 */ 308 public static final class Builder { 309 310 private final CharSequence mText; 311 @Nullable private Bundle mBundle; 312 313 /** 314 * Creates a builder to build TextLanguage requests. 315 * 316 * @param text the text to process. 317 */ Builder(@onNull CharSequence text)318 public Builder(@NonNull CharSequence text) { 319 mText = Objects.requireNonNull(text); 320 } 321 322 /** 323 * Sets a bundle containing non-structured extra information about the request. 324 */ 325 @NonNull setExtras(@onNull Bundle bundle)326 public Builder setExtras(@NonNull Bundle bundle) { 327 mBundle = Objects.requireNonNull(bundle); 328 return this; 329 } 330 331 /** 332 * Builds and returns a new TextLanguage request object. 333 * <p> 334 * If necessary, this method will verify fields, clamp them, and make them immutable. 335 */ 336 @NonNull build()337 public Request build() { 338 return new Request(mText.toString(), mBundle == null ? Bundle.EMPTY : mBundle); 339 } 340 } 341 } 342 } 343