diff --git a/api/current.txt b/api/current.txt index 5dbe3f32a6568..c45015307a227 100644 --- a/api/current.txt +++ b/api/current.txt @@ -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); } diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java index 860b9cc25d22c..87e744c057d64 100644 --- a/core/java/android/app/Notification.java +++ b/core/java/android/app/Notification.java @@ -5064,6 +5064,403 @@ public class Notification implements Parcelable } } + /** + *
Helper class to add Android Auto extensions to notifications. To create a notification + * with car extensions: + * + *
+ * Notification notification = new Notification.Builder(context) + * ... + * .extend(new CarExtender() + * .set*(...)) + * .build(); + *+ * + *
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