blob: e11861f49be89c5610ed3f9797c615ac4b3de7c1 [file] [log] [blame]
/*
* Copyright (C) 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.app.people;
import android.annotation.NonNull;
import android.app.Person;
import android.content.Intent;
import android.content.pm.LauncherApps;
import android.content.pm.ShortcutInfo;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.Icon;
import android.net.Uri;
import android.os.Parcel;
import android.os.Parcelable;
import android.os.UserHandle;
import java.util.ArrayList;
import java.util.List;
/**
* The People Space tile contains all relevant information to render a tile in People Space: namely
* the data of any visible conversation notification associated, associated statuses, and the last
* interaction time.
*
* @hide
*/
public class PeopleSpaceTile implements Parcelable {
public static final int SHOW_CONVERSATIONS = 1 << 0;
public static final int BLOCK_CONVERSATIONS = 1 << 1;
public static final int SHOW_IMPORTANT_CONVERSATIONS = 1 << 2;
public static final int SHOW_STARRED_CONTACTS = 1 << 3;
public static final int SHOW_CONTACTS = 1 << 4;
private String mId;
private CharSequence mUserName;
private Icon mUserIcon;
private UserHandle mUserHandle;
private Uri mContactUri;
private String mPackageName;
private String mBirthdayText;
private long mLastInteractionTimestamp;
private boolean mIsImportantConversation;
private String mNotificationKey;
private CharSequence mNotificationContent;
private CharSequence mNotificationSender;
private String mNotificationCategory;
private Uri mNotificationDataUri;
private int mMessagesCount;
private Intent mIntent;
private long mNotificationTimestamp;
private List<ConversationStatus> mStatuses;
private boolean mCanBypassDnd;
private boolean mIsPackageSuspended;
private boolean mIsUserQuieted;
private int mNotificationPolicyState;
private float mContactAffinity;
private PeopleSpaceTile(Builder b) {
mId = b.mId;
mUserName = b.mUserName;
mUserIcon = b.mUserIcon;
mContactUri = b.mContactUri;
mUserHandle = b.mUserHandle;
mPackageName = b.mPackageName;
mBirthdayText = b.mBirthdayText;
mLastInteractionTimestamp = b.mLastInteractionTimestamp;
mIsImportantConversation = b.mIsImportantConversation;
mNotificationKey = b.mNotificationKey;
mNotificationContent = b.mNotificationContent;
mNotificationSender = b.mNotificationSender;
mNotificationCategory = b.mNotificationCategory;
mNotificationDataUri = b.mNotificationDataUri;
mMessagesCount = b.mMessagesCount;
mIntent = b.mIntent;
mNotificationTimestamp = b.mNotificationTimestamp;
mStatuses = b.mStatuses;
mCanBypassDnd = b.mCanBypassDnd;
mIsPackageSuspended = b.mIsPackageSuspended;
mIsUserQuieted = b.mIsUserQuieted;
mNotificationPolicyState = b.mNotificationPolicyState;
mContactAffinity = b.mContactAffinity;
}
public String getId() {
return mId;
}
public CharSequence getUserName() {
return mUserName;
}
public Icon getUserIcon() {
return mUserIcon;
}
/** Returns the Uri associated with the user in Android Contacts database. */
public Uri getContactUri() {
return mContactUri;
}
public UserHandle getUserHandle() {
return mUserHandle;
}
public String getPackageName() {
return mPackageName;
}
public String getBirthdayText() {
return mBirthdayText;
}
/** Returns the timestamp of the last interaction. */
public long getLastInteractionTimestamp() {
return mLastInteractionTimestamp;
}
/**
* Whether the conversation is important.
*/
public boolean isImportantConversation() {
return mIsImportantConversation;
}
/**
* If a notification is currently active that maps to the relevant shortcut ID, provides the
* associated notification's key.
*/
public String getNotificationKey() {
return mNotificationKey;
}
public CharSequence getNotificationContent() {
return mNotificationContent;
}
public CharSequence getNotificationSender() {
return mNotificationSender;
}
public String getNotificationCategory() {
return mNotificationCategory;
}
public Uri getNotificationDataUri() {
return mNotificationDataUri;
}
public int getMessagesCount() {
return mMessagesCount;
}
/**
* Provides an intent to launch. If present, we should manually launch the intent on tile
* click, rather than calling {@link android.content.pm.LauncherApps} to launch the shortcut ID.
*
* <p>This field should only be used if manually constructing a tile without an associated
* shortcut to launch (i.e. birthday tiles).
*/
public Intent getIntent() {
return mIntent;
}
/** Returns the timestamp of the last notification. */
public long getNotificationTimestamp() {
return mNotificationTimestamp;
}
/** Returns the statuses associated with the tile. */
public List<ConversationStatus> getStatuses() {
return mStatuses;
}
/**
* Whether the app associated with the conversation can bypass DND.
*/
public boolean canBypassDnd() {
return mCanBypassDnd;
}
/**
* Whether the app associated with the conversation is suspended.
*/
public boolean isPackageSuspended() {
return mIsPackageSuspended;
}
/**
* Whether the user associated with the conversation is quieted.
*/
public boolean isUserQuieted() {
return mIsUserQuieted;
}
/**
* Returns the state of notifications for the conversation.
*/
public int getNotificationPolicyState() {
return mNotificationPolicyState;
}
/**
* Returns the contact affinity (whether the contact is starred).
*/
public float getContactAffinity() {
return mContactAffinity;
}
/** Converts a {@link PeopleSpaceTile} into a {@link PeopleSpaceTile.Builder}. */
public Builder toBuilder() {
Builder builder =
new Builder(mId, mUserName, mUserIcon, mIntent);
builder.setContactUri(mContactUri);
builder.setUserHandle(mUserHandle);
builder.setPackageName(mPackageName);
builder.setBirthdayText(mBirthdayText);
builder.setLastInteractionTimestamp(mLastInteractionTimestamp);
builder.setIsImportantConversation(mIsImportantConversation);
builder.setNotificationKey(mNotificationKey);
builder.setNotificationContent(mNotificationContent);
builder.setNotificationSender(mNotificationSender);
builder.setNotificationCategory(mNotificationCategory);
builder.setNotificationDataUri(mNotificationDataUri);
builder.setMessagesCount(mMessagesCount);
builder.setIntent(mIntent);
builder.setNotificationTimestamp(mNotificationTimestamp);
builder.setStatuses(mStatuses);
builder.setCanBypassDnd(mCanBypassDnd);
builder.setIsPackageSuspended(mIsPackageSuspended);
builder.setIsUserQuieted(mIsUserQuieted);
builder.setNotificationPolicyState(mNotificationPolicyState);
builder.setContactAffinity(mContactAffinity);
return builder;
}
/** Builder to create a {@link PeopleSpaceTile}. */
public static class Builder {
private String mId;
private CharSequence mUserName;
private Icon mUserIcon;
private Uri mContactUri;
private UserHandle mUserHandle;
private String mPackageName;
private String mBirthdayText;
private long mLastInteractionTimestamp;
private boolean mIsImportantConversation;
private String mNotificationKey;
private CharSequence mNotificationContent;
private CharSequence mNotificationSender;
private String mNotificationCategory;
private Uri mNotificationDataUri;
private int mMessagesCount;
private Intent mIntent;
private long mNotificationTimestamp;
private List<ConversationStatus> mStatuses;
private boolean mCanBypassDnd;
private boolean mIsPackageSuspended;
private boolean mIsUserQuieted;
private int mNotificationPolicyState;
private float mContactAffinity;
/** Builder for use only if a shortcut is not available for the tile. */
public Builder(String id, CharSequence userName, Icon userIcon, Intent intent) {
mId = id;
mUserName = userName;
mUserIcon = userIcon;
mIntent = intent;
mPackageName = intent == null ? null : intent.getPackage();
mNotificationPolicyState = SHOW_CONVERSATIONS;
}
public Builder(ShortcutInfo info, LauncherApps launcherApps) {
mId = info.getId();
mUserName = info.getLabel();
mUserIcon = convertDrawableToIcon(launcherApps.getShortcutIconDrawable(info, 0));
mUserHandle = info.getUserHandle();
mPackageName = info.getPackage();
mContactUri = getContactUri(info);
mNotificationPolicyState = SHOW_CONVERSATIONS;
}
public Builder(ConversationChannel channel, LauncherApps launcherApps) {
ShortcutInfo info = channel.getShortcutInfo();
mId = info.getId();
mUserName = info.getLabel();
mUserIcon = convertDrawableToIcon(launcherApps.getShortcutIconDrawable(info, 0));
mUserHandle = info.getUserHandle();
mPackageName = info.getPackage();
mContactUri = getContactUri(info);
mStatuses = channel.getStatuses();
mLastInteractionTimestamp = channel.getLastEventTimestamp();
mIsImportantConversation = channel.getNotificationChannel() != null
&& channel.getNotificationChannel().isImportantConversation();
mCanBypassDnd = channel.getNotificationChannel() != null
&& channel.getNotificationChannel().canBypassDnd();
mNotificationPolicyState = SHOW_CONVERSATIONS;
}
/** Returns the Contact's Uri if present. */
public Uri getContactUri(ShortcutInfo info) {
if (info.getPersons() == null || info.getPersons().length != 1) {
return null;
}
// TODO(b/175584929): Update to use the Uri from PeopleService directly
Person person = info.getPersons()[0];
return person.getUri() == null ? null : Uri.parse(person.getUri());
}
/** Sets the ID for the tile. */
public Builder setId(String id) {
mId = id;
return this;
}
/** Sets the user name. */
public Builder setUserName(CharSequence userName) {
mUserName = userName;
return this;
}
/** Sets the icon shown for the user. */
public Builder setUserIcon(Icon userIcon) {
mUserIcon = userIcon;
return this;
}
/** Sets the Uri associated with the user in Android Contacts database. */
public Builder setContactUri(Uri uri) {
mContactUri = uri;
return this;
}
/** Sets the associated {@code userHandle}. */
public Builder setUserHandle(UserHandle userHandle) {
mUserHandle = userHandle;
return this;
}
/** Sets the package shown that provided the information. */
public Builder setPackageName(String packageName) {
mPackageName = packageName;
return this;
}
/** Sets the status text. */
public Builder setBirthdayText(String birthdayText) {
mBirthdayText = birthdayText;
return this;
}
/** Sets the last interaction timestamp. */
public Builder setLastInteractionTimestamp(long lastInteractionTimestamp) {
mLastInteractionTimestamp = lastInteractionTimestamp;
return this;
}
/** Sets whether the conversation is important. */
public Builder setIsImportantConversation(boolean isImportantConversation) {
mIsImportantConversation = isImportantConversation;
return this;
}
/** Sets the associated notification's key. */
public Builder setNotificationKey(String notificationKey) {
mNotificationKey = notificationKey;
return this;
}
/** Sets the associated notification's content. */
public Builder setNotificationContent(CharSequence notificationContent) {
mNotificationContent = notificationContent;
return this;
}
/** Sets the associated notification's sender. */
public Builder setNotificationSender(CharSequence notificationSender) {
mNotificationSender = notificationSender;
return this;
}
/** Sets the associated notification's category. */
public Builder setNotificationCategory(String notificationCategory) {
mNotificationCategory = notificationCategory;
return this;
}
/** Sets the associated notification's data URI. */
public Builder setNotificationDataUri(Uri notificationDataUri) {
mNotificationDataUri = notificationDataUri;
return this;
}
/** Sets the number of messages associated with the Tile. */
public Builder setMessagesCount(int messagesCount) {
mMessagesCount = messagesCount;
return this;
}
/** Sets an intent to launch on click. */
public Builder setIntent(Intent intent) {
mIntent = intent;
return this;
}
/** Sets the notification timestamp. */
public Builder setNotificationTimestamp(long notificationTimestamp) {
mNotificationTimestamp = notificationTimestamp;
return this;
}
/** Sets the statuses. */
public Builder setStatuses(List<ConversationStatus> statuses) {
mStatuses = statuses;
return this;
}
/** Sets whether the conversation channel can bypass DND. */
public Builder setCanBypassDnd(boolean canBypassDnd) {
mCanBypassDnd = canBypassDnd;
return this;
}
/** Sets whether the package is suspended. */
public Builder setIsPackageSuspended(boolean isPackageSuspended) {
mIsPackageSuspended = isPackageSuspended;
return this;
}
/** Sets whether the user has been quieted. */
public Builder setIsUserQuieted(boolean isUserQuieted) {
mIsUserQuieted = isUserQuieted;
return this;
}
/** Sets the state of blocked notifications for the conversation. */
public Builder setNotificationPolicyState(int notificationPolicyState) {
mNotificationPolicyState = notificationPolicyState;
return this;
}
/** Sets the contact's affinity. */
public Builder setContactAffinity(float contactAffinity) {
mContactAffinity = contactAffinity;
return this;
}
/** Builds a {@link PeopleSpaceTile}. */
@NonNull
public PeopleSpaceTile build() {
return new PeopleSpaceTile(this);
}
}
public PeopleSpaceTile(Parcel in) {
mId = in.readString();
mUserName = in.readCharSequence();
mUserIcon = in.readParcelable(Icon.class.getClassLoader());
mContactUri = in.readParcelable(Uri.class.getClassLoader());
mUserHandle = in.readParcelable(UserHandle.class.getClassLoader());
mPackageName = in.readString();
mBirthdayText = in.readString();
mLastInteractionTimestamp = in.readLong();
mIsImportantConversation = in.readBoolean();
mNotificationKey = in.readString();
mNotificationContent = in.readCharSequence();
mNotificationSender = in.readCharSequence();
mNotificationCategory = in.readString();
mNotificationDataUri = in.readParcelable(Uri.class.getClassLoader());
mMessagesCount = in.readInt();
mIntent = in.readParcelable(Intent.class.getClassLoader());
mNotificationTimestamp = in.readLong();
mStatuses = new ArrayList<>();
in.readParcelableList(mStatuses, ConversationStatus.class.getClassLoader());
mCanBypassDnd = in.readBoolean();
mIsPackageSuspended = in.readBoolean();
mIsUserQuieted = in.readBoolean();
mNotificationPolicyState = in.readInt();
mContactAffinity = in.readFloat();
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(mId);
dest.writeCharSequence(mUserName);
dest.writeParcelable(mUserIcon, flags);
dest.writeParcelable(mContactUri, flags);
dest.writeParcelable(mUserHandle, flags);
dest.writeString(mPackageName);
dest.writeString(mBirthdayText);
dest.writeLong(mLastInteractionTimestamp);
dest.writeBoolean(mIsImportantConversation);
dest.writeString(mNotificationKey);
dest.writeCharSequence(mNotificationContent);
dest.writeCharSequence(mNotificationSender);
dest.writeString(mNotificationCategory);
dest.writeParcelable(mNotificationDataUri, flags);
dest.writeInt(mMessagesCount);
dest.writeParcelable(mIntent, flags);
dest.writeLong(mNotificationTimestamp);
dest.writeParcelableList(mStatuses, flags);
dest.writeBoolean(mCanBypassDnd);
dest.writeBoolean(mIsPackageSuspended);
dest.writeBoolean(mIsUserQuieted);
dest.writeInt(mNotificationPolicyState);
dest.writeFloat(mContactAffinity);
}
public static final @android.annotation.NonNull
Creator<PeopleSpaceTile> CREATOR = new Creator<PeopleSpaceTile>() {
public PeopleSpaceTile createFromParcel(Parcel source) {
return new PeopleSpaceTile(source);
}
public PeopleSpaceTile[] newArray(int size) {
return new PeopleSpaceTile[size];
}
};
/** Converts {@code drawable} to a {@link Icon}. */
public static Icon convertDrawableToIcon(Drawable drawable) {
if (drawable == null) {
return null;
}
if (drawable instanceof BitmapDrawable) {
BitmapDrawable bitmapDrawable = (BitmapDrawable) drawable;
if (bitmapDrawable.getBitmap() != null) {
return Icon.createWithBitmap(bitmapDrawable.getBitmap());
}
}
Bitmap bitmap;
if (drawable.getIntrinsicWidth() <= 0 || drawable.getIntrinsicHeight() <= 0) {
bitmap = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888);
// Single color bitmap will be created of 1x1 pixel
} else {
bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(),
drawable.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);
}
Canvas canvas = new Canvas(bitmap);
drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
drawable.draw(canvas);
return Icon.createWithBitmap(bitmap);
}
}