• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.people;
18 
19 import android.annotation.NonNull;
20 import android.app.Person;
21 import android.content.Intent;
22 import android.content.pm.LauncherApps;
23 import android.content.pm.ShortcutInfo;
24 import android.graphics.Bitmap;
25 import android.graphics.Canvas;
26 import android.graphics.drawable.BitmapDrawable;
27 import android.graphics.drawable.Drawable;
28 import android.graphics.drawable.Icon;
29 import android.net.Uri;
30 import android.os.Parcel;
31 import android.os.Parcelable;
32 import android.os.UserHandle;
33 
34 import java.util.ArrayList;
35 import java.util.List;
36 
37 /**
38  * The People Space tile contains all relevant information to render a tile in People Space: namely
39  * the data of any visible conversation notification associated, associated statuses, and the last
40  * interaction time.
41  *
42  * @hide
43  */
44 public class PeopleSpaceTile implements Parcelable {
45 
46     public static final int SHOW_CONVERSATIONS = 1 << 0;
47     public static final int BLOCK_CONVERSATIONS =  1 << 1;
48     public static final int SHOW_IMPORTANT_CONVERSATIONS = 1 << 2;
49     public static final int SHOW_STARRED_CONTACTS = 1 << 3;
50     public static final int SHOW_CONTACTS = 1 << 4;
51 
52     private String mId;
53     private CharSequence mUserName;
54     private Icon mUserIcon;
55     private UserHandle mUserHandle;
56     private Uri mContactUri;
57     private String mPackageName;
58     private String mBirthdayText;
59     private long mLastInteractionTimestamp;
60     private boolean mIsImportantConversation;
61     private String mNotificationKey;
62     private CharSequence mNotificationContent;
63     private CharSequence mNotificationSender;
64     private String mNotificationCategory;
65     private Uri mNotificationDataUri;
66     private int mMessagesCount;
67     private Intent mIntent;
68     private long mNotificationTimestamp;
69     private List<ConversationStatus> mStatuses;
70     private boolean mCanBypassDnd;
71     private boolean mIsPackageSuspended;
72     private boolean mIsUserQuieted;
73     private int mNotificationPolicyState;
74     private float mContactAffinity;
75 
PeopleSpaceTile(Builder b)76     private PeopleSpaceTile(Builder b) {
77         mId = b.mId;
78         mUserName = b.mUserName;
79         mUserIcon = b.mUserIcon;
80         mContactUri = b.mContactUri;
81         mUserHandle = b.mUserHandle;
82         mPackageName = b.mPackageName;
83         mBirthdayText = b.mBirthdayText;
84         mLastInteractionTimestamp = b.mLastInteractionTimestamp;
85         mIsImportantConversation = b.mIsImportantConversation;
86         mNotificationKey = b.mNotificationKey;
87         mNotificationContent = b.mNotificationContent;
88         mNotificationSender = b.mNotificationSender;
89         mNotificationCategory = b.mNotificationCategory;
90         mNotificationDataUri = b.mNotificationDataUri;
91         mMessagesCount = b.mMessagesCount;
92         mIntent = b.mIntent;
93         mNotificationTimestamp = b.mNotificationTimestamp;
94         mStatuses = b.mStatuses;
95         mCanBypassDnd = b.mCanBypassDnd;
96         mIsPackageSuspended = b.mIsPackageSuspended;
97         mIsUserQuieted = b.mIsUserQuieted;
98         mNotificationPolicyState = b.mNotificationPolicyState;
99         mContactAffinity = b.mContactAffinity;
100     }
101 
getId()102     public String getId() {
103         return mId;
104     }
105 
getUserName()106     public CharSequence getUserName() {
107         return mUserName;
108     }
109 
getUserIcon()110     public Icon getUserIcon() {
111         return mUserIcon;
112     }
113 
114     /** Returns the Uri associated with the user in Android Contacts database. */
getContactUri()115     public Uri getContactUri() {
116         return mContactUri;
117     }
118 
getUserHandle()119     public UserHandle getUserHandle() {
120         return mUserHandle;
121     }
122 
getPackageName()123     public String getPackageName() {
124         return mPackageName;
125     }
126 
getBirthdayText()127     public String getBirthdayText() {
128         return mBirthdayText;
129     }
130 
131     /** Returns the timestamp of the last interaction. */
getLastInteractionTimestamp()132     public long getLastInteractionTimestamp() {
133         return mLastInteractionTimestamp;
134     }
135 
136     /**
137      * Whether the conversation is important.
138      */
isImportantConversation()139     public boolean isImportantConversation() {
140         return mIsImportantConversation;
141     }
142 
143     /**
144      * If a notification is currently active that maps to the relevant shortcut ID, provides the
145      * associated notification's key.
146      */
getNotificationKey()147     public String getNotificationKey() {
148         return mNotificationKey;
149     }
150 
getNotificationContent()151     public CharSequence getNotificationContent() {
152         return mNotificationContent;
153     }
154 
getNotificationSender()155     public CharSequence getNotificationSender() {
156         return mNotificationSender;
157     }
158 
getNotificationCategory()159     public String getNotificationCategory() {
160         return mNotificationCategory;
161     }
162 
getNotificationDataUri()163     public Uri getNotificationDataUri() {
164         return mNotificationDataUri;
165     }
166 
getMessagesCount()167     public int getMessagesCount() {
168         return mMessagesCount;
169     }
170 
171     /**
172      * Provides an intent to launch. If present, we should manually launch the intent on tile
173      * click, rather than calling {@link android.content.pm.LauncherApps} to launch the shortcut ID.
174      *
175      * <p>This field should only be used if manually constructing a tile without an associated
176      * shortcut to launch (i.e. birthday tiles).
177      */
getIntent()178     public Intent getIntent() {
179         return mIntent;
180     }
181 
182     /** Returns the timestamp of the last notification. */
getNotificationTimestamp()183     public long getNotificationTimestamp() {
184         return mNotificationTimestamp;
185     }
186 
187     /** Returns the statuses associated with the tile. */
getStatuses()188     public List<ConversationStatus> getStatuses() {
189         return mStatuses;
190     }
191 
192     /**
193      * Whether the app associated with the conversation can bypass DND.
194      */
canBypassDnd()195     public boolean canBypassDnd() {
196         return mCanBypassDnd;
197     }
198 
199     /**
200      * Whether the app associated with the conversation is suspended.
201      */
isPackageSuspended()202     public boolean isPackageSuspended() {
203         return mIsPackageSuspended;
204     }
205 
206     /**
207      * Whether the user associated with the conversation is quieted.
208      */
isUserQuieted()209     public boolean isUserQuieted() {
210         return mIsUserQuieted;
211     }
212 
213     /**
214      * Returns the state of notifications for the conversation.
215      */
getNotificationPolicyState()216     public int getNotificationPolicyState() {
217         return mNotificationPolicyState;
218     }
219 
220     /**
221      * Returns the contact affinity (whether the contact is starred).
222      */
getContactAffinity()223     public float getContactAffinity() {
224         return mContactAffinity;
225     }
226 
227     /** Converts a {@link PeopleSpaceTile} into a {@link PeopleSpaceTile.Builder}. */
toBuilder()228     public Builder toBuilder() {
229         Builder builder =
230                 new Builder(mId, mUserName, mUserIcon, mIntent);
231         builder.setContactUri(mContactUri);
232         builder.setUserHandle(mUserHandle);
233         builder.setPackageName(mPackageName);
234         builder.setBirthdayText(mBirthdayText);
235         builder.setLastInteractionTimestamp(mLastInteractionTimestamp);
236         builder.setIsImportantConversation(mIsImportantConversation);
237         builder.setNotificationKey(mNotificationKey);
238         builder.setNotificationContent(mNotificationContent);
239         builder.setNotificationSender(mNotificationSender);
240         builder.setNotificationCategory(mNotificationCategory);
241         builder.setNotificationDataUri(mNotificationDataUri);
242         builder.setMessagesCount(mMessagesCount);
243         builder.setIntent(mIntent);
244         builder.setNotificationTimestamp(mNotificationTimestamp);
245         builder.setStatuses(mStatuses);
246         builder.setCanBypassDnd(mCanBypassDnd);
247         builder.setIsPackageSuspended(mIsPackageSuspended);
248         builder.setIsUserQuieted(mIsUserQuieted);
249         builder.setNotificationPolicyState(mNotificationPolicyState);
250         builder.setContactAffinity(mContactAffinity);
251         return builder;
252     }
253 
254     /** Builder to create a {@link PeopleSpaceTile}. */
255     public static class Builder {
256         private String mId;
257         private CharSequence mUserName;
258         private Icon mUserIcon;
259         private Uri mContactUri;
260         private UserHandle mUserHandle;
261         private String mPackageName;
262         private String mBirthdayText;
263         private long mLastInteractionTimestamp;
264         private boolean mIsImportantConversation;
265         private String mNotificationKey;
266         private CharSequence mNotificationContent;
267         private CharSequence mNotificationSender;
268         private String mNotificationCategory;
269         private Uri mNotificationDataUri;
270         private int mMessagesCount;
271         private Intent mIntent;
272         private long mNotificationTimestamp;
273         private List<ConversationStatus> mStatuses;
274         private boolean mCanBypassDnd;
275         private boolean mIsPackageSuspended;
276         private boolean mIsUserQuieted;
277         private int mNotificationPolicyState;
278         private float mContactAffinity;
279 
280         /** Builder for use only if a shortcut is not available for the tile. */
Builder(String id, CharSequence userName, Icon userIcon, Intent intent)281         public Builder(String id, CharSequence userName, Icon userIcon, Intent intent) {
282             mId = id;
283             mUserName = userName;
284             mUserIcon = userIcon;
285             mIntent = intent;
286             mPackageName = intent == null ? null : intent.getPackage();
287             mNotificationPolicyState = SHOW_CONVERSATIONS;
288         }
289 
Builder(ShortcutInfo info, LauncherApps launcherApps)290         public Builder(ShortcutInfo info, LauncherApps launcherApps) {
291             mId = info.getId();
292             mUserName = info.getLabel();
293             mUserIcon = convertDrawableToIcon(launcherApps.getShortcutIconDrawable(info, 0));
294             mUserHandle = info.getUserHandle();
295             mPackageName = info.getPackage();
296             mContactUri = getContactUri(info);
297             mNotificationPolicyState = SHOW_CONVERSATIONS;
298         }
299 
Builder(ConversationChannel channel, LauncherApps launcherApps)300         public Builder(ConversationChannel channel, LauncherApps launcherApps) {
301             ShortcutInfo info = channel.getShortcutInfo();
302             mId = info.getId();
303             mUserName = info.getLabel();
304             mUserIcon = convertDrawableToIcon(launcherApps.getShortcutIconDrawable(info, 0));
305             mUserHandle = info.getUserHandle();
306             mPackageName = info.getPackage();
307             mContactUri = getContactUri(info);
308             mStatuses = channel.getStatuses();
309             mLastInteractionTimestamp = channel.getLastEventTimestamp();
310             mIsImportantConversation = channel.getNotificationChannel() != null
311                     && channel.getNotificationChannel().isImportantConversation();
312             mCanBypassDnd = channel.getNotificationChannel() != null
313                     && channel.getNotificationChannel().canBypassDnd();
314             mNotificationPolicyState = SHOW_CONVERSATIONS;
315         }
316 
317         /** Returns the Contact's Uri if present. */
getContactUri(ShortcutInfo info)318         public Uri getContactUri(ShortcutInfo info) {
319             if (info.getPersons() == null || info.getPersons().length != 1) {
320                 return null;
321             }
322             // TODO(b/175584929): Update to use the Uri from PeopleService directly
323             Person person = info.getPersons()[0];
324             return person.getUri() == null ? null : Uri.parse(person.getUri());
325         }
326 
327         /** Sets the ID for the tile. */
setId(String id)328         public Builder setId(String id) {
329             mId = id;
330             return this;
331         }
332 
333         /** Sets the user name. */
setUserName(CharSequence userName)334         public Builder setUserName(CharSequence userName) {
335             mUserName = userName;
336             return this;
337         }
338 
339         /** Sets the icon shown for the user. */
setUserIcon(Icon userIcon)340         public Builder setUserIcon(Icon userIcon) {
341             mUserIcon = userIcon;
342             return this;
343         }
344 
345         /** Sets the Uri associated with the user in Android Contacts database. */
setContactUri(Uri uri)346         public Builder setContactUri(Uri uri) {
347             mContactUri = uri;
348             return this;
349         }
350 
351         /** Sets the associated {@code userHandle}. */
setUserHandle(UserHandle userHandle)352         public Builder setUserHandle(UserHandle userHandle) {
353             mUserHandle = userHandle;
354             return this;
355         }
356 
357         /** Sets the package shown that provided the information. */
setPackageName(String packageName)358         public Builder setPackageName(String packageName) {
359             mPackageName = packageName;
360             return this;
361         }
362 
363         /** Sets the status text. */
setBirthdayText(String birthdayText)364         public Builder setBirthdayText(String birthdayText) {
365             mBirthdayText = birthdayText;
366             return this;
367         }
368 
369         /** Sets the last interaction timestamp. */
setLastInteractionTimestamp(long lastInteractionTimestamp)370         public Builder setLastInteractionTimestamp(long lastInteractionTimestamp) {
371             mLastInteractionTimestamp = lastInteractionTimestamp;
372             return this;
373         }
374 
375         /** Sets whether the conversation is important. */
setIsImportantConversation(boolean isImportantConversation)376         public Builder setIsImportantConversation(boolean isImportantConversation) {
377             mIsImportantConversation = isImportantConversation;
378             return this;
379         }
380 
381         /** Sets the associated notification's key. */
setNotificationKey(String notificationKey)382         public Builder setNotificationKey(String notificationKey) {
383             mNotificationKey = notificationKey;
384             return this;
385         }
386 
387         /** Sets the associated notification's content. */
setNotificationContent(CharSequence notificationContent)388         public Builder setNotificationContent(CharSequence notificationContent) {
389             mNotificationContent = notificationContent;
390             return this;
391         }
392 
393         /** Sets the associated notification's sender. */
setNotificationSender(CharSequence notificationSender)394         public Builder setNotificationSender(CharSequence notificationSender) {
395             mNotificationSender = notificationSender;
396             return this;
397         }
398 
399         /** Sets the associated notification's category. */
setNotificationCategory(String notificationCategory)400         public Builder setNotificationCategory(String notificationCategory) {
401             mNotificationCategory = notificationCategory;
402             return this;
403         }
404 
405         /** Sets the associated notification's data URI. */
setNotificationDataUri(Uri notificationDataUri)406         public Builder setNotificationDataUri(Uri notificationDataUri) {
407             mNotificationDataUri = notificationDataUri;
408             return this;
409         }
410 
411         /** Sets the number of messages associated with the Tile. */
setMessagesCount(int messagesCount)412         public Builder setMessagesCount(int messagesCount) {
413             mMessagesCount = messagesCount;
414             return this;
415         }
416 
417         /** Sets an intent to launch on click. */
setIntent(Intent intent)418         public Builder setIntent(Intent intent) {
419             mIntent = intent;
420             return this;
421         }
422 
423         /** Sets the notification timestamp. */
setNotificationTimestamp(long notificationTimestamp)424         public Builder setNotificationTimestamp(long notificationTimestamp) {
425             mNotificationTimestamp = notificationTimestamp;
426             return this;
427         }
428 
429         /** Sets the statuses. */
setStatuses(List<ConversationStatus> statuses)430         public Builder setStatuses(List<ConversationStatus> statuses) {
431             mStatuses = statuses;
432             return this;
433         }
434 
435         /** Sets whether the conversation channel can bypass DND. */
setCanBypassDnd(boolean canBypassDnd)436         public Builder setCanBypassDnd(boolean canBypassDnd) {
437             mCanBypassDnd = canBypassDnd;
438             return this;
439         }
440 
441         /** Sets whether the package is suspended. */
setIsPackageSuspended(boolean isPackageSuspended)442         public Builder setIsPackageSuspended(boolean isPackageSuspended) {
443             mIsPackageSuspended = isPackageSuspended;
444             return this;
445         }
446 
447         /** Sets whether the user has been quieted. */
setIsUserQuieted(boolean isUserQuieted)448         public Builder setIsUserQuieted(boolean isUserQuieted) {
449             mIsUserQuieted = isUserQuieted;
450             return this;
451         }
452 
453         /** Sets the state of blocked notifications for the conversation. */
setNotificationPolicyState(int notificationPolicyState)454         public Builder setNotificationPolicyState(int notificationPolicyState) {
455             mNotificationPolicyState = notificationPolicyState;
456             return this;
457         }
458 
459         /** Sets the contact's affinity. */
setContactAffinity(float contactAffinity)460         public Builder setContactAffinity(float contactAffinity) {
461             mContactAffinity = contactAffinity;
462             return this;
463         }
464 
465         /** Builds a {@link PeopleSpaceTile}. */
466         @NonNull
build()467         public PeopleSpaceTile build() {
468             return new PeopleSpaceTile(this);
469         }
470     }
471 
PeopleSpaceTile(Parcel in)472     public PeopleSpaceTile(Parcel in) {
473         mId = in.readString();
474         mUserName = in.readCharSequence();
475         mUserIcon = in.readParcelable(Icon.class.getClassLoader());
476         mContactUri = in.readParcelable(Uri.class.getClassLoader());
477         mUserHandle = in.readParcelable(UserHandle.class.getClassLoader());
478         mPackageName = in.readString();
479         mBirthdayText = in.readString();
480         mLastInteractionTimestamp = in.readLong();
481         mIsImportantConversation = in.readBoolean();
482         mNotificationKey = in.readString();
483         mNotificationContent = in.readCharSequence();
484         mNotificationSender = in.readCharSequence();
485         mNotificationCategory = in.readString();
486         mNotificationDataUri = in.readParcelable(Uri.class.getClassLoader());
487         mMessagesCount = in.readInt();
488         mIntent = in.readParcelable(Intent.class.getClassLoader());
489         mNotificationTimestamp = in.readLong();
490         mStatuses = new ArrayList<>();
491         in.readParcelableList(mStatuses, ConversationStatus.class.getClassLoader());
492         mCanBypassDnd = in.readBoolean();
493         mIsPackageSuspended = in.readBoolean();
494         mIsUserQuieted = in.readBoolean();
495         mNotificationPolicyState = in.readInt();
496         mContactAffinity = in.readFloat();
497     }
498 
499     @Override
describeContents()500     public int describeContents() {
501         return 0;
502     }
503 
504     @Override
writeToParcel(Parcel dest, int flags)505     public void writeToParcel(Parcel dest, int flags) {
506         dest.writeString(mId);
507         dest.writeCharSequence(mUserName);
508         dest.writeParcelable(mUserIcon, flags);
509         dest.writeParcelable(mContactUri, flags);
510         dest.writeParcelable(mUserHandle, flags);
511         dest.writeString(mPackageName);
512         dest.writeString(mBirthdayText);
513         dest.writeLong(mLastInteractionTimestamp);
514         dest.writeBoolean(mIsImportantConversation);
515         dest.writeString(mNotificationKey);
516         dest.writeCharSequence(mNotificationContent);
517         dest.writeCharSequence(mNotificationSender);
518         dest.writeString(mNotificationCategory);
519         dest.writeParcelable(mNotificationDataUri, flags);
520         dest.writeInt(mMessagesCount);
521         dest.writeParcelable(mIntent, flags);
522         dest.writeLong(mNotificationTimestamp);
523         dest.writeParcelableList(mStatuses, flags);
524         dest.writeBoolean(mCanBypassDnd);
525         dest.writeBoolean(mIsPackageSuspended);
526         dest.writeBoolean(mIsUserQuieted);
527         dest.writeInt(mNotificationPolicyState);
528         dest.writeFloat(mContactAffinity);
529     }
530 
531     public static final @android.annotation.NonNull
532             Creator<PeopleSpaceTile> CREATOR = new Creator<PeopleSpaceTile>() {
533                 public PeopleSpaceTile createFromParcel(Parcel source) {
534                     return new PeopleSpaceTile(source);
535                 }
536                 public PeopleSpaceTile[] newArray(int size) {
537                     return new PeopleSpaceTile[size];
538                 }
539             };
540 
541     /** Converts {@code drawable} to a {@link Icon}. */
convertDrawableToIcon(Drawable drawable)542     public static Icon convertDrawableToIcon(Drawable drawable) {
543         if (drawable == null) {
544             return null;
545         }
546 
547         if (drawable instanceof BitmapDrawable) {
548             BitmapDrawable bitmapDrawable = (BitmapDrawable) drawable;
549             if (bitmapDrawable.getBitmap() != null) {
550                 return Icon.createWithBitmap(bitmapDrawable.getBitmap());
551             }
552         }
553 
554         Bitmap bitmap;
555         if (drawable.getIntrinsicWidth() <= 0 || drawable.getIntrinsicHeight() <= 0) {
556             bitmap = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888);
557             // Single color bitmap will be created of 1x1 pixel
558         } else {
559             bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(),
560                     drawable.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);
561         }
562 
563         Canvas canvas = new Canvas(bitmap);
564         drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
565         drawable.draw(canvas);
566         return Icon.createWithBitmap(bitmap);
567     }
568 }
569