+ Add CarExtender to Notification

Bug: 18316420

Change-Id: Idd7a06c2271d62c603014038fbe5a0bbacb0ed78
This commit is contained in:
Zhen Yu Song
2014-11-14 15:34:39 -08:00
parent 5e0cd7768e
commit 9d5528ba9f
2 changed files with 428 additions and 0 deletions

View File

@@ -4767,6 +4767,37 @@ package android.app {
method public android.app.Notification.Builder setWhen(long);
}
public static final class Notification.CarExtender implements android.app.Notification.Extender {
ctor public Notification.CarExtender();
ctor public Notification.CarExtender(android.app.Notification);
method public android.app.Notification.Builder extend(android.app.Notification.Builder);
method public int getColor();
method public android.graphics.Bitmap getLargeIcon();
method public android.app.Notification.CarExtender.UnreadConversation getUnreadConversation();
method public android.app.Notification.CarExtender setColor(int);
method public android.app.Notification.CarExtender setLargeIcon(android.graphics.Bitmap);
method public android.app.Notification.CarExtender setUnreadConversation(android.app.Notification.CarExtender.UnreadConversation);
}
public static class Notification.CarExtender.Builder {
ctor public Notification.CarExtender.Builder(java.lang.String);
method public android.app.Notification.CarExtender.Builder addMessage(java.lang.String);
method public android.app.Notification.CarExtender.UnreadConversation build();
method public android.app.Notification.CarExtender.Builder setLatestTimestamp(long);
method public android.app.Notification.CarExtender.Builder setReadPendingIntent(android.app.PendingIntent);
method public android.app.Notification.CarExtender.Builder setReplyAction(android.app.PendingIntent, android.app.RemoteInput);
}
public static class Notification.CarExtender.UnreadConversation {
method public long getLatestTimestamp();
method public java.lang.String[] getMessages();
method public java.lang.String getParticipant();
method public java.lang.String[] getParticipants();
method public android.app.PendingIntent getReadPendingIntent();
method public android.app.RemoteInput getRemoteInput();
method public android.app.PendingIntent getReplyPendingIntent();
}
public static abstract interface Notification.Extender {
method public abstract android.app.Notification.Builder extend(android.app.Notification.Builder);
}

View File

@@ -5064,6 +5064,403 @@ public class Notification implements Parcelable
}
}
/**
* <p>Helper class to add Android Auto extensions to notifications. To create a notification
* with car extensions:
*
* <ol>
* <li>Create an {@link Notification.Builder}, setting any desired
* properties.
* <li>Create a {@link CarExtender}.
* <li>Set car-specific properties using the {@code add} and {@code set} methods of
* {@link CarExtender}.
* <li>Call {@link Notification.Builder#extend(Notification.Extender)}
* to apply the extensions to a notification.
* </ol>
*
* <pre class="prettyprint">
* Notification notification = new Notification.Builder(context)
* ...
* .extend(new CarExtender()
* .set*(...))
* .build();
* </pre>
*
* <p>Car extensions can be accessed on an existing notification by using the
* {@code CarExtender(Notification)} constructor, and then using the {@code get} methods
* to access values.
*/
public static final class CarExtender implements Extender {
private static final String TAG = "CarExtender";
private static final String EXTRA_CAR_EXTENDER = "android.car.EXTENSIONS";
private static final String EXTRA_LARGE_ICON = "large_icon";
private static final String EXTRA_CONVERSATION = "car_conversation";
private static final String EXTRA_COLOR = "app_color";
private Bitmap mLargeIcon;
private UnreadConversation mUnreadConversation;
private int mColor = Notification.COLOR_DEFAULT;
/**
* Create a {@link CarExtender} with default options.
*/
public CarExtender() {
}
/**
* Create a {@link CarExtender} from the CarExtender options of an existing Notification.
*
* @param notif The notification from which to copy options.
*/
public CarExtender(Notification notif) {
Bundle carBundle = notif.extras == null ?
null : notif.extras.getBundle(EXTRA_CAR_EXTENDER);
if (carBundle != null) {
mLargeIcon = carBundle.getParcelable(EXTRA_LARGE_ICON);
mColor = carBundle.getInt(EXTRA_COLOR, Notification.COLOR_DEFAULT);
Bundle b = carBundle.getBundle(EXTRA_CONVERSATION);
mUnreadConversation = UnreadConversation.getUnreadConversationFromBundle(b);
}
}
/**
* Apply car extensions to a notification that is being built. This is typically called by
* the {@link Notification.Builder#extend(Notification.Extender)}
* method of {@link Notification.Builder}.
*/
@Override
public Notification.Builder extend(Notification.Builder builder) {
Bundle carExtensions = new Bundle();
if (mLargeIcon != null) {
carExtensions.putParcelable(EXTRA_LARGE_ICON, mLargeIcon);
}
if (mColor != Notification.COLOR_DEFAULT) {
carExtensions.putInt(EXTRA_COLOR, mColor);
}
if (mUnreadConversation != null) {
Bundle b = mUnreadConversation.getBundleForUnreadConversation();
carExtensions.putBundle(EXTRA_CONVERSATION, b);
}
builder.getExtras().putBundle(EXTRA_CAR_EXTENDER, carExtensions);
return builder;
}
/**
* Sets the accent color to use when Android Auto presents the notification.
*
* Android Auto uses the color set with {@link Notification.Builder#setColor(int)}
* to accent the displayed notification. However, not all colors are acceptable in an
* automotive setting. This method can be used to override the color provided in the
* notification in such a situation.
*/
public CarExtender setColor(int color) {
mColor = color;
return this;
}
/**
* Gets the accent color.
*
* @see setColor
*/
public int getColor() {
return mColor;
}
/**
* Sets the large icon of the car notification.
*
* If no large icon is set in the extender, Android Auto will display the icon
* specified by {@link Notification.Builder#setLargeIcon(android.graphics.Bitmap)}
*
* @param largeIcon The large icon to use in the car notification.
* @return This object for method chaining.
*/
public CarExtender setLargeIcon(Bitmap largeIcon) {
mLargeIcon = largeIcon;
return this;
}
/**
* Gets the large icon used in this car notification, or null if no icon has been set.
*
* @return The large icon for the car notification.
* @see CarExtender#setLargeIcon
*/
public Bitmap getLargeIcon() {
return mLargeIcon;
}
/**
* Sets the unread conversation in a message notification.
*
* @param unreadConversation The unread part of the conversation this notification conveys.
* @return This object for method chaining.
*/
public CarExtender setUnreadConversation(UnreadConversation unreadConversation) {
mUnreadConversation = unreadConversation;
return this;
}
/**
* Returns the unread conversation conveyed by this notification.
* @see #setUnreadConversation(UnreadConversation)
*/
public UnreadConversation getUnreadConversation() {
return mUnreadConversation;
}
/**
* A class which holds the unread messages from a conversation.
*/
public static class UnreadConversation {
private static final String KEY_AUTHOR = "author";
private static final String KEY_TEXT = "text";
private static final String KEY_MESSAGES = "messages";
private static final String KEY_REMOTE_INPUT = "remote_input";
private static final String KEY_ON_REPLY = "on_reply";
private static final String KEY_ON_READ = "on_read";
private static final String KEY_PARTICIPANTS = "participants";
private static final String KEY_TIMESTAMP = "timestamp";
private final String[] mMessages;
private final RemoteInput mRemoteInput;
private final PendingIntent mReplyPendingIntent;
private final PendingIntent mReadPendingIntent;
private final String[] mParticipants;
private final long mLatestTimestamp;
UnreadConversation(String[] messages, RemoteInput remoteInput,
PendingIntent replyPendingIntent, PendingIntent readPendingIntent,
String[] participants, long latestTimestamp) {
mMessages = messages;
mRemoteInput = remoteInput;
mReadPendingIntent = readPendingIntent;
mReplyPendingIntent = replyPendingIntent;
mParticipants = participants;
mLatestTimestamp = latestTimestamp;
}
/**
* Gets the list of messages conveyed by this notification.
*/
public String[] getMessages() {
return mMessages;
}
/**
* Gets the remote input that will be used to convey the response to a message list, or
* null if no such remote input exists.
*/
public RemoteInput getRemoteInput() {
return mRemoteInput;
}
/**
* Gets the pending intent that will be triggered when the user replies to this
* notification.
*/
public PendingIntent getReplyPendingIntent() {
return mReplyPendingIntent;
}
/**
* Gets the pending intent that Android Auto will send after it reads aloud all messages
* in this object's message list.
*/
public PendingIntent getReadPendingIntent() {
return mReadPendingIntent;
}
/**
* Gets the participants in the conversation.
*/
public String[] getParticipants() {
return mParticipants;
}
/**
* Gets the firs participant in the conversation.
*/
public String getParticipant() {
return mParticipants.length > 0 ? mParticipants[0] : null;
}
/**
* Gets the timestamp of the conversation.
*/
public long getLatestTimestamp() {
return mLatestTimestamp;
}
Bundle getBundleForUnreadConversation() {
Bundle b = new Bundle();
String author = null;
if (mParticipants != null && mParticipants.length > 1) {
author = mParticipants[0];
}
Parcelable[] messages = new Parcelable[mMessages.length];
for (int i = 0; i < messages.length; i++) {
Bundle m = new Bundle();
m.putString(KEY_TEXT, mMessages[i]);
m.putString(KEY_AUTHOR, author);
messages[i] = m;
}
b.putParcelableArray(KEY_MESSAGES, messages);
if (mRemoteInput != null) {
b.putParcelable(KEY_REMOTE_INPUT, mRemoteInput);
}
b.putParcelable(KEY_ON_REPLY, mReplyPendingIntent);
b.putParcelable(KEY_ON_READ, mReadPendingIntent);
b.putStringArray(KEY_PARTICIPANTS, mParticipants);
b.putLong(KEY_TIMESTAMP, mLatestTimestamp);
return b;
}
static UnreadConversation getUnreadConversationFromBundle(Bundle b) {
if (b == null) {
return null;
}
Parcelable[] parcelableMessages = b.getParcelableArray(KEY_MESSAGES);
String[] messages = null;
if (parcelableMessages != null) {
String[] tmp = new String[parcelableMessages.length];
boolean success = true;
for (int i = 0; i < tmp.length; i++) {
if (!(parcelableMessages[i] instanceof Bundle)) {
success = false;
break;
}
tmp[i] = ((Bundle) parcelableMessages[i]).getString(KEY_TEXT);
if (tmp[i] == null) {
success = false;
break;
}
}
if (success) {
messages = tmp;
} else {
return null;
}
}
PendingIntent onRead = b.getParcelable(KEY_ON_READ);
PendingIntent onReply = b.getParcelable(KEY_ON_REPLY);
RemoteInput remoteInput = b.getParcelable(KEY_REMOTE_INPUT);
String[] participants = b.getStringArray(KEY_PARTICIPANTS);
if (participants == null || participants.length != 1) {
return null;
}
return new UnreadConversation(messages,
remoteInput,
onReply,
onRead,
participants, b.getLong(KEY_TIMESTAMP));
}
};
/**
* Builder class for {@link CarExtender.UnreadConversation} objects.
*/
public static class Builder {
private final List<String> mMessages = new ArrayList<String>();
private final String mParticipant;
private RemoteInput mRemoteInput;
private PendingIntent mReadPendingIntent;
private PendingIntent mReplyPendingIntent;
private long mLatestTimestamp;
/**
* Constructs a new builder for {@link CarExtender.UnreadConversation}.
*
* @param name The name of the other participant in the conversation.
*/
public Builder(String name) {
mParticipant = name;
}
/**
* Appends a new unread message to the list of messages for this conversation.
*
* The messages should be added from oldest to newest.
*
* @param message The text of the new unread message.
* @return This object for method chaining.
*/
public Builder addMessage(String message) {
mMessages.add(message);
return this;
}
/**
* Sets the pending intent and remote input which will convey the reply to this
* notification.
*
* @param pendingIntent The pending intent which will be triggered on a reply.
* @param remoteInput The remote input parcelable which will carry the reply.
* @return This object for method chaining.
*
* @see CarExtender.UnreadConversation#getRemoteInput
* @see CarExtender.UnreadConversation#getReplyPendingIntent
*/
public Builder setReplyAction(
PendingIntent pendingIntent, RemoteInput remoteInput) {
mRemoteInput = remoteInput;
mReplyPendingIntent = pendingIntent;
return this;
}
/**
* Sets the pending intent that will be sent once the messages in this notification
* are read.
*
* @param pendingIntent The pending intent to use.
* @return This object for method chaining.
*/
public Builder setReadPendingIntent(PendingIntent pendingIntent) {
mReadPendingIntent = pendingIntent;
return this;
}
/**
* Sets the timestamp of the most recent message in an unread conversation.
*
* If a messaging notification has been posted by your application and has not
* yet been cancelled, posting a later notification with the same id and tag
* but without a newer timestamp may result in Android Auto not displaying a
* heads up notification for the later notification.
*
* @param timestamp The timestamp of the most recent message in the conversation.
* @return This object for method chaining.
*/
public Builder setLatestTimestamp(long timestamp) {
mLatestTimestamp = timestamp;
return this;
}
/**
* Builds a new unread conversation object.
*
* @return The new unread conversation object.
*/
public UnreadConversation build() {
String[] messages = mMessages.toArray(new String[mMessages.size()]);
String[] participants = { mParticipant };
return new UnreadConversation(messages, mRemoteInput, mReplyPendingIntent,
mReadPendingIntent, participants, mLatestTimestamp);
}
}
}
/**
* Get an array of Notification objects from a parcelable array bundle field.
* Update the bundle to have a typed array so fetches in the future don't need