blob: eaf4d7f5d5d1a23a1864955f082dafa898ecb795 [file] [log] [blame]
Abodunrinwa Toki7cefd4f2018-09-14 16:00:03 +01001/*
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
17package android.view.textclassifier;
18
19import android.annotation.FloatRange;
20import android.annotation.IntRange;
21import android.annotation.NonNull;
22import android.annotation.Nullable;
23import android.icu.util.ULocale;
24import android.os.Bundle;
25import android.os.Parcel;
26import android.os.Parcelable;
27import android.util.ArrayMap;
28
Abodunrinwa Toki0f138962018-12-03 22:35:10 +000029import com.android.internal.annotations.VisibleForTesting;
Abodunrinwa Toki7cefd4f2018-09-14 16:00:03 +010030import com.android.internal.util.Preconditions;
31
32import java.util.Locale;
33import java.util.Map;
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 */
44public final class TextLanguage implements Parcelable {
45
Jeff Sharkey9e8f83d2019-02-28 12:06:45 -070046 public static final @android.annotation.NonNull Creator<TextLanguage> CREATOR = new Creator<TextLanguage>() {
Abodunrinwa Toki7cefd4f2018-09-14 16:00:03 +010047 @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
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
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)
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.
Abodunrinwa Tokia77dba62019-01-25 19:27:11 +000092 * <p>
93 * See {@link #getLocaleHypothesisCount()} for the number of locales available.
Abodunrinwa Toki7cefd4f2018-09-14 16:00:03 +010094 *
95 * @throws IndexOutOfBoundsException if the specified index is out of range.
Abodunrinwa Toki7cefd4f2018-09-14 16:00:03 +010096 */
97 @NonNull
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)
108 public float getConfidenceScore(@NonNull ULocale locale) {
109 return mEntityConfidence.getConfidenceScore(locale.toLanguageTag());
110 }
111
112 /**
Abodunrinwa Tokia77dba62019-01-25 19:27:11 +0000113 * 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.
Abodunrinwa Toki7cefd4f2018-09-14 16:00:03 +0100115 *
116 * <p><b>NOTE: </b>Each call to this method returns a new bundle copy so clients should prefer
117 * to hold a reference to the returned bundle rather than frequently calling this method.
118 */
119 @NonNull
120 public Bundle getExtras() {
121 return mBundle.deepCopy();
122 }
123
124 @Override
125 public String toString() {
126 return String.format(
127 Locale.US,
128 "TextLanguage {id=%s, locales=%s, bundle=%s}",
129 mId, mEntityConfidence, mBundle);
130 }
131
132 @Override
133 public int describeContents() {
134 return 0;
135 }
136
137 @Override
138 public void writeToParcel(Parcel dest, int flags) {
139 dest.writeString(mId);
140 mEntityConfidence.writeToParcel(dest, flags);
141 dest.writeBundle(mBundle);
142 }
143
144 private static TextLanguage readFromParcel(Parcel in) {
145 return new TextLanguage(
146 in.readString(),
147 EntityConfidence.CREATOR.createFromParcel(in),
148 in.readBundle());
149 }
150
151 /**
152 * Builder used to build TextLanguage objects.
153 */
154 public static final class Builder {
155
156 @Nullable private String mId;
157 private final Map<String, Float> mEntityConfidenceMap = new ArrayMap<>();
158 @Nullable private Bundle mBundle;
159
160 /**
161 * Sets a language locale for the processed text and assigns a confidence score. If the
162 * locale has already been set, this updates it.
163 *
164 * @param confidenceScore a value from 0 (low confidence) to 1 (high confidence).
165 * 0 implies the locale does not exist for the processed text.
166 * Values greater than 1 are clamped to 1.
167 */
168 @NonNull
169 public Builder putLocale(
170 @NonNull ULocale locale,
171 @FloatRange(from = 0.0, to = 1.0) float confidenceScore) {
172 Preconditions.checkNotNull(locale);
173 mEntityConfidenceMap.put(locale.toLanguageTag(), confidenceScore);
174 return this;
175 }
176
177 /**
178 * Sets an optional id for the TextLanguage object.
179 */
180 @NonNull
181 public Builder setId(@Nullable String id) {
182 mId = id;
183 return this;
184 }
185
186 /**
187 * Sets a bundle containing non-structured extra information about the TextLanguage object.
188 */
189 @NonNull
190 public Builder setExtras(@NonNull Bundle bundle) {
191 mBundle = Preconditions.checkNotNull(bundle);
192 return this;
193 }
194
195 /**
196 * Builds and returns a new TextLanguage object.
197 * <p>
198 * If necessary, this method will verify fields, clamp them, and make them immutable.
199 */
200 @NonNull
201 public TextLanguage build() {
202 mBundle = mBundle == null ? new Bundle() : mBundle.deepCopy();
203 return new TextLanguage(
204 mId,
205 new EntityConfidence(mEntityConfidenceMap),
206 mBundle);
207 }
208 }
209
210 /**
211 * A request object for detecting the language of a piece of text.
212 */
213 public static final class Request implements Parcelable {
214
Jeff Sharkey9e8f83d2019-02-28 12:06:45 -0700215 public static final @android.annotation.NonNull Creator<Request> CREATOR = new Creator<Request>() {
Abodunrinwa Toki7cefd4f2018-09-14 16:00:03 +0100216 @Override
217 public Request createFromParcel(Parcel in) {
218 return readFromParcel(in);
219 }
220
221 @Override
222 public Request[] newArray(int size) {
223 return new Request[size];
224 }
225 };
226
227 private final CharSequence mText;
Abodunrinwa Toki0f138962018-12-03 22:35:10 +0000228 private final Bundle mExtra;
229 @Nullable private String mCallingPackageName;
Abodunrinwa Toki7cefd4f2018-09-14 16:00:03 +0100230
231 private Request(CharSequence text, Bundle bundle) {
232 mText = text;
Abodunrinwa Toki0f138962018-12-03 22:35:10 +0000233 mExtra = bundle;
Abodunrinwa Toki7cefd4f2018-09-14 16:00:03 +0100234 }
235
236 /**
237 * Returns the text to process.
238 */
239 @NonNull
240 public CharSequence getText() {
241 return mText;
242 }
243
244 /**
Abodunrinwa Toki0f138962018-12-03 22:35:10 +0000245 * Sets the name of the package that is sending this request.
246 * Package-private for SystemTextClassifier's use.
247 * @hide
248 */
249 @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
250 public void setCallingPackageName(@Nullable String callingPackageName) {
251 mCallingPackageName = callingPackageName;
252 }
253
254 /**
255 * Returns the name of the package that sent this request.
256 * This returns null if no calling package name is set.
257 */
258 @Nullable
259 public String getCallingPackageName() {
260 return mCallingPackageName;
261 }
262
263 /**
Abodunrinwa Toki7cefd4f2018-09-14 16:00:03 +0100264 * Returns a bundle containing non-structured extra information about this request.
265 *
266 * <p><b>NOTE: </b>Each call to this method returns a new bundle copy so clients should
267 * prefer to hold a reference to the returned bundle rather than frequently calling this
268 * method.
269 */
270 @NonNull
271 public Bundle getExtras() {
Abodunrinwa Toki0f138962018-12-03 22:35:10 +0000272 return mExtra.deepCopy();
Abodunrinwa Toki7cefd4f2018-09-14 16:00:03 +0100273 }
274
275 @Override
276 public int describeContents() {
277 return 0;
278 }
279
280 @Override
281 public void writeToParcel(Parcel dest, int flags) {
282 dest.writeCharSequence(mText);
Abodunrinwa Toki0f138962018-12-03 22:35:10 +0000283 dest.writeString(mCallingPackageName);
284 dest.writeBundle(mExtra);
Abodunrinwa Toki7cefd4f2018-09-14 16:00:03 +0100285 }
286
287 private static Request readFromParcel(Parcel in) {
Abodunrinwa Toki0f138962018-12-03 22:35:10 +0000288 final CharSequence text = in.readCharSequence();
289 final String callingPackageName = in.readString();
290 final Bundle extra = in.readBundle();
291
292 final Request request = new Request(text, extra);
293 request.setCallingPackageName(callingPackageName);
294 return request;
Abodunrinwa Toki7cefd4f2018-09-14 16:00:03 +0100295 }
296
297 /**
298 * A builder for building TextLanguage requests.
299 */
300 public static final class Builder {
301
302 private final CharSequence mText;
303 @Nullable private Bundle mBundle;
304
305 /**
306 * Creates a builder to build TextLanguage requests.
307 *
308 * @param text the text to process.
309 */
310 public Builder(@NonNull CharSequence text) {
311 mText = Preconditions.checkNotNull(text);
312 }
313
314 /**
315 * Sets a bundle containing non-structured extra information about the request.
316 */
317 @NonNull
318 public Builder setExtras(@NonNull Bundle bundle) {
319 mBundle = Preconditions.checkNotNull(bundle);
320 return this;
321 }
322
323 /**
324 * Builds and returns a new TextLanguage request object.
325 * <p>
326 * If necessary, this method will verify fields, clamp them, and make them immutable.
327 */
328 @NonNull
329 public Request build() {
330 mBundle = mBundle == null ? new Bundle() : mBundle.deepCopy();
331 return new Request(mText.toString(), mBundle);
332 }
333 }
334 }
335}