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 package android.view.textclassifier;
17 
18 import static java.lang.annotation.RetentionPolicy.SOURCE;
19 
20 import android.annotation.FloatRange;
21 import android.annotation.NonNull;
22 import android.annotation.Nullable;
23 import android.annotation.StringDef;
24 import android.app.RemoteAction;
25 import android.os.Bundle;
26 import android.os.Parcel;
27 import android.os.Parcelable;
28 
29 import java.lang.annotation.Retention;
30 import java.util.Objects;
31 
32 /** Represents the action suggested by a {@link TextClassifier} on a given conversation. */
33 public final class ConversationAction implements Parcelable {
34 
35     /** @hide */
36     @Retention(SOURCE)
37     @StringDef(
38             value = {
39                     TYPE_VIEW_CALENDAR,
40                     TYPE_VIEW_MAP,
41                     TYPE_TRACK_FLIGHT,
42                     TYPE_OPEN_URL,
43                     TYPE_SEND_SMS,
44                     TYPE_CALL_PHONE,
45                     TYPE_SEND_EMAIL,
46                     TYPE_TEXT_REPLY,
47                     TYPE_CREATE_REMINDER,
48                     TYPE_SHARE_LOCATION
49             },
50             prefix = "TYPE_")
51     public @interface ActionType {}
52 
53     /**
54      * Indicates an action to view a calendar at a specified time.
55      */
56     public static final String TYPE_VIEW_CALENDAR = "view_calendar";
57     /**
58      * Indicates an action to view the map at a specified location.
59      */
60     public static final String TYPE_VIEW_MAP = "view_map";
61     /**
62      * Indicates an action to track a flight.
63      */
64     public static final String TYPE_TRACK_FLIGHT = "track_flight";
65     /**
66      * Indicates an action to open an URL.
67      */
68     public static final String TYPE_OPEN_URL = "open_url";
69     /**
70      * Indicates an action to send a SMS.
71      */
72     public static final String TYPE_SEND_SMS = "send_sms";
73     /**
74      * Indicates an action to call a phone number.
75      */
76     public static final String TYPE_CALL_PHONE = "call_phone";
77     /**
78      * Indicates an action to send an email.
79      */
80     public static final String TYPE_SEND_EMAIL = "send_email";
81     /**
82      * Indicates an action to reply with a text message.
83      */
84     public static final String TYPE_TEXT_REPLY = "text_reply";
85     /**
86      * Indicates an action to create a reminder.
87      */
88     public static final String TYPE_CREATE_REMINDER = "create_reminder";
89     /**
90      * Indicates an action to reply with a location.
91      */
92     public static final String TYPE_SHARE_LOCATION = "share_location";
93 
94     // TODO: Make this public API
95     /** @hide **/
96     public static final String TYPE_ADD_CONTACT = "add_contact";
97 
98     // TODO: Make this public API
99     /** @hide **/
100     public static final String TYPE_COPY = "copy";
101 
102     public static final @NonNull Creator<ConversationAction> CREATOR =
103             new Creator<ConversationAction>() {
104                 @Override
105                 public ConversationAction createFromParcel(Parcel in) {
106                     return new ConversationAction(in);
107                 }
108 
109                 @Override
110                 public ConversationAction[] newArray(int size) {
111                     return new ConversationAction[size];
112                 }
113             };
114 
115     @NonNull
116     @ActionType
117     private final String mType;
118     @NonNull
119     private final CharSequence mTextReply;
120     @Nullable
121     private final RemoteAction mAction;
122 
123     @FloatRange(from = 0, to = 1)
124     private final float mScore;
125 
126     @NonNull
127     private final Bundle mExtras;
128 
ConversationAction( @onNull String type, @Nullable RemoteAction action, @Nullable CharSequence textReply, float score, @NonNull Bundle extras)129     private ConversationAction(
130             @NonNull String type,
131             @Nullable RemoteAction action,
132             @Nullable CharSequence textReply,
133             float score,
134             @NonNull Bundle extras) {
135         mType = Objects.requireNonNull(type);
136         mAction = action;
137         mTextReply = textReply;
138         mScore = score;
139         mExtras = Objects.requireNonNull(extras);
140     }
141 
ConversationAction(Parcel in)142     private ConversationAction(Parcel in) {
143         mType = in.readString();
144         mAction = in.readParcelable(null, android.app.RemoteAction.class);
145         mTextReply = in.readCharSequence();
146         mScore = in.readFloat();
147         mExtras = in.readBundle();
148     }
149 
150     @Override
writeToParcel(Parcel parcel, int flags)151     public void writeToParcel(Parcel parcel, int flags) {
152         parcel.writeString(mType);
153         parcel.writeParcelable(mAction, flags);
154         parcel.writeCharSequence(mTextReply);
155         parcel.writeFloat(mScore);
156         parcel.writeBundle(mExtras);
157     }
158 
159     @Override
describeContents()160     public int describeContents() {
161         return 0;
162     }
163 
164     /** Returns the type of this action, for example, {@link #TYPE_VIEW_CALENDAR}. */
165     @NonNull
166     @ActionType
getType()167     public String getType() {
168         return mType;
169     }
170 
171     /**
172      * Returns a RemoteAction object, which contains the icon, label and a PendingIntent, for
173      * the specified action type.
174      */
175     @Nullable
getAction()176     public RemoteAction getAction() {
177         return mAction;
178     }
179 
180     /**
181      * Returns the confidence score for the specified action. The value ranges from 0 (low
182      * confidence) to 1 (high confidence).
183      */
184     @FloatRange(from = 0, to = 1)
getConfidenceScore()185     public float getConfidenceScore() {
186         return mScore;
187     }
188 
189     /**
190      * Returns the text reply that could be sent as a reply to the given conversation.
191      * <p>
192      * This is only available when the type of the action is {@link #TYPE_TEXT_REPLY}.
193      */
194     @Nullable
getTextReply()195     public CharSequence getTextReply() {
196         return mTextReply;
197     }
198 
199     /**
200      * Returns the extended data related to this conversation action.
201      *
202      * <p><b>NOTE: </b>Do not modify this bundle.
203      */
204     @NonNull
getExtras()205     public Bundle getExtras() {
206         return mExtras;
207     }
208 
209     /** @hide */
toBuilder()210     public Builder toBuilder() {
211         return new Builder(mType)
212             .setTextReply(mTextReply)
213             .setAction(mAction)
214             .setConfidenceScore(mScore)
215             .setExtras(mExtras);
216     }
217 
218     /** Builder class to construct {@link ConversationAction}. */
219     public static final class Builder {
220         @Nullable
221         @ActionType
222         private String mType;
223         @Nullable
224         private RemoteAction mAction;
225         @Nullable
226         private CharSequence mTextReply;
227         private float mScore;
228         @Nullable
229         private Bundle mExtras;
230 
Builder(@onNull @ctionType String actionType)231         public Builder(@NonNull @ActionType String actionType) {
232             mType = Objects.requireNonNull(actionType);
233         }
234 
235         /**
236          * Sets an action that may be performed on the given conversation.
237          */
238         @NonNull
setAction(@ullable RemoteAction action)239         public Builder setAction(@Nullable RemoteAction action) {
240             mAction = action;
241             return this;
242         }
243 
244         /**
245          * Sets a text reply that may be performed on the given conversation.
246          */
247         @NonNull
setTextReply(@ullable CharSequence textReply)248         public Builder setTextReply(@Nullable CharSequence textReply) {
249             mTextReply = textReply;
250             return this;
251         }
252 
253         /** Sets the confident score. */
254         @NonNull
setConfidenceScore(@loatRangefrom = 0, to = 1) float score)255         public Builder setConfidenceScore(@FloatRange(from = 0, to = 1) float score) {
256             mScore = score;
257             return this;
258         }
259 
260         /**
261          * Sets the extended data for the conversation action object.
262          */
263         @NonNull
setExtras(@ullable Bundle extras)264         public Builder setExtras(@Nullable Bundle extras) {
265             mExtras = extras;
266             return this;
267         }
268 
269         /** Builds the {@link ConversationAction} object. */
270         @NonNull
build()271         public ConversationAction build() {
272             return new ConversationAction(
273                     mType,
274                     mAction,
275                     mTextReply,
276                     mScore,
277                     mExtras == null ? Bundle.EMPTY : mExtras);
278         }
279     }
280 }
281