1 /*
2  * Copyright (C) 2021 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.app.smartspace;
18 
19 import android.annotation.NonNull;
20 import android.annotation.Nullable;
21 import android.annotation.SuppressLint;
22 import android.annotation.SystemApi;
23 import android.app.PendingIntent;
24 import android.content.Intent;
25 import android.graphics.drawable.Icon;
26 import android.os.Bundle;
27 import android.os.Parcel;
28 import android.os.Parcelable;
29 import android.os.UserHandle;
30 import android.text.TextUtils;
31 
32 import java.util.Objects;
33 
34 /**
35  * A {@link SmartspaceAction} represents an action which can be taken by a user by tapping on either
36  * the title, the subtitle or on the icon. Supported instances are Intents, PendingIntents or a
37  * ShortcutInfo (by putting the ShortcutInfoId in the bundle). These actions can be called from
38  * another process or within the client process.
39  *
40  * Clients can also receive conditional Intents/PendingIntents in the extras bundle which are
41  * supposed to be fired when the conditions are met. For example, a user can invoke a dismiss/block
42  * action on a game score card but the intention is to only block the team and not the entire
43  * feature.
44  *
45  * @hide
46  */
47 @SystemApi
48 public final class SmartspaceAction implements Parcelable {
49 
50     private static final String TAG = "SmartspaceAction";
51 
52     /** A unique Id of this {@link SmartspaceAction}. */
53     @NonNull
54     private final String mId;
55 
56     /** An Icon which can be displayed in the UI. */
57     @Nullable
58     private final Icon mIcon;
59 
60     /** Title associated with an action. */
61     @NonNull
62     private final CharSequence mTitle;
63 
64     /** Subtitle associated with an action. */
65     @Nullable
66     private final CharSequence mSubtitle;
67 
68     @Nullable
69     private final CharSequence mContentDescription;
70 
71     @Nullable
72     private final PendingIntent mPendingIntent;
73 
74     @Nullable
75     private final Intent mIntent;
76 
77     @Nullable
78     private final UserHandle mUserHandle;
79 
80     @Nullable
81     private Bundle mExtras;
82 
SmartspaceAction(Parcel in)83     SmartspaceAction(Parcel in) {
84         mId = in.readString();
85         mIcon = in.readTypedObject(Icon.CREATOR);
86         mTitle = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
87         mSubtitle = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
88         mContentDescription = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
89         mPendingIntent = in.readTypedObject(PendingIntent.CREATOR);
90         mIntent = in.readTypedObject(Intent.CREATOR);
91         mUserHandle = in.readTypedObject(UserHandle.CREATOR);
92         mExtras = in.readBundle();
93     }
94 
SmartspaceAction( @onNull String id, @Nullable Icon icon, @NonNull CharSequence title, @Nullable CharSequence subtitle, @Nullable CharSequence contentDescription, @Nullable PendingIntent pendingIntent, @Nullable Intent intent, @Nullable UserHandle userHandle, @Nullable Bundle extras)95     private SmartspaceAction(
96             @NonNull String id,
97             @Nullable Icon icon,
98             @NonNull CharSequence title,
99             @Nullable CharSequence subtitle,
100             @Nullable CharSequence contentDescription,
101             @Nullable PendingIntent pendingIntent,
102             @Nullable Intent intent,
103             @Nullable UserHandle userHandle,
104             @Nullable Bundle extras) {
105         mId = Objects.requireNonNull(id);
106         mIcon = icon;
107         mTitle = Objects.requireNonNull(title);
108         mSubtitle = subtitle;
109         mContentDescription = contentDescription;
110         mPendingIntent = pendingIntent;
111         mIntent = intent;
112         mUserHandle = userHandle;
113         mExtras = extras;
114     }
115 
116     /**
117      * Returns the unique id of this object.
118      */
getId()119     public @NonNull String getId() {
120         return mId;
121     }
122 
123     /**
124      * Returns an icon representing the action.
125      */
getIcon()126     public @Nullable Icon getIcon() {
127         return mIcon;
128     }
129 
130     /**
131      * Returns a title representing the action.
132      */
getTitle()133     public @NonNull CharSequence getTitle() {
134         return mTitle;
135     }
136 
137     /**
138      * Returns a subtitle representing the action.
139      */
getSubtitle()140     public @Nullable CharSequence getSubtitle() {
141         return mSubtitle;
142     }
143 
144     /**
145      * Returns a content description representing the action.
146      */
getContentDescription()147     public @Nullable CharSequence getContentDescription() {
148         return mContentDescription;
149     }
150 
151     /**
152      * Returns the action intent.
153      */
getPendingIntent()154     public @Nullable PendingIntent getPendingIntent() {
155         return mPendingIntent;
156     }
157 
158     /**
159      * Returns the intent.
160      */
getIntent()161     public @Nullable Intent getIntent() {
162         return mIntent;
163     }
164 
165     /**
166      * Returns the user handle.
167      */
getUserHandle()168     public @Nullable UserHandle getUserHandle() {
169         return mUserHandle;
170     }
171 
172     /**
173      * Returns the extra bundle for this object.
174      */
175     @SuppressLint("NullableCollection")
getExtras()176     public @Nullable Bundle getExtras() {
177         return mExtras;
178     }
179 
180     @Override
equals(Object o)181     public boolean equals(Object o) {
182         if (this == o) return true;
183         if (!(o instanceof SmartspaceAction)) return false;
184         SmartspaceAction that = (SmartspaceAction) o;
185         return mId.equals(that.mId);
186     }
187 
188     @Override
hashCode()189     public int hashCode() {
190         return Objects.hash(mId);
191     }
192 
193     @Override
describeContents()194     public int describeContents() {
195         return 0;
196     }
197 
198     @Override
writeToParcel(@onNull Parcel out, int flags)199     public void writeToParcel(@NonNull Parcel out, int flags) {
200         out.writeString(mId);
201         out.writeTypedObject(mIcon, flags);
202         TextUtils.writeToParcel(mTitle, out, flags);
203         TextUtils.writeToParcel(mSubtitle, out, flags);
204         TextUtils.writeToParcel(mContentDescription, out, flags);
205         out.writeTypedObject(mPendingIntent, flags);
206         out.writeTypedObject(mIntent, flags);
207         out.writeTypedObject(mUserHandle, flags);
208         out.writeBundle(mExtras);
209     }
210 
211     @Override
toString()212     public String toString() {
213         return "SmartspaceAction{"
214                 + "mId='" + mId + '\''
215                 + ", mIcon=" + mIcon
216                 + ", mTitle=" + mTitle
217                 + ", mSubtitle=" + mSubtitle
218                 + ", mContentDescription=" + mContentDescription
219                 + ", mPendingIntent=" + mPendingIntent
220                 + ", mIntent=" + mIntent
221                 + ", mUserHandle=" + mUserHandle
222                 + ", mExtras=" + mExtras
223                 + '}';
224     }
225 
226     public static final @NonNull Creator<SmartspaceAction> CREATOR =
227             new Creator<SmartspaceAction>() {
228                 public SmartspaceAction createFromParcel(Parcel in) {
229                     return new SmartspaceAction(in);
230                 }
231                 public SmartspaceAction[] newArray(int size) {
232                     return new SmartspaceAction[size];
233                 }
234             };
235 
236     /**
237      * A builder for Smartspace action object.
238      *
239      * @hide
240      */
241     @SystemApi
242     public static final class Builder {
243         @NonNull
244         private String mId;
245 
246         @Nullable
247         private Icon mIcon;
248 
249         @NonNull
250         private CharSequence mTitle;
251 
252         @Nullable
253         private CharSequence mSubtitle;
254 
255         @Nullable
256         private CharSequence mContentDescription;
257 
258         @Nullable
259         private PendingIntent mPendingIntent;
260 
261         @Nullable
262         private Intent mIntent;
263 
264         @Nullable
265         private UserHandle mUserHandle;
266 
267         @Nullable
268         private Bundle mExtras;
269 
270         /**
271          * Id and title are required.
272          */
Builder(@onNull String id, @NonNull String title)273         public Builder(@NonNull String id, @NonNull String title) {
274             mId = Objects.requireNonNull(id);
275             mTitle = Objects.requireNonNull(title);
276         }
277 
278         /**
279          * Sets the icon.
280          */
281         @NonNull
setIcon( @ullable Icon icon)282         public Builder setIcon(
283                 @Nullable Icon icon) {
284             mIcon = icon;
285             return this;
286         }
287 
288         /**
289          * Sets the subtitle.
290          */
291         @NonNull
setSubtitle( @ullable CharSequence subtitle)292         public Builder setSubtitle(
293                 @Nullable CharSequence subtitle) {
294             mSubtitle = subtitle;
295             return this;
296         }
297 
298         /**
299          * Sets the content description.
300          */
301         @NonNull
setContentDescription( @ullable CharSequence contentDescription)302         public Builder setContentDescription(
303                 @Nullable CharSequence contentDescription) {
304             mContentDescription = contentDescription;
305             return this;
306         }
307 
308         /**
309          * Sets the pending intent.
310          */
311         @NonNull
setPendingIntent(@ullable PendingIntent pendingIntent)312         public Builder setPendingIntent(@Nullable PendingIntent pendingIntent) {
313             mPendingIntent = pendingIntent;
314             return this;
315         }
316 
317         /**
318          * Sets the user handle.
319          */
320         @NonNull
setUserHandle(@ullable UserHandle userHandle)321         public Builder setUserHandle(@Nullable UserHandle userHandle) {
322             mUserHandle = userHandle;
323             return this;
324         }
325 
326         /**
327          * Sets the intent.
328          */
329         @NonNull
setIntent(@ullable Intent intent)330         public Builder setIntent(@Nullable Intent intent) {
331             mIntent = intent;
332             return this;
333         }
334 
335         /**
336          * Sets the extra.
337          */
338         @NonNull
setExtras(@uppressLintR) @ullable Bundle extras)339         public Builder setExtras(@SuppressLint("NullableCollection") @Nullable Bundle extras) {
340             mExtras = extras;
341             return this;
342         }
343 
344         /**
345          * Builds a new SmartspaceAction instance.
346          *
347          * @throws IllegalStateException if no target is set
348          */
349         @NonNull
build()350         public SmartspaceAction build() {
351             if (mIcon != null) {
352                 mIcon.convertToAshmem();
353             }
354 
355             return new SmartspaceAction(mId, mIcon, mTitle, mSubtitle, mContentDescription,
356                     mPendingIntent, mIntent, mUserHandle, mExtras);
357         }
358     }
359 }
360