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