1c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus/*
2c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus * Copyright (C) 2018 The Android Open Source Project
3c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus *
4c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus * Licensed under the Apache License, Version 2.0 (the "License");
5c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus * you may not use this file except in compliance with the License.
6c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus * You may obtain a copy of the License at
7c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus *
8c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus *      http://www.apache.org/licenses/LICENSE-2.0
9c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus *
10c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus * Unless required by applicable law or agreed to in writing, software
11c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus * distributed under the License is distributed on an "AS IS" BASIS,
12c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus * See the License for the specific language governing permissions and
14c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus * limitations under the License.
15c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus */
16c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus
17ddf3bdd8f2a3afe5d8fd041f542ad4005a2ac869Aurimas Liutikaspackage androidx.textclassifier;
18c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus
19c08637c95be5e31268baf9b434a2d710423181f5Jan Althausimport android.content.Intent;
20c08637c95be5e31268baf9b434a2d710423181f5Jan Althausimport android.graphics.Bitmap;
21c08637c95be5e31268baf9b434a2d710423181f5Jan Althausimport android.graphics.Canvas;
22c08637c95be5e31268baf9b434a2d710423181f5Jan Althausimport android.graphics.drawable.BitmapDrawable;
23c08637c95be5e31268baf9b434a2d710423181f5Jan Althausimport android.graphics.drawable.Drawable;
24c08637c95be5e31268baf9b434a2d710423181f5Jan Althausimport android.os.Parcel;
25c08637c95be5e31268baf9b434a2d710423181f5Jan Althausimport android.os.Parcelable;
26c65e03f6e729f8c5e5a766a1076ee3531dbdc0b2Aurimas Liutikas
27ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikasimport androidx.annotation.FloatRange;
28ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikasimport androidx.annotation.IntRange;
29ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikasimport androidx.annotation.NonNull;
30ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikasimport androidx.annotation.Nullable;
31ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikasimport androidx.annotation.RestrictTo;
32ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikasimport androidx.collection.ArrayMap;
33c65e03f6e729f8c5e5a766a1076ee3531dbdc0b2Aurimas Liutikasimport androidx.core.os.LocaleListCompat;
34ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikasimport androidx.core.util.Preconditions;
35c65e03f6e729f8c5e5a766a1076ee3531dbdc0b2Aurimas Liutikasimport androidx.textclassifier.TextClassifier.EntityType;
36c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus
37c08637c95be5e31268baf9b434a2d710423181f5Jan Althausimport java.util.ArrayList;
385e36a8223de2be293b905f5e022eaf74a090f6acJan Althausimport java.util.Calendar;
39c08637c95be5e31268baf9b434a2d710423181f5Jan Althausimport java.util.List;
40c08637c95be5e31268baf9b434a2d710423181f5Jan Althausimport java.util.Locale;
41c08637c95be5e31268baf9b434a2d710423181f5Jan Althausimport java.util.Map;
42c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus
43c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus/**
44c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus * Information for generating a widget to handle classified text.
45c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus *
46c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus * <p>A TextClassification object contains icons, labels, and intents that may be used to build a
47c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus * widget that can be used to act on classified text. There is the concept of a <i>primary
48c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus * action</i> and other <i>secondary actions</i>.
49c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus *
50c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus * <p>e.g. building a view that, when clicked, shares the classified text with the preferred app:
51c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus *
52c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus * <pre>{@code
53c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus *   // Called preferably outside the UiThread.
54c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus *   TextClassification classification = textClassifier.classifyText(allText, 10, 25);
55c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus *
56c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus *   // Called on the UiThread.
57c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus *   Button button = new Button(context);
58c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus *   button.setCompoundDrawablesWithIntrinsicBounds(classification.getIcon(), null, null, null);
59c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus *   button.setText(classification.getLabel());
60c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus *   button.setOnClickListener(v -> context.startActivity(classification.getIntent()));
61c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus * }</pre>
62c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus *
63c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus * TODO: describe how to start action mode for classified text.
64c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus */
65c08637c95be5e31268baf9b434a2d710423181f5Jan Althauspublic final class TextClassification implements Parcelable {
66c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus
67c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus    /**
68c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus     * @hide
69c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus     */
70c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus    @RestrictTo(RestrictTo.Scope.LIBRARY)
71c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus    static final TextClassification EMPTY = new TextClassification.Builder().build();
72c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus
73c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus    // TODO: investigate a way to derive this based on device properties.
74c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus    private static final int MAX_PRIMARY_ICON_SIZE = 192;
75c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus    private static final int MAX_SECONDARY_ICON_SIZE = 144;
76c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus
77c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus    @Nullable private final String mText;
78c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus    @Nullable private final Drawable mPrimaryIcon;
79c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus    @Nullable private final String mPrimaryLabel;
80c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus    @Nullable private final Intent mPrimaryIntent;
81c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus    @NonNull private final List<Drawable> mSecondaryIcons;
82c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus    @NonNull private final List<String> mSecondaryLabels;
83c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus    @NonNull private final List<Intent> mSecondaryIntents;
84c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus    @NonNull private final EntityConfidence mEntityConfidence;
85c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus    @NonNull private final String mSignature;
86c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus
87c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus    private TextClassification(
88c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus            @Nullable String text,
89c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus            @Nullable Drawable primaryIcon,
90c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus            @Nullable String primaryLabel,
91c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus            @Nullable Intent primaryIntent,
92c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus            @NonNull List<Drawable> secondaryIcons,
93c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus            @NonNull List<String> secondaryLabels,
94c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus            @NonNull List<Intent> secondaryIntents,
95c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus            @NonNull Map<String, Float> entityConfidence,
96c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus            @NonNull String signature) {
97c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus        Preconditions.checkArgument(secondaryLabels.size() == secondaryIntents.size());
98c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus        Preconditions.checkArgument(secondaryIcons.size() == secondaryIntents.size());
99c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus        mText = text;
100c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus        mPrimaryIcon = primaryIcon;
101c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus        mPrimaryLabel = primaryLabel;
102c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus        mPrimaryIntent = primaryIntent;
103c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus        mSecondaryIcons = secondaryIcons;
104c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus        mSecondaryLabels = secondaryLabels;
105c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus        mSecondaryIntents = secondaryIntents;
106c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus        mEntityConfidence = new EntityConfidence(entityConfidence);
107c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus        mSignature = signature;
108c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus    }
109c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus
110c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus    /**
111c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus     * Gets the classified text.
112c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus     */
113c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus    @Nullable
114c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus    public String getText() {
115c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus        return mText;
116c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus    }
117c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus
118c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus    /**
119c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus     * Returns the number of entities found in the classified text.
120c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus     */
121c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus    @IntRange(from = 0)
122c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus    public int getEntityCount() {
123c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus        return mEntityConfidence.getEntities().size();
124c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus    }
125c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus
126c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus    /**
127c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus     * Returns the entity at the specified index. Entities are ordered from high confidence
128c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus     * to low confidence.
129c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus     *
130c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus     * @throws IndexOutOfBoundsException if the specified index is out of range.
131c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus     * @see #getEntityCount() for the number of entities available.
132c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus     */
133c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus    @NonNull
134c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus    public @EntityType String getEntity(int index) {
135c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus        return mEntityConfidence.getEntities().get(index);
136c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus    }
137c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus
138c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus    /**
139c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus     * Returns the confidence score for the specified entity. The value ranges from
140c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus     * 0 (low confidence) to 1 (high confidence). 0 indicates that the entity was not found for the
141c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus     * classified text.
142c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus     */
143c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus    @FloatRange(from = 0.0, to = 1.0)
144c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus    public float getConfidenceScore(@EntityType String entity) {
145c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus        return mEntityConfidence.getConfidenceScore(entity);
146c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus    }
147c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus
148c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus    /**
149c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus     * Returns the number of <i>secondary</i> actions that are available to act on the classified
150c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus     * text.
151c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus     *
152c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus     * <p><strong>Note: </strong> that there may or may not be a <i>primary</i> action.
153c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus     *
154c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus     * @see #getSecondaryIntent(int)
155c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus     * @see #getSecondaryLabel(int)
156c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus     * @see #getSecondaryIcon(int)
157c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus     */
158c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus    @IntRange(from = 0)
159c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus    public int getSecondaryActionsCount() {
160c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus        return mSecondaryIntents.size();
161c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus    }
162c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus
163c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus    /**
164c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus     * Returns one of the <i>secondary</i> icons that maybe rendered on a widget used to act on the
165c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus     * classified text.
166c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus     *
167c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus     * @param index Index of the action to get the icon for.
168c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus     * @throws IndexOutOfBoundsException if the specified index is out of range.
169c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus     * @see #getSecondaryActionsCount() for the number of actions available.
170c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus     * @see #getSecondaryIntent(int)
171c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus     * @see #getSecondaryLabel(int)
172c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus     * @see #getIcon()
173c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus     */
174c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus    @Nullable
175c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus    public Drawable getSecondaryIcon(int index) {
176c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus        return mSecondaryIcons.get(index);
177c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus    }
178c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus
179c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus    /**
180c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus     * Returns an icon for the <i>primary</i> intent that may be rendered on a widget used to act
181c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus     * on the classified text.
182c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus     *
183c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus     * @see #getSecondaryIcon(int)
184c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus     */
185c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus    @Nullable
186c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus    public Drawable getIcon() {
187c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus        return mPrimaryIcon;
188c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus    }
189c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus
190c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus    /**
191c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus     * Returns one of the <i>secondary</i> labels that may be rendered on a widget used to act on
192c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus     * the classified text.
193c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus     *
194c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus     * @param index Index of the action to get the label for.
195c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus     * @throws IndexOutOfBoundsException if the specified index is out of range.
196c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus     * @see #getSecondaryActionsCount()
197c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus     * @see #getSecondaryIntent(int)
198c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus     * @see #getSecondaryIcon(int)
199c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus     * @see #getLabel()
200c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus     */
201c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus    @Nullable
202c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus    public CharSequence getSecondaryLabel(int index) {
203c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus        return mSecondaryLabels.get(index);
204c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus    }
205c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus
206c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus    /**
207c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus     * Returns a label for the <i>primary</i> intent that may be rendered on a widget used to act
208c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus     * on the classified text.
209c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus     *
210c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus     * @see #getSecondaryLabel(int)
211c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus     */
212c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus    @Nullable
213c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus    public CharSequence getLabel() {
214c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus        return mPrimaryLabel;
215c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus    }
216c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus
217c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus    /**
218c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus     * Returns one of the <i>secondary</i> intents that may be fired to act on the classified text.
219c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus     *
220c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus     * @param index Index of the action to get the intent for.
221c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus     * @throws IndexOutOfBoundsException if the specified index is out of range.
222c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus     * @see #getSecondaryActionsCount()
223c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus     * @see #getSecondaryLabel(int)
224c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus     * @see #getSecondaryIcon(int)
225c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus     * @see #getIntent()
226c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus     */
227c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus    @Nullable
228c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus    public Intent getSecondaryIntent(int index) {
229c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus        return mSecondaryIntents.get(index);
230c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus    }
231c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus
232c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus    /**
233c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus     * Returns the <i>primary</i> intent that may be fired to act on the classified text.
234c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus     *
235c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus     * @see #getSecondaryIntent(int)
236c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus     */
237c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus    @Nullable
238c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus    public Intent getIntent() {
239c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus        return mPrimaryIntent;
240c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus    }
241c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus
242c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus    /**
243c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus     * Returns the signature for this object.
244c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus     * The TextClassifier that generates this object may use it as a way to internally identify
245c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus     * this object.
246c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus     */
247c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus    @NonNull
248c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus    public String getSignature() {
249c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus        return mSignature;
250c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus    }
251c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus
252c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus    @Override
253c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus    public String toString() {
254c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus        return String.format(Locale.US, "TextClassification {"
255c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus                        + "text=%s, entities=%s, "
256c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus                        + "primaryLabel=%s, secondaryLabels=%s, "
257c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus                        + "primaryIntent=%s, secondaryIntents=%s, "
258c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus                        + "signature=%s}",
259c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus                mText, mEntityConfidence,
260c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus                mPrimaryLabel, mSecondaryLabels,
261c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus                mPrimaryIntent, mSecondaryIntents,
262c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus                mSignature);
263c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus    }
264c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus
265c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus    @Override
266c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus    public int describeContents() {
267c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus        return 0;
268c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus    }
269c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus
270c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus    @Override
271c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus    public void writeToParcel(Parcel dest, int flags) {
272c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus        dest.writeString(mText);
273c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus        final Bitmap primaryIconBitmap = drawableToBitmap(mPrimaryIcon, MAX_PRIMARY_ICON_SIZE);
274c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus        dest.writeInt(primaryIconBitmap != null ? 1 : 0);
275c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus        if (primaryIconBitmap != null) {
276c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus            primaryIconBitmap.writeToParcel(dest, flags);
277c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus        }
278c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus        dest.writeString(mPrimaryLabel);
279c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus        dest.writeInt(mPrimaryIntent != null ? 1 : 0);
280c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus        if (mPrimaryIntent != null) {
281c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus            mPrimaryIntent.writeToParcel(dest, flags);
282c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus        }
283c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus        dest.writeTypedList(drawablesToBitmaps(mSecondaryIcons, MAX_SECONDARY_ICON_SIZE));
284c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus        dest.writeStringList(mSecondaryLabels);
285c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus        dest.writeTypedList(mSecondaryIntents);
286c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus        mEntityConfidence.writeToParcel(dest, flags);
287c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus        dest.writeString(mSignature);
288c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus    }
289c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus
290c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus    public static final Parcelable.Creator<TextClassification> CREATOR =
291c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus            new Parcelable.Creator<TextClassification>() {
292c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus                @Override
293c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus                public TextClassification createFromParcel(Parcel in) {
294c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus                    return new TextClassification(in);
295c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus                }
296c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus
297c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus                @Override
298c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus                public TextClassification[] newArray(int size) {
299c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus                    return new TextClassification[size];
300c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus                }
301c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus            };
302c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus
303c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus    private TextClassification(Parcel in) {
304c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus        mText = in.readString();
305c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus        mPrimaryIcon = in.readInt() == 0
306c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus                ? null : new BitmapDrawable(null, Bitmap.CREATOR.createFromParcel(in));
307c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus        mPrimaryLabel = in.readString();
308c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus        mPrimaryIntent = in.readInt() == 0 ? null : Intent.CREATOR.createFromParcel(in);
309c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus        mSecondaryIcons = bitmapsToDrawables(in.createTypedArrayList(Bitmap.CREATOR));
310c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus        mSecondaryLabels = in.createStringArrayList();
311c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus        mSecondaryIntents = in.createTypedArrayList(Intent.CREATOR);
312c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus        mEntityConfidence = EntityConfidence.CREATOR.createFromParcel(in);
313c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus        mSignature = in.readString();
314c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus    }
315c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus
316c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus    /**
317c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus     * Returns a Bitmap representation of the Drawable
318c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus     *
319c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus     * @param drawable The drawable to convert.
320c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus     * @param maxDims The maximum edge length of the resulting bitmap (in pixels).
321c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus     */
322c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus    @Nullable
323c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus    private static Bitmap drawableToBitmap(@Nullable Drawable drawable, int maxDims) {
324c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus        if (drawable == null) {
325c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus            return null;
326c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus        }
327c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus        final int actualWidth = Math.max(1, drawable.getIntrinsicWidth());
328c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus        final int actualHeight = Math.max(1, drawable.getIntrinsicHeight());
329c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus        final double scaleWidth = ((double) maxDims) / actualWidth;
330c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus        final double scaleHeight = ((double) maxDims) / actualHeight;
331c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus        final double scale = Math.min(1.0, Math.min(scaleWidth, scaleHeight));
332c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus        final int width = (int) (actualWidth * scale);
333c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus        final int height = (int) (actualHeight * scale);
334c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus        if (drawable instanceof BitmapDrawable) {
335c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus            final BitmapDrawable bitmapDrawable = (BitmapDrawable) drawable;
336c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus            if (actualWidth != width || actualHeight != height) {
337c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus                return Bitmap.createScaledBitmap(
338c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus                        bitmapDrawable.getBitmap(), width, height, /*filter=*/false);
339c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus            } else {
340c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus                return bitmapDrawable.getBitmap();
341c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus            }
342c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus        } else {
343c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus            final Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
344c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus            final Canvas canvas = new Canvas(bitmap);
345c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus            drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
346c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus            drawable.draw(canvas);
347c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus            return bitmap;
348c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus        }
349c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus    }
350c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus
351c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus    /**
352c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus     * Returns a list of drawables converted to Bitmaps
353c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus     *
354c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus     * @param drawables The drawables to convert.
355c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus     * @param maxDims The maximum edge length of the resulting bitmaps (in pixels).
356c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus     */
357c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus    private static List<Bitmap> drawablesToBitmaps(List<Drawable> drawables, int maxDims) {
358c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus        final List<Bitmap> bitmaps = new ArrayList<>(drawables.size());
359c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus        for (Drawable drawable : drawables) {
360c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus            bitmaps.add(drawableToBitmap(drawable, maxDims));
361c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus        }
362c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus        return bitmaps;
363c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus    }
364c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus
365c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus    /** Returns a list of drawable wrappers for a list of bitmaps. */
366c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus    private static List<Drawable> bitmapsToDrawables(List<Bitmap> bitmaps) {
367c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus        final List<Drawable> drawables = new ArrayList<>(bitmaps.size());
368c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus        for (Bitmap bitmap : bitmaps) {
369c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus            if (bitmap != null) {
370c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus                drawables.add(new BitmapDrawable(null, bitmap));
371c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus            } else {
372c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus                drawables.add(null);
373c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus            }
374c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus        }
375c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus        return drawables;
376c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus    }
377c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus
378c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus    /**
379c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus     * Builder for building {@link TextClassification} objects.
380c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus     *
381c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus     * <p>e.g.
382c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus     *
383c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus     * <pre>{@code
384c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus     *   TextClassification classification = new TextClassification.Builder()
385c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus     *          .setText(classifiedText)
386c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus     *          .setEntityType(TextClassifier.TYPE_EMAIL, 0.9)
387c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus     *          .setEntityType(TextClassifier.TYPE_OTHER, 0.1)
388c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus     *          .setPrimaryAction(intent, label, icon)
389c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus     *          .addSecondaryAction(intent1, label1, icon1)
390c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus     *          .addSecondaryAction(intent2, label2, icon2)
391c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus     *          .build();
392c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus     * }</pre>
393c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus     */
394c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus    public static final class Builder {
395c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus
396c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus        @NonNull private String mText;
397c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus        @NonNull private final List<Drawable> mSecondaryIcons = new ArrayList<>();
398c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus        @NonNull private final List<String> mSecondaryLabels = new ArrayList<>();
399c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus        @NonNull private final List<Intent> mSecondaryIntents = new ArrayList<>();
400c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus        @NonNull private final Map<String, Float> mEntityConfidence = new ArrayMap<>();
401c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus        @Nullable Drawable mPrimaryIcon;
402c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus        @Nullable String mPrimaryLabel;
403c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus        @Nullable Intent mPrimaryIntent;
404c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus        @NonNull private String mSignature = "";
405c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus
406c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus        /**
407c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus         * Sets the classified text.
408c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus         */
409c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus        public Builder setText(@Nullable String text) {
410c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus            mText = text;
411c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus            return this;
412c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus        }
413c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus
414c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus        /**
415c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus         * Sets an entity type for the classification result and assigns a confidence score.
416c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus         * If a confidence score had already been set for the specified entity type, this will
417c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus         * override that score.
418c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus         *
419c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus         * @param confidenceScore a value from 0 (low confidence) to 1 (high confidence).
420c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus         *      0 implies the entity does not exist for the classified text.
421c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus         *      Values greater than 1 are clamped to 1.
422c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus         */
423c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus        public Builder setEntityType(
424c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus                @NonNull @EntityType String type,
425c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus                @FloatRange(from = 0.0, to = 1.0) float confidenceScore) {
426c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus            mEntityConfidence.put(type, confidenceScore);
427c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus            return this;
428c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus        }
429c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus
430c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus        /**
431c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus         * Adds an <i>secondary</i> action that may be performed on the classified text.
432c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus         * Secondary actions are in addition to the <i>primary</i> action which may or may not
433c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus         * exist.
434c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus         *
435c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus         * <p>The label and icon are used for rendering of widgets that offer the intent.
436c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus         * Actions should be added in order of priority.
437c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus         *
438c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus         * <p><stong>Note: </stong> If all input parameters are set to null, this method will be a
439c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus         * no-op.
440c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus         *
441c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus         * @see #setPrimaryAction(Intent, String, Drawable)
442c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus         */
443c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus        public Builder addSecondaryAction(
444c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus                @Nullable Intent intent, @Nullable String label, @Nullable Drawable icon) {
445c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus            if (intent != null || label != null || icon != null) {
446c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus                mSecondaryIntents.add(intent);
447c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus                mSecondaryLabels.add(label);
448c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus                mSecondaryIcons.add(icon);
449c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus            }
450c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus            return this;
451c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus        }
452c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus
453c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus        /**
454c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus         * Removes all the <i>secondary</i> actions.
455c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus         */
456c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus        public Builder clearSecondaryActions() {
457c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus            mSecondaryIntents.clear();
458c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus            mSecondaryLabels.clear();
459c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus            mSecondaryIcons.clear();
460c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus            return this;
461c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus        }
462c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus
463c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus        /**
464c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus         * Sets the <i>primary</i> action that may be performed on the classified text. This is
465c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus         * equivalent to calling {@code setIntent(intent).setLabel(label).setIcon(icon)}.
466c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus         *
467c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus         * <p><strong>Note: </strong>If all input parameters are null, there will be no
468c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus         * <i>primary</i> action but there may still be <i>secondary</i> actions.
469c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus         *
470c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus         * @see #addSecondaryAction(Intent, String, Drawable)
471c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus         */
472c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus        public Builder setPrimaryAction(
473c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus                @Nullable Intent intent, @Nullable String label, @Nullable Drawable icon) {
474c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus            return setIntent(intent).setLabel(label).setIcon(icon);
475c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus        }
476c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus
477c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus        /**
478c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus         * Sets the icon for the <i>primary</i> action that may be rendered on a widget used to act
479c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus         * on the classified text.
480c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus         *
481c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus         * @see #setPrimaryAction(Intent, String, Drawable)
482c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus         */
483c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus        public Builder setIcon(@Nullable Drawable icon) {
484c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus            mPrimaryIcon = icon;
485c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus            return this;
486c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus        }
487c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus
488c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus        /**
489c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus         * Sets the label for the <i>primary</i> action that may be rendered on a widget used to
490c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus         * act on the classified text.
491c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus         *
492c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus         * @see #setPrimaryAction(Intent, String, Drawable)
493c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus         */
494c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus        public Builder setLabel(@Nullable String label) {
495c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus            mPrimaryLabel = label;
496c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus            return this;
497c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus        }
498c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus
499c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus        /**
500c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus         * Sets the intent for the <i>primary</i> action that may be fired to act on the classified
501c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus         * text.
502c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus         *
503c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus         * @see #setPrimaryAction(Intent, String, Drawable)
504c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus         */
505c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus        public Builder setIntent(@Nullable Intent intent) {
506c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus            mPrimaryIntent = intent;
507c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus            return this;
508c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus        }
509c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus
510c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus        /**
511c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus         * Sets a signature for the TextClassification object.
512c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus         * The TextClassifier that generates the TextClassification object may use it as a way to
513c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus         * internally identify the TextClassification object.
514c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus         */
515c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus        public Builder setSignature(@NonNull String signature) {
516c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus            mSignature = Preconditions.checkNotNull(signature);
517c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus            return this;
518c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus        }
519c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus
520c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus        /**
521c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus         * Builds and returns a {@link TextClassification} object.
522c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus         */
523c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus        public TextClassification build() {
524c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus            return new TextClassification(
525c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus                    mText,
526c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus                    mPrimaryIcon, mPrimaryLabel, mPrimaryIntent,
527c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus                    mSecondaryIcons, mSecondaryLabels, mSecondaryIntents,
528c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus                    mEntityConfidence, mSignature);
529c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus        }
530c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus    }
531c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus
532c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus    /**
533c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus     * Optional input parameters for generating TextClassification.
534c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus     */
535c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus    public static final class Options implements Parcelable {
536c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus
5375e36a8223de2be293b905f5e022eaf74a090f6acJan Althaus        private @Nullable LocaleListCompat mDefaultLocales;
5385e36a8223de2be293b905f5e022eaf74a090f6acJan Althaus        private @Nullable Calendar mReferenceTime;
539fa2de0056203d1cd59387416a1ebcee587c4b151Jan Althaus        private @Nullable String mCallingPackageName;
540c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus
541c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus        public Options() {}
542c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus
543c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus        /**
544c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus         * @param defaultLocales ordered list of locale preferences that may be used to disambiguate
545c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus         *      the provided text. If no locale preferences exist, set this to null or an empty
546c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus         *      locale list.
547c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus         */
5485e36a8223de2be293b905f5e022eaf74a090f6acJan Althaus        public Options setDefaultLocales(@Nullable LocaleListCompat defaultLocales) {
5495e36a8223de2be293b905f5e022eaf74a090f6acJan Althaus            mDefaultLocales = defaultLocales;
5505e36a8223de2be293b905f5e022eaf74a090f6acJan Althaus            return this;
5515e36a8223de2be293b905f5e022eaf74a090f6acJan Althaus        }
5525e36a8223de2be293b905f5e022eaf74a090f6acJan Althaus
5535e36a8223de2be293b905f5e022eaf74a090f6acJan Althaus        /**
5545e36a8223de2be293b905f5e022eaf74a090f6acJan Althaus         * @param referenceTime reference time based on which relative dates (e.g. "tomorrow" should
5555e36a8223de2be293b905f5e022eaf74a090f6acJan Althaus         *      be interpreted. This should usually be the time when the text was originally
5565e36a8223de2be293b905f5e022eaf74a090f6acJan Althaus         *      composed. If no reference time is set, now is used.
5575e36a8223de2be293b905f5e022eaf74a090f6acJan Althaus         */
5585e36a8223de2be293b905f5e022eaf74a090f6acJan Althaus        public Options setReferenceTime(Calendar referenceTime) {
5595e36a8223de2be293b905f5e022eaf74a090f6acJan Althaus            mReferenceTime = referenceTime;
560c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus            return this;
561c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus        }
562c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus
563c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus        /**
564fa2de0056203d1cd59387416a1ebcee587c4b151Jan Althaus         * @param packageName name of the package from which the call was made.
565fa2de0056203d1cd59387416a1ebcee587c4b151Jan Althaus         *
566fa2de0056203d1cd59387416a1ebcee587c4b151Jan Althaus         * @hide
567fa2de0056203d1cd59387416a1ebcee587c4b151Jan Althaus         */
568fa2de0056203d1cd59387416a1ebcee587c4b151Jan Althaus        @RestrictTo(RestrictTo.Scope.LIBRARY)
569fa2de0056203d1cd59387416a1ebcee587c4b151Jan Althaus        public Options setCallingPackageName(@Nullable String packageName) {
570fa2de0056203d1cd59387416a1ebcee587c4b151Jan Althaus            mCallingPackageName = packageName;
571fa2de0056203d1cd59387416a1ebcee587c4b151Jan Althaus            return this;
572fa2de0056203d1cd59387416a1ebcee587c4b151Jan Althaus        }
573fa2de0056203d1cd59387416a1ebcee587c4b151Jan Althaus
574fa2de0056203d1cd59387416a1ebcee587c4b151Jan Althaus        /**
575c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus         * @return ordered list of locale preferences that can be used to disambiguate
576c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus         *      the provided text.
577c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus         */
578c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus        @Nullable
5795e36a8223de2be293b905f5e022eaf74a090f6acJan Althaus        public LocaleListCompat getDefaultLocales() {
580c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus            return mDefaultLocales;
581c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus        }
582c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus
5835e36a8223de2be293b905f5e022eaf74a090f6acJan Althaus        /**
5845e36a8223de2be293b905f5e022eaf74a090f6acJan Althaus         * @return reference time based on which relative dates (e.g. "tomorrow") should be
5855e36a8223de2be293b905f5e022eaf74a090f6acJan Althaus         *      interpreted.
5865e36a8223de2be293b905f5e022eaf74a090f6acJan Althaus         */
5875e36a8223de2be293b905f5e022eaf74a090f6acJan Althaus        @Nullable
5885e36a8223de2be293b905f5e022eaf74a090f6acJan Althaus        public Calendar getReferenceTime() {
5895e36a8223de2be293b905f5e022eaf74a090f6acJan Althaus            return mReferenceTime;
5905e36a8223de2be293b905f5e022eaf74a090f6acJan Althaus        }
5915e36a8223de2be293b905f5e022eaf74a090f6acJan Althaus
592fa2de0056203d1cd59387416a1ebcee587c4b151Jan Althaus        /**
593fa2de0056203d1cd59387416a1ebcee587c4b151Jan Althaus         * @return name of the package from which the call was made.
594fa2de0056203d1cd59387416a1ebcee587c4b151Jan Althaus         */
595fa2de0056203d1cd59387416a1ebcee587c4b151Jan Althaus        @Nullable
596fa2de0056203d1cd59387416a1ebcee587c4b151Jan Althaus        public String getCallingPackageName() {
597fa2de0056203d1cd59387416a1ebcee587c4b151Jan Althaus            return mCallingPackageName;
598fa2de0056203d1cd59387416a1ebcee587c4b151Jan Althaus        }
599fa2de0056203d1cd59387416a1ebcee587c4b151Jan Althaus
600c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus        @Override
601c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus        public int describeContents() {
602c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus            return 0;
603c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus        }
604c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus
605c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus        @Override
606c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus        public void writeToParcel(Parcel dest, int flags) {
6075e36a8223de2be293b905f5e022eaf74a090f6acJan Althaus            dest.writeInt(mDefaultLocales != null ? 1 : 0);
608c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus            if (mDefaultLocales != null) {
6095e36a8223de2be293b905f5e022eaf74a090f6acJan Althaus                dest.writeString(mDefaultLocales.toLanguageTags());
6105e36a8223de2be293b905f5e022eaf74a090f6acJan Althaus            }
6115e36a8223de2be293b905f5e022eaf74a090f6acJan Althaus            dest.writeInt(mReferenceTime != null ? 1 : 0);
6125e36a8223de2be293b905f5e022eaf74a090f6acJan Althaus            if (mReferenceTime != null) {
6135e36a8223de2be293b905f5e022eaf74a090f6acJan Althaus                dest.writeSerializable(mReferenceTime);
614c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus            }
615fa2de0056203d1cd59387416a1ebcee587c4b151Jan Althaus            dest.writeString(mCallingPackageName);
616c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus        }
617c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus
618c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus        public static final Parcelable.Creator<Options> CREATOR =
619c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus                new Parcelable.Creator<Options>() {
620c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus                    @Override
621c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus                    public Options createFromParcel(Parcel in) {
622c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus                        return new Options(in);
623c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus                    }
624c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus
625c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus                    @Override
626c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus                    public Options[] newArray(int size) {
627c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus                        return new Options[size];
628c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus                    }
629c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus                };
630c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus
631c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus        private Options(Parcel in) {
6325e36a8223de2be293b905f5e022eaf74a090f6acJan Althaus            if (in.readInt() > 0) {
6335e36a8223de2be293b905f5e022eaf74a090f6acJan Althaus                mDefaultLocales = LocaleListCompat.forLanguageTags(in.readString());
6345e36a8223de2be293b905f5e022eaf74a090f6acJan Althaus            }
6355e36a8223de2be293b905f5e022eaf74a090f6acJan Althaus            if (in.readInt() > 0) {
6365e36a8223de2be293b905f5e022eaf74a090f6acJan Althaus                mReferenceTime = (Calendar) in.readSerializable();
637c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus            }
638fa2de0056203d1cd59387416a1ebcee587c4b151Jan Althaus            mCallingPackageName = in.readString();
639c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus        }
640c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus    }
641c08637c95be5e31268baf9b434a2d710423181f5Jan Althaus}
642