From fc737def026d88cdf3e21a3368317f039973cd66 Mon Sep 17 00:00:00 2001 From: Alex Hills Date: Wed, 23 Mar 2016 17:33:02 -0400 Subject: [PATCH] Adds support for MessagingStyle This change adds support for the new MessagingStyle, which supports a fully back-and-forth messaging/chat experience within the notification display itself. Bug:28043958 Change-Id: Ibb9c2a0784f028d8cf01bd3cee4fecc5f72d68cd --- api/current.txt | 30 ++ api/system-current.txt | 30 ++ api/test-current.txt | 30 ++ core/java/android/app/Notification.java | 375 +++++++++++++++++++++++- 4 files changed, 464 insertions(+), 1 deletion(-) diff --git a/api/current.txt b/api/current.txt index 18388b2d3a7c4..f651020c40335 100644 --- a/api/current.txt +++ b/api/current.txt @@ -4915,6 +4915,7 @@ package android.app { field public static final int DEFAULT_LIGHTS = 4; // 0x4 field public static final int DEFAULT_SOUND = 1; // 0x1 field public static final int DEFAULT_VIBRATE = 2; // 0x2 + field public static final java.lang.String EXTRA_ALLOW_GENERATED_REPLIES = "android.allowGeneratedReplies"; field public static final java.lang.String EXTRA_BACKGROUND_IMAGE_URI = "android.backgroundImageUri"; field public static final java.lang.String EXTRA_BIG_TEXT = "android.bigText"; field public static final java.lang.String EXTRA_CHRONOMETER_COUNTS_DOWN = "android.chronometerCountsDown"; @@ -4923,12 +4924,14 @@ package android.app { field public static final java.lang.String EXTRA_LARGE_ICON = "android.largeIcon"; field public static final java.lang.String EXTRA_LARGE_ICON_BIG = "android.largeIcon.big"; field public static final java.lang.String EXTRA_MEDIA_SESSION = "android.mediaSession"; + field public static final java.lang.String EXTRA_MESSAGES = "android.messages"; field public static final java.lang.String EXTRA_PEOPLE = "android.people"; field public static final java.lang.String EXTRA_PICTURE = "android.picture"; field public static final java.lang.String EXTRA_PROGRESS = "android.progress"; field public static final java.lang.String EXTRA_PROGRESS_INDETERMINATE = "android.progressIndeterminate"; field public static final java.lang.String EXTRA_PROGRESS_MAX = "android.progressMax"; field public static final java.lang.String EXTRA_REMOTE_INPUT_HISTORY = "android.remoteInputHistory"; + field public static final java.lang.String EXTRA_SELF_DISPLAY_NAME = "android.selfDisplayName"; field public static final java.lang.String EXTRA_SHOW_CHRONOMETER = "android.showChronometer"; field public static final java.lang.String EXTRA_SHOW_WHEN = "android.showWhen"; field public static final java.lang.String EXTRA_SMALL_ICON = "android.icon"; @@ -4937,6 +4940,7 @@ package android.app { field public static final java.lang.String EXTRA_TEMPLATE = "android.template"; field public static final java.lang.String EXTRA_TEXT = "android.text"; field public static final java.lang.String EXTRA_TEXT_LINES = "android.textLines"; + field public static final java.lang.String EXTRA_THREAD_TITLE = "android.threadTitle"; field public static final java.lang.String EXTRA_TITLE = "android.title"; field public static final java.lang.String EXTRA_TITLE_BIG = "android.title.big"; field public static final int FLAG_AUTO_CANCEL = 16; // 0x10 @@ -5174,6 +5178,32 @@ package android.app { method public android.app.Notification.MediaStyle setShowActionsInCompactView(int...); } + public static class Notification.MessagingStyle extends android.app.Notification.Style { + ctor public Notification.MessagingStyle(java.lang.CharSequence); + method public android.app.Notification.MessagingStyle addMessage(java.lang.CharSequence, long, java.lang.CharSequence); + method public android.app.Notification.MessagingStyle addMessage(android.app.Notification.MessagingStyle.Message); + method public boolean getAllowGeneratedReplies(); + method public java.lang.CharSequence getConversationTitle(); + method public java.util.List getMessages(); + method public java.lang.CharSequence getUserDisplayName(); + method public android.app.Notification.MessagingStyle setAllowGeneratedReplies(boolean); + method public android.app.Notification.MessagingStyle setConversationTitle(java.lang.CharSequence); + field public static final int MAXIMUM_RETAINED_MESSAGES = 25; // 0x19 + } + + public static final class Notification.MessagingStyle.Message implements android.os.Parcelable { + ctor public Notification.MessagingStyle.Message(java.lang.CharSequence, long, java.lang.CharSequence); + method public int describeContents(); + method public java.lang.String getDataMimeType(); + method public android.net.Uri getDataUri(); + method public java.lang.CharSequence getSender(); + method public java.lang.CharSequence getText(); + method public long getTimestamp(); + method public android.app.Notification.MessagingStyle.Message setData(java.lang.String, android.net.Uri); + method public void writeToParcel(android.os.Parcel, int); + field public static final android.os.Parcelable.Creator CREATOR; + } + public static abstract class Notification.Style { ctor public Notification.Style(); method public android.app.Notification build(); diff --git a/api/system-current.txt b/api/system-current.txt index 051ed04fcdbc1..b817927a01b97 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -5048,6 +5048,7 @@ package android.app { field public static final int DEFAULT_LIGHTS = 4; // 0x4 field public static final int DEFAULT_SOUND = 1; // 0x1 field public static final int DEFAULT_VIBRATE = 2; // 0x2 + field public static final java.lang.String EXTRA_ALLOW_GENERATED_REPLIES = "android.allowGeneratedReplies"; field public static final java.lang.String EXTRA_BACKGROUND_IMAGE_URI = "android.backgroundImageUri"; field public static final java.lang.String EXTRA_BIG_TEXT = "android.bigText"; field public static final java.lang.String EXTRA_CHRONOMETER_COUNTS_DOWN = "android.chronometerCountsDown"; @@ -5056,12 +5057,14 @@ package android.app { field public static final java.lang.String EXTRA_LARGE_ICON = "android.largeIcon"; field public static final java.lang.String EXTRA_LARGE_ICON_BIG = "android.largeIcon.big"; field public static final java.lang.String EXTRA_MEDIA_SESSION = "android.mediaSession"; + field public static final java.lang.String EXTRA_MESSAGES = "android.messages"; field public static final java.lang.String EXTRA_PEOPLE = "android.people"; field public static final java.lang.String EXTRA_PICTURE = "android.picture"; field public static final java.lang.String EXTRA_PROGRESS = "android.progress"; field public static final java.lang.String EXTRA_PROGRESS_INDETERMINATE = "android.progressIndeterminate"; field public static final java.lang.String EXTRA_PROGRESS_MAX = "android.progressMax"; field public static final java.lang.String EXTRA_REMOTE_INPUT_HISTORY = "android.remoteInputHistory"; + field public static final java.lang.String EXTRA_SELF_DISPLAY_NAME = "android.selfDisplayName"; field public static final java.lang.String EXTRA_SHOW_CHRONOMETER = "android.showChronometer"; field public static final java.lang.String EXTRA_SHOW_WHEN = "android.showWhen"; field public static final java.lang.String EXTRA_SMALL_ICON = "android.icon"; @@ -5070,6 +5073,7 @@ package android.app { field public static final java.lang.String EXTRA_TEMPLATE = "android.template"; field public static final java.lang.String EXTRA_TEXT = "android.text"; field public static final java.lang.String EXTRA_TEXT_LINES = "android.textLines"; + field public static final java.lang.String EXTRA_THREAD_TITLE = "android.threadTitle"; field public static final java.lang.String EXTRA_TITLE = "android.title"; field public static final java.lang.String EXTRA_TITLE_BIG = "android.title.big"; field public static final int FLAG_AUTO_CANCEL = 16; // 0x10 @@ -5307,6 +5311,32 @@ package android.app { method public android.app.Notification.MediaStyle setShowActionsInCompactView(int...); } + public static class Notification.MessagingStyle extends android.app.Notification.Style { + ctor public Notification.MessagingStyle(java.lang.CharSequence); + method public android.app.Notification.MessagingStyle addMessage(java.lang.CharSequence, long, java.lang.CharSequence); + method public android.app.Notification.MessagingStyle addMessage(android.app.Notification.MessagingStyle.Message); + method public boolean getAllowGeneratedReplies(); + method public java.lang.CharSequence getConversationTitle(); + method public java.util.List getMessages(); + method public java.lang.CharSequence getUserDisplayName(); + method public android.app.Notification.MessagingStyle setAllowGeneratedReplies(boolean); + method public android.app.Notification.MessagingStyle setConversationTitle(java.lang.CharSequence); + field public static final int MAXIMUM_RETAINED_MESSAGES = 25; // 0x19 + } + + public static final class Notification.MessagingStyle.Message implements android.os.Parcelable { + ctor public Notification.MessagingStyle.Message(java.lang.CharSequence, long, java.lang.CharSequence); + method public int describeContents(); + method public java.lang.String getDataMimeType(); + method public android.net.Uri getDataUri(); + method public java.lang.CharSequence getSender(); + method public java.lang.CharSequence getText(); + method public long getTimestamp(); + method public android.app.Notification.MessagingStyle.Message setData(java.lang.String, android.net.Uri); + method public void writeToParcel(android.os.Parcel, int); + field public static final android.os.Parcelable.Creator CREATOR; + } + public static abstract class Notification.Style { ctor public Notification.Style(); method public android.app.Notification build(); diff --git a/api/test-current.txt b/api/test-current.txt index fe7b4d38a9e83..d4ed2e912b4b1 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -4915,6 +4915,7 @@ package android.app { field public static final int DEFAULT_LIGHTS = 4; // 0x4 field public static final int DEFAULT_SOUND = 1; // 0x1 field public static final int DEFAULT_VIBRATE = 2; // 0x2 + field public static final java.lang.String EXTRA_ALLOW_GENERATED_REPLIES = "android.allowGeneratedReplies"; field public static final java.lang.String EXTRA_BACKGROUND_IMAGE_URI = "android.backgroundImageUri"; field public static final java.lang.String EXTRA_BIG_TEXT = "android.bigText"; field public static final java.lang.String EXTRA_CHRONOMETER_COUNTS_DOWN = "android.chronometerCountsDown"; @@ -4923,12 +4924,14 @@ package android.app { field public static final java.lang.String EXTRA_LARGE_ICON = "android.largeIcon"; field public static final java.lang.String EXTRA_LARGE_ICON_BIG = "android.largeIcon.big"; field public static final java.lang.String EXTRA_MEDIA_SESSION = "android.mediaSession"; + field public static final java.lang.String EXTRA_MESSAGES = "android.messages"; field public static final java.lang.String EXTRA_PEOPLE = "android.people"; field public static final java.lang.String EXTRA_PICTURE = "android.picture"; field public static final java.lang.String EXTRA_PROGRESS = "android.progress"; field public static final java.lang.String EXTRA_PROGRESS_INDETERMINATE = "android.progressIndeterminate"; field public static final java.lang.String EXTRA_PROGRESS_MAX = "android.progressMax"; field public static final java.lang.String EXTRA_REMOTE_INPUT_HISTORY = "android.remoteInputHistory"; + field public static final java.lang.String EXTRA_SELF_DISPLAY_NAME = "android.selfDisplayName"; field public static final java.lang.String EXTRA_SHOW_CHRONOMETER = "android.showChronometer"; field public static final java.lang.String EXTRA_SHOW_WHEN = "android.showWhen"; field public static final java.lang.String EXTRA_SMALL_ICON = "android.icon"; @@ -4937,6 +4940,7 @@ package android.app { field public static final java.lang.String EXTRA_TEMPLATE = "android.template"; field public static final java.lang.String EXTRA_TEXT = "android.text"; field public static final java.lang.String EXTRA_TEXT_LINES = "android.textLines"; + field public static final java.lang.String EXTRA_THREAD_TITLE = "android.threadTitle"; field public static final java.lang.String EXTRA_TITLE = "android.title"; field public static final java.lang.String EXTRA_TITLE_BIG = "android.title.big"; field public static final int FLAG_AUTO_CANCEL = 16; // 0x10 @@ -5174,6 +5178,32 @@ package android.app { method public android.app.Notification.MediaStyle setShowActionsInCompactView(int...); } + public static class Notification.MessagingStyle extends android.app.Notification.Style { + ctor public Notification.MessagingStyle(java.lang.CharSequence); + method public android.app.Notification.MessagingStyle addMessage(java.lang.CharSequence, long, java.lang.CharSequence); + method public android.app.Notification.MessagingStyle addMessage(android.app.Notification.MessagingStyle.Message); + method public boolean getAllowGeneratedReplies(); + method public java.lang.CharSequence getConversationTitle(); + method public java.util.List getMessages(); + method public java.lang.CharSequence getUserDisplayName(); + method public android.app.Notification.MessagingStyle setAllowGeneratedReplies(boolean); + method public android.app.Notification.MessagingStyle setConversationTitle(java.lang.CharSequence); + field public static final int MAXIMUM_RETAINED_MESSAGES = 25; // 0x19 + } + + public static final class Notification.MessagingStyle.Message implements android.os.Parcelable { + ctor public Notification.MessagingStyle.Message(java.lang.CharSequence, long, java.lang.CharSequence); + method public int describeContents(); + method public java.lang.String getDataMimeType(); + method public android.net.Uri getDataUri(); + method public java.lang.CharSequence getSender(); + method public java.lang.CharSequence getText(); + method public long getTimestamp(); + method public android.app.Notification.MessagingStyle.Message setData(java.lang.String, android.net.Uri); + method public void writeToParcel(android.os.Parcel, int); + field public static final android.os.Parcelable.Creator CREATOR; + } + public static abstract class Notification.Style { ctor public Notification.Style(); method public android.app.Notification build(); diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java index 8423de8827822..aee4ca7d899af 100644 --- a/core/java/android/app/Notification.java +++ b/core/java/android/app/Notification.java @@ -898,6 +898,34 @@ public class Notification implements Parcelable */ public static final String EXTRA_COMPACT_ACTIONS = "android.compactActions"; + /** + * {@link #extras} key: the username to be displayed for all messages sent by the user including + * direct replies + * {@link android.app.Notification.MessagingStyle} notification. + */ + public static final String EXTRA_SELF_DISPLAY_NAME = "android.selfDisplayName"; + + /** + * {@link #extras} key: a boolean describing whether the platform should automatically + * generate possible replies to + * {@link android.app.Notification.MessagingStyle.Message} objects provided by a + * {@link android.app.Notification.MessagingStyle} notification. + */ + public static final String EXTRA_ALLOW_GENERATED_REPLIES = "android.allowGeneratedReplies"; + + /** + * {@link #extras} key: a {@link String} to be displayed as the title to a thread represented by + * a {@link android.app.Notification.MessagingStyle} + */ + public static final String EXTRA_THREAD_TITLE = "android.threadTitle"; + + /** + * {@link #extras} key: an array of {@link android.app.Notification.MessagingStyle.Message} + * bundles provided by a + * {@link android.app.Notification.MessagingStyle} notification. + */ + public static final String EXTRA_MESSAGES = "android.messages"; + /** * {@link #extras} key: the user that built the notification. * @@ -3529,7 +3557,8 @@ public class Notification implements Parcelable private static Class getNotificationStyleClass(String templateClass) { Class[] classes = new Class[] { BigTextStyle.class, BigPictureStyle.class, InboxStyle.class, MediaStyle.class, - DecoratedCustomViewStyle.class, DecoratedMediaCustomViewStyle.class }; + DecoratedCustomViewStyle.class, DecoratedMediaCustomViewStyle.class, + MessagingStyle.class }; for (Class innerClass : classes) { if (templateClass.equals(innerClass.getName())) { return innerClass; @@ -4125,6 +4154,350 @@ public class Notification implements Parcelable } } + /** + * Helper class for generating large-format notifications that include multiple back-and-forth + * messages of varying types between any number of people. + * + *
+ * If the platform does not provide large-format notifications, this method has no effect. The + * user will always see the normal notification view. + *
+ * This class is a "rebuilder": It attaches to a Builder object and modifies its behavior, like + * so: + *
+     *
+     * Notification noti = new Notification.Builder()
+     *     .setContentTitle("2 new messages wtih " + sender.toString())
+     *     .setContentText(subject)
+     *     .setSmallIcon(R.drawable.new_message)
+     *     .setLargeIcon(aBitmap)
+     *     .setStyle(new Notification.MessagingStyle(resources.getString(R.string.reply_name))
+     *         .addMessage(messages[0].getText(), messages[0].getTime(), messages[0].getSender())
+     *         .addMessage(messages[1].getText(), messages[1].getTime(), messages[1].getSender()))
+     *     .build();
+     * 
+ */ + public static class MessagingStyle extends Style { + + /** + * The maximum number of messages that will be retained in the Notification itself (the + * number displayed is up to the platform). + */ + public static final int MAXIMUM_RETAINED_MESSAGES = 25; + + CharSequence mUserDisplayName; + CharSequence mConversationTitle; + boolean mAllowGeneratedReplies = true; + ArrayList mMessages = new ArrayList<>(); + + MessagingStyle() { + } + + /** + * @param userDisplayName the name to be displayed for any replies sent by the user before the + * posting app reposts the notification with those messages after they've been actually + * sent and in previous messages sent by the user added in + * {@link #addMessage(Notification.MessagingStyle.Message)} + */ + public MessagingStyle(CharSequence userDisplayName) { + mUserDisplayName = userDisplayName; + } + + /** + * Returns the name to be displayed for any replies sent by the user + */ + public CharSequence getUserDisplayName() { + return mUserDisplayName; + } + + /** + * Set whether the platform should automatically generate possible replies from messages. + * @param allowGeneratedReplies {@code true} to allow generated replies, {@code false} + * otherwise + * @return this object for method chaining + * The default value is {@code true} + */ + public MessagingStyle setAllowGeneratedReplies(boolean allowGeneratedReplies) { + mAllowGeneratedReplies = allowGeneratedReplies; + return this; + } + + /** + * Return whether the platform should automatically generate possible replies from messages. + */ + public boolean getAllowGeneratedReplies() { + return mAllowGeneratedReplies; + } + + /** + * Sets the title to be displayed on this conversation. This should only be used for + * group messaging and left unset for one-on-one conversations. + * @param conversationTitle + * @return this object for method chaining. + */ + public MessagingStyle setConversationTitle(CharSequence conversationTitle) { + mConversationTitle = conversationTitle; + return this; + } + + /** + * Return the title to be displayed on this conversation. Can be null and + * should be for one-on-one conversations + */ + public CharSequence getConversationTitle() { + return mConversationTitle; + } + + /** + * Adds a message for display by this notification. Convenience call for a simple + * {@link Message} in {@link #addMessage(Notification.MessagingStyle.Message)}. + * @param text A {@link CharSequence} to be displayed as the message content + * @param timestamp Time at which the message arrived + * @param sender A {@link CharSequence} to be used for displaying the name of the + * sender. Should be null for messages by the current user, in which case + * the platform will insert {@link #getUserDisplayName()}. + * Should be unique amongst all individuals in the conversation, and should be + * consistent during re-posts of the notification. + * + * @see Message#Message(CharSequence, long, CharSequence) + * + * @return this object for method chaining + */ + public MessagingStyle addMessage(CharSequence text, long timestamp, CharSequence sender) { + mMessages.add(new Message(text, timestamp, sender)); + if (mMessages.size() > MAXIMUM_RETAINED_MESSAGES) { + mMessages.remove(0); + } + return this; + } + + /** + * Adds a {@link Message} for display in this notification. + * @param message The {@link Message} to be displayed + * @return this object for method chaining + */ + public MessagingStyle addMessage(Message message) { + mMessages.add(message); + if (mMessages.size() > MAXIMUM_RETAINED_MESSAGES) { + mMessages.remove(0); + } + return this; + } + + /** + * Gets the list of {@code Message} objects that represent the notification + */ + public List getMessages() { + return mMessages; + } + + /** + * @hide + */ + @Override + public void addExtras(Bundle extras) { + super.addExtras(extras); + if (mUserDisplayName != null) { + extras.putCharSequence(EXTRA_SELF_DISPLAY_NAME, mUserDisplayName); + } + if (mConversationTitle != null) { + extras.putCharSequence(EXTRA_THREAD_TITLE, mConversationTitle); + } + extras.putBoolean(EXTRA_ALLOW_GENERATED_REPLIES, mAllowGeneratedReplies); + if (!mMessages.isEmpty()) { + extras.putParcelableArrayList(EXTRA_MESSAGES, mMessages); + } + } + + /** + * @hide + */ + @Override + protected void restoreFromExtras(Bundle extras) { + super.restoreFromExtras(extras); + + mMessages.clear(); + mUserDisplayName = extras.getString(EXTRA_SELF_DISPLAY_NAME); + mConversationTitle = extras.getString(EXTRA_THREAD_TITLE); + mAllowGeneratedReplies = extras.getBoolean(EXTRA_ALLOW_GENERATED_REPLIES, + mAllowGeneratedReplies); + List messages = extras.getParcelableArrayList(EXTRA_MESSAGES); + if (messages != null) { + mMessages.addAll(messages); + } + } + + /** + * @hide + */ + public RemoteViews makeBigContentView() { + // TODO handset to write implementation + RemoteViews contentView = getStandardView(mBuilder.getBigTextLayoutResource()); + + return contentView; + } + + public static final class Message implements Parcelable { + + private final CharSequence mText; + private final long mTimestamp; + private final CharSequence mSender; + + private String mDataMimeType; + private Uri mDataUri; + + /** + * Constructor + * @param text A {@link CharSequence} to be displayed as the message content + * @param timestamp Time at which the message arrived + * @param sender A {@link CharSequence} to be used for displaying the name of the + * sender. Should be null for messages by the current user, in which case + * the platform will insert {@link MessagingStyle#getUserDisplayName()}. + * Should be unique amongst all individuals in the conversation, and should be + * consistent during re-posts of the notification. + */ + public Message(CharSequence text, long timestamp, CharSequence sender){ + mText = text; + mTimestamp = timestamp; + mSender = sender; + } + + /** + * Sets a binary blob of data and an associated MIME type for a message. In the case + * where the platform doesn't support the MIME type, the original text provided in the + * constructor will be used. + * @param dataMimeType The MIME type of the content. See + * for the list of supported MIME + * types on Android and Android Wear. + * @param dataUri The uri containing the content whose type is given by the MIME type. + *

+ *

    + *
  1. Notification Listeners including the System UI need permission to access the + * data the Uri points to. The recommended ways to do this are:
  2. + *
  3. Store the data in your own ContentProvider, making sure that other apps have + * the correct permission to access your provider. The preferred mechanism for + * providing access is to use per-URI permissions which are temporary and only + * grant access to the receiving application. An easy way to create a + * ContentProvider like this is to use the FileProvider helper class.
  4. + *
  5. Use the system MediaStore. The MediaStore is primarily aimed at video, audio + * and image MIME types, however beginning with Android 3.0 (API level 11) it can + * also store non-media types (see MediaStore.Files for more info). Files can be + * inserted into the MediaStore using scanFile() after which a content:// style + * Uri suitable for sharing is passed to the provided onScanCompleted() callback. + * Note that once added to the system MediaStore the content is accessible to any + * app on the device.
  6. + *
+ * @return this object for method chaining + */ + public Message setData(String dataMimeType, Uri dataUri) { + mDataMimeType = dataMimeType; + mDataUri = dataUri; + return this; + } + + private Message(Parcel in) { + if (in.readInt() != 0) { + mText = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in); + } else { + mText = null; + } + mTimestamp = in.readLong(); + if (in.readInt() != 0) { + mSender = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in); + } else { + mSender = null; + } + if (in.readInt() != 0) { + mDataMimeType = in.readString(); + } + if (in.readInt() != 0) { + mDataUri = in.readParcelable(Uri.class.getClassLoader()); + } + } + + /** + * Get the text to be used for this message, or the fallback text if a type and content + * Uri have been set + */ + public CharSequence getText() { + return mText; + } + + /** + * Get the time at which this message arrived + */ + public long getTimestamp() { + return mTimestamp; + } + + /** + * Get the text used to display the contact's name in the messaging experience + */ + public CharSequence getSender() { + return mSender; + } + + /** + * Get the MIME type of the data pointed to by the Uri + */ + public String getDataMimeType() { + return mDataMimeType; + } + + /** + * Get the the Uri pointing to the content of the message. Can be null, in which case + * {@see #getText()} is used. + */ + public Uri getDataUri() { + return mDataUri; + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel out, int flags) { + if (mText != null) { + out.writeInt(1); + TextUtils.writeToParcel(mText, out, flags); + } else { + out.writeInt(0); + } + out.writeLong(mTimestamp); + if (mSender != null) { + out.writeInt(1); + TextUtils.writeToParcel(mSender, out, flags); + } else { + out.writeInt(0); + } + if (mDataMimeType != null) { + out.writeInt(1); + out.writeString(mDataMimeType); + } else { + out.writeInt(0); + } + if (mDataUri != null) { + out.writeInt(1); + out.writeParcelable(mDataUri, flags); + } else { + out.writeInt(0); + } + } + + public static final Parcelable.Creator CREATOR = + new Parcelable.Creator() { + public Message createFromParcel(Parcel in) { + return new Message(in); + } + public Message[] newArray(int size) { + return new Message[size]; + } + }; + } + } + /** * Helper class for generating large-format notifications that include a list of (up to 5) strings. *