diff options
Diffstat (limited to 'docs/html/training/auto/messaging/index.jd')
-rw-r--r-- | docs/html/training/auto/messaging/index.jd | 371 |
1 files changed, 245 insertions, 126 deletions
diff --git a/docs/html/training/auto/messaging/index.jd b/docs/html/training/auto/messaging/index.jd index 2405d83..70ac205 100644 --- a/docs/html/training/auto/messaging/index.jd +++ b/docs/html/training/auto/messaging/index.jd @@ -48,7 +48,7 @@ page.article=true </a> <p> - Staying connected through text messages is important to many drivers. Chat apps can let users + Staying connected through messages is important to many drivers. Chat apps can let users know if a child need to be picked up, or if a dinner location has been changed. Apps that provide sports information might tell the user who just won the big game, and let the user ask questions about other games being played. The Android framework enables messaging apps to extend their @@ -95,6 +95,90 @@ page.article=true has read or replied to a message. </ul> +<h3 id="#concepts">Concepts and Objects</h3> + +<p>Before you start designing your app, it's helpful to understand how Auto +handles messaging.</p> + +<p>Each individual chunk of communication is a <em>message</em>. A message is a +short length of text, suitable for the Auto device to read aloud. In a chat app, +this might be a single message from one person to another: <code>"Fitzy -- Jane +can't come to the ball, her youngest has the croup. :-( --Liz"</code> In a +sports app, a message might be a single bit of news about a game: <code>"Granger +scores for Harpies at 7 minutes in."</code></p> + +<p>A <em>conversation</em> is a group of messages that are all grouped together +in some way. Auto uses the conversation information to group the messages +together when presenting them to the user. In a chat app, a conversation might +be all the messages between the user and another person (for example, all +the messages back and forth between Darcy and Elizabeth). In a sports app, a +conversation might be all the messages about a particular game. Every message +belongs to a conversation, even if it's the only message in that conversation. +Each conversation has a <em>conversation name</em>. +The conversation name is used by Android Auto to +present the messages; it's up to your app to choose an appropriate conversation +name. In a chat app, the conversation name is usually the person your user is +talking to. +In a sports app, this might be the name of the teams playing in the game.</p> + +<p>The v4 support library defines an {@link +android.support.v4.app.NotificationCompat.CarExtender.UnreadConversation +UnreadConversation} object. This object holds all messages in a conversation +which have not yet been heard by the user. To give those messages to the user, +you attach that {@link +android.support.v4.app.NotificationCompat.CarExtender.UnreadConversation +UnreadConversation} to a notification. However, you do not attach messages to +the {@link +android.support.v4.app.NotificationCompat.CarExtender.UnreadConversation +UnreadConversation} directly. Instead, you must first set up an {@link +android.support.v4.app.NotificationCompat.CarExtender.UnreadConversation.Builder +UnreadConversation.Builder} object for the conversation. The messages are added to the builder, +then when you are ready to send the messages, you use the builder to create the +actual {@link +android.support.v4.app.NotificationCompat.CarExtender.UnreadConversation +UnreadConversation} and attach the {@link +android.support.v4.app.NotificationCompat.CarExtender.UnreadConversation +UnreadConversation} to the notification.</p> + +<p class="note"><strong>Note:</strong> When Auto presents messages to the +user, it uses the notification <em>tag</em> and <em>ID</em> to determine which conversation the +messages belong to. It is important to use the same tag and ID for all messages in +a conversation, and to not use that tag for other conversations.</p> + +<h3 id="#workflow">Workflow</h3> + +<p>This section describes how the mobile device interacts with Auto to present +messages to the user.</p> + +<ol> + +<li>The app receives a message that it wants to pass on to the user. It attaches +the message to an {@link +android.support.v4.app.NotificationCompat.CarExtender.UnreadConversation +UnreadConversation} object and attaches it to a notification. That notification +is associated with a {@link +android.support.v4.app.NotificationCompat.CarExtender CarExtender} object, which +indicates that the notification can be handled by Android Auto.</li> + +<li>The app posts the notification. The Android notification framework passes the +message to Auto. Auto uses the notification tag and ID to determine which conversation +the message belongs to, and presents the message to the user in an appropriate +way.</li> + +<li>When the user listens to the message, Auto triggers the app's message heard +pending intent. The app should discard the {@link +android.support.v4.app.NotificationCompat.CarExtender.UnreadConversation +UnreadConversation} object and its builder at this time, since the messages +contained in those objects have been heard by the user.</li> + +<li>If the user sends a reply, Auto triggers the app's "message reply" intent and +attaches a transcript of the user's response. The app can take appropriate +action, based on the app's logic. For example, a chat app might interpret the +reply as a message to go to the other conversation participants, while a sports +app might try to interpret the "reply" as a request for other information +("What's the score in the Sharks game?").</li> + +</ol> <h2 id="#manifest">Configure Your Manifest</h2> @@ -104,7 +188,6 @@ page.article=true section describes what changes to make to your manifest to support messaging for Auto devices. </p> - <h3 id="manifest-messaging">Declare Auto messaging support</h3> <p> @@ -159,26 +242,28 @@ page.article=true <pre> <application> ... - <receiver android:name="<em>.MyMessageReadReceiver</em>"> + <receiver android:name=".MyMessageHeardReceiver"> <intent-filter> - <action android:name="<em>com.myapp.messagingservice.ACTION_MESSAGE_HEARD</em>"/> + <action android:name="com.myapp.messagingservice.MY_ACTION_MESSAGE_HEARD"/> </intent-filter> </receiver> - <receiver android:name="<em>.MyMessageReplyReceiver</em>"> + <receiver android:name=".MyMessageReplyReceiver"> <intent-filter> - <action android:name="<em>com.myapp.messagingservice.ACTION_MESSAGE_REPLY</em>"/> + <action android:name="com.myapp.messagingservice.MY_ACTION_MESSAGE_REPLY"/> </intent-filter> </receiver> ... </application> </pre> -<p> - The definition of the {@link android.content.BroadcastReceiver} classes shown in this example - is discussed in <a href="#handle_actions">Handle User Actions</a>. -</p> - +<p> In this example, <code>"MyMessageReadReceiver"</code> and +<code>"MyMessageReplyReceiver"</code> are the names of the {@link +android.content.BroadcastReceiver} subclasses you define to handle the +intents. You can choose whatever you like as the action names, but it's best +to prepend your package name to ensure that the action names are unique. For +more information about handling actions, see <a href="#handle_actions">Handle +User Actions</a>. </p> <h2 id="support-lib">Import Support Library for Messaging</h3> @@ -199,7 +284,7 @@ page.article=true <pre> dependencies { ... - compile 'com.android.support:support-v4:21.0.+' + compile 'com.android.support:support-v4:21.0.2' } </pre> @@ -240,79 +325,6 @@ dependencies { provide the content of messages in those conversations. </p> - -<h3 id="build_conversation">Build message conversations</h4> - -<p> - Messaging notifications for Auto organize messages into conversations using the {@link - android.support.v4.app.NotificationCompat.CarExtender.UnreadConversation} class, - that represents an unread or new - portion of a conversation from a particular sender. It contains a list of messages from the - sender. -</p> - -<p> - Use the {@link android.support.v4.app.NotificationCompat.CarExtender.UnreadConversation.Builder} class to create an unread conversation object, - as shown in the following example code: -</p> - -<pre> -// Build a RemoteInput for receiving voice input in a Car Notification -RemoteInput remoteInput = new RemoteInput.Builder(EXTRA_VOICE_REPLY) - .setLabel(getApplicationContext().getString(R.string.notification_reply)) - .build(); - -// Create an unread conversation object to organize a group of messages -// from a particular sender. -UnreadConversation.Builder unreadConvBuilder = - new UnreadConversation.Builder(participantName) - .setReadPendingIntent(msgHeardPendingIntent) - .setReplyAction(replyPendingIntent, remoteInput); -</pre> - -<p> - This conversation object includes a {@link android.app.PendingIntent}, which allows the Auto - device to signal your app that the conversation has been read by the Auto user. The construction - of this intent is discussed in the <a href="#conversation-intents">Creating conversation read and - reply intents</a> section. -</p> - -<p> - If your app supports replying to a conversation, you must call the {@link android.support.v4.app.NotificationCompat.CarExtender.UnreadConversation.Builder#setReplyAction setReplyAction()} - method and provide a pending intent to pass that user action back to your app. The - {@link android.support.v4.app.NotificationCompat.CarExtender.UnreadConversation} - object you create must also include a {@link - android.support.v4.app.RemoteInput} object. When the Auto user - receiving this conversation speaks a reply, the remote input objects lets your app get a text - version of the voice reply. -</p> - - -<h4 id="conversation-messages">Associate messages with conversations</h4> - -<p> - Messages provided for Auto must be associated with a conversation using the - {@link android.support.v4.app.NotificationCompat.CarExtender.UnreadConversation} - class. The following code example shows how - to associate individual messages with a conversation object. -</p> - -<pre> -// Note: Add messages from oldest to newest to the UnreadConversation.Builder -for (Iterator<String> messages = conversation.getMessages().iterator(); - messages.hasNext(); ) { - String message = messages.next(); - unreadConvBuilder.addMessage(message); -} -</pre> - -<p> - When a new message arrives in a particular conversation, your app should check if there is - already a conversation object for that particular conversation. If there is, associate the new - message with the existing conversation instead of building a new one. -</p> - - <h4 id="conversation-intents">Create conversation read and reply intents</h4> <p> @@ -323,28 +335,27 @@ for (Iterator<String> messages = conversation.getMessages().iterator(); <p> The following example code demonstrates how to define a {@link android.app.PendingIntent} to let - your app know if a conversation was listened to by the Auto user: + your app know if a conversation was read to the Auto user: </p> <pre> Intent msgHeardIntent = new Intent() .addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES) - .setAction(<em>com.myapp.messagingservice.ACTION_MESSAGE_HEARD</em>) - .putExtra("conversation_id", <em>conversationId</em>); + .setAction("com.myapp.messagingservice.MY_ACTION_MESSAGE_HEARD") + .putExtra("conversation_id", thisConversationId); PendingIntent msgHeardPendingIntent = PendingIntent.getBroadcast(getApplicationContext(), - <em>conversationId</em>, + thisConversationId, msgHeardIntent, PendingIntent.FLAG_UPDATE_CURRENT); </pre> -<p> - In this example, {@code conversationId} is an integer that identifies the current conversation. - The value of {@link android.content.Intent#setAction setAction()} is an intent filter identifier for heard messages which is - defined in your app manifest, as shown in <a href="#manifest-intent">Define read and reply intent - filters</a>. -</p> +<p>In this example, {@code thisConversationId} is an integer that identifies the +current conversation. The value of {@link android.content.Intent#setAction +Intent.setAction()} is the intent filter identifier for heard messages which you +defined in your app manifest, as shown in <a href="#manifest-intent">Define read +and reply intent filters</a>. </p> <p> If your app supports replying to conversations, you also create a {@link @@ -356,22 +367,79 @@ PendingIntent msgHeardPendingIntent = <pre> Intent msgReplyIntent = new Intent() .addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES) - .setAction(<em>com.myapp.messagingservice.ACTION_MESSAGE_REPLY</em>) - .putExtra("conversation_id", <em>conversationId</em>); + .setAction("com.myapp.messagingservice.MY_ACTION_MESSAGE_REPLY") + .putExtra("conversation_id", thisConversationId); PendingIntent msgReplyPendingIntent = PendingIntent.getBroadcast( getApplicationContext(), - <em>conversationId</em>, + thisConversationId, msgReplyIntent, PendingIntent.FLAG_UPDATE_CURRENT); </pre> +<p> Once again, {@code thisConversationId} is an integer that uniquely identifies +this conversation, and the value you pass to {@link +android.content.Intent#setAction Intent.setAction()} is the intent filter +identifier you defined for replies in your app manifest. </p> + +<h3 id="build_conversation">Set up the conversation builder</h4> + +<p> + Messaging notifications for Auto organize messages into conversations using the {@link + android.support.v4.app.NotificationCompat.CarExtender.UnreadConversation} class, + that represents an unread or new + portion of a conversation from a particular sender. It contains a list of messages from the + sender. +</p> + <p> - Once again, {@code conversationId} is an integer that uniquely identifies this conversation. The - value of {@link android.content.Intent#setAction setAction()} is an intent filter identifier for replies which is defined in your - app manifest, as shown in <a href="#manifest-intent">Define read and reply intent filters</a>. + You generally do not configure the {@link + android.support.v4.app.NotificationCompat.CarExtender.UnreadConversation UnreadConversation} + directly. Instead, you configure an + {@link android.support.v4.app.NotificationCompat.CarExtender.UnreadConversation.Builder + UnreadConversation.Builder} with the information about the conversation, + as shown in the following example code. </p> +<pre> +// Build a RemoteInput for receiving voice input in a Car Notification +RemoteInput remoteInput = new RemoteInput.Builder(MY_VOICE_REPLY_KEY) + .setLabel(getApplicationContext().getString(R.string.notification_reply)) + .build(); + +// Create an unread conversation object to organize a group of messages +// from a particular sender. +UnreadConversation.Builder unreadConvBuilder = + new UnreadConversation.Builder(conversationName) + .setReadPendingIntent(msgHeardPendingIntent) + .setReplyAction(msgReplyPendingIntent, remoteInput); +</pre> + +<p class="note"> + <strong>Note:</strong> You won't actually create the {@link + android.support.v4.app.NotificationCompat.CarExtender.UnreadConversation + UnreadConversation} until you are almost ready to send the message. +</p> + +<p> + This conversation object includes a {@link android.app.PendingIntent}, which allows the Auto + device to signal your app that the conversation has been read by the Auto user. The construction + of this intent is discussed in the <a href="#conversation-intents">Creating conversation read and + reply intents</a> section. +</p> + +<p> + If your app supports replying to a conversation, you must call the + {@link android.support.v4.app.NotificationCompat.CarExtender.UnreadConversation.Builder#setReplyAction + UnreadConversation.Builder.setReplyAction()} + method and provide a pending intent to pass that user action back to your app. The + {@link android.support.v4.app.NotificationCompat.CarExtender.UnreadConversation + UnreadConversation} + object you create must also include a {@link + android.support.v4.app.RemoteInput} object. When the Auto user + receiving this conversation speaks a reply, the remote input objects lets your app get a text + version of the voice reply. +</p> <h3 id="sending_messages">Sending Messages</h4> @@ -381,49 +449,99 @@ PendingIntent msgReplyPendingIntent = PendingIntent.getBroadcast( </p> <p>First, add the message to the {@link -android.support.v4.app.NotificationCompat.CarExtender.UnreadConversation.Builder} -for this conversation, and update its timestamp:</p> +android.support.v4.app.NotificationCompat.CarExtender.UnreadConversation.Builder +UnreadConversation.Builder} for this conversation, and update its timestamp:</p> <pre> -unreadConvBuilder.addMessage(<em>messageString</em>) - .setLatestTimestamp(<em>currentTimestamp</em>); +unreadConvBuilder.addMessage(messageString) + .setLatestTimestamp(currentTimestamp); </pre> -<p>Then create a {@link android.support.v4.app.NotificationCompat.Builder} -object that you'll use to build the actual notification. You'll need to use the +<p class="note"><strong>Note:</strong> If you are sending several messages at +once, add them to the {@link +android.support.v4.app.NotificationCompat.CarExtender.UnreadConversation.Builder +UnreadConversation.Builder} in order, from oldest to newest.</p> + +<p>Then create the {@link android.support.v4.app.NotificationCompat.Builder +NotificationCompat.Builder} +object that builds the actual notification. You need to use the pending intents you created in the previous step.</p> <pre> NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(getApplicationContext()) - .setSmallIcon(R.drawable.<em>notification_icon</em>) - .setLargeIcon(<em>icon_bitmap</em>) - .setContentText(<em>messageString</em>) - .setWhen(<em>currentTimestamp</em>) - .setContentTitle(<em>participant_name</em>) - .setContentIntent(msgHeardPendingIntent); - + .setSmallIcon(smallIconResourceID) + .setLargeIcon(largeIconBitmap); </pre> +<dl> + <dt><code>smallIconResourceID</code></dt> + <dd>The resource ID of a small icon to use for the conversation. This is + typically a generic icon for the messaging app.</dd> + + <dt><code>largeIconBitmap</code></dt> + <dd>A {@link android.graphics.Bitmap} of a large version of the icon. This + is typically a conversation-specific graphic. For example, if this is a + chat app, the large icon would be a picture of the person the user is + chatting with.</dd> + + <dt><code>messageString</code></dt> + <dd>The text of the message you want to send. (If you are sending several + messages at once, concatenate them into a single string, with the oldest + message first.)</dd> + + <dt><code>currentTimestamp</code></dt> + <dd>The message timestamp. (If you are sending several messages at once, + use the timestamp of the most recent message.)</dd> + + <dt><code>conversationName</code></dt> + + <dd>The name you chose for this conversation (for example, the name of the + person the user is chatting with). This should be the same conversation + name you used when you created the {@link +android.support.v4.app.NotificationCompat.CarExtender.UnreadConversation.Builder + UnreadConversation.Builder}.</dd> + + <dt><code>msgHeardPendingIntent</code></dt> + <dd>The pending intent object you created in + <a href="#conversation-intents">Create conversation read and reply + intents</a>.</dd> +</dl> + + <p>You'll also need to extend the {@link -android.support.v4.app.NotificationCompat.Builder} with the {@link -android.support.v4.app.NotificationCompat.CarExtender}. This is where you -actually create the {@link android.support.v4.app.NotificationCompat.CarExtender.UnreadConversation} object using the builder you +android.support.v4.app.NotificationCompat.Builder NotificationCompat.Builder} with the {@link +android.support.v4.app.NotificationCompat.CarExtender CarExtender}. This is where you +actually create the +{@link android.support.v4.app.NotificationCompat.CarExtender.UnreadConversation +UnreadConversation} object using the builder you just created, and attach it to the {@link -android.support.v4.app.NotificationCompat.CarExtender}:</p> +android.support.v4.app.NotificationCompat.CarExtender CarExtender}:</p> <pre> notificationBuilder.extend(new CarExtender() .setUnreadConversation(unreadConvBuilder.build()); </pre> +<p class="note"><strong>Note:</strong> If you wish, you can set an override icon +or color for the {@link android.support.v4.app.NotificationCompat.CarExtender +CarExtender} by calling {@link +android.support.v4.app.NotificationCompat.CarExtender#setLargeIcon +setLargeIcon()} or {@link +android.support.v4.app.NotificationCompat.CarExtender#setColor setColor()}. The +override icon or color is used when the notification is handled by a car, and +has no effect if the notification is handled on the Android device. This is +useful if the notification's default icon or color are not suitable for the +car's display.</p> + <p>Once you've done all this, you use your app's {@link android.support.v4.app.NotificationManagerCompat} to send the notification:</p> <pre> NotificationManagerCompat msgNotificationManager = NotificationManagerCompat.from(context); -msgNotificationManager.notify(<em>notificationId</em>, notificationBuilder.build()); +msgNotificationManager.notify(notificationTag, + notificationId, notificationBuilder.build()); </pre> <h2 id="handle_actions">Handle User Actions</h2> @@ -431,7 +549,7 @@ msgNotificationManager.notify(<em>notificationId</em>, notificationBuilder.build <p> When your create and dispatch a notification for messaging, you specify intents to be triggered when the Auto user hears the message and when the user dictates a reply. Your app indicates to - the Android framework that it handles these intends by registering them through it's manifest, as + the Android framework that it handles these intends by registering them through its manifest, as discussed in <a href="#manifest-intent">Define read and reply intent filters</a>. </p> @@ -461,7 +579,7 @@ msgNotificationManager.notify(<em>notificationId</em>, notificationBuilder.build </p> <pre> -public class MessageHeardReceiver extends BroadcastReceiver { +public class MyMessageHeardReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { @@ -469,7 +587,7 @@ public class MessageHeardReceiver extends BroadcastReceiver { // If you set up the intent as described in // "Create conversation read and reply intents", // you can get the conversation ID by calling: - int conversationId = intent.getIntExtra("conversation_id", -1); + int thisConversationId = intent.getIntExtra("conversation_id", -1); // Remove the notification to indicate it has been read // and update the list of unread conversations in your app. @@ -479,7 +597,8 @@ public class MessageHeardReceiver extends BroadcastReceiver { <p> Once a notification is read, your app can remove it by calling - {@link android.support.v4.app.NotificationManagerCompat#cancel} with the notification ID. + {@link android.support.v4.app.NotificationManagerCompat#cancel + NotificationManagerCompat.cancel()} with the notification ID. Within your app, you should mark the messages provided in the notification as read. </p> @@ -505,7 +624,7 @@ public class MessageHeardReceiver extends BroadcastReceiver { </p> <pre> - public class MessageReplyReceiver extends BroadcastReceiver { + public class MyMessageReplyReceiver extends BroadcastReceiver { @Override @@ -513,7 +632,7 @@ public class MessageHeardReceiver extends BroadcastReceiver { // If you set up the intent as described in // "Create conversation read and reply intents", // you can get the conversation ID by calling: - int conversationId = intent.getIntExtra("conversation_id", -1). + int thisConversationId = intent.getIntExtra("conversation_id", -1). } @@ -527,7 +646,7 @@ public class MessageHeardReceiver extends BroadcastReceiver { Bundle remoteInput = RemoteInput.getResultsFromIntent(intent); if (remoteInput != null) { - return remoteInput.getCharSequence("extra_voice_reply"); + return remoteInput.getCharSequence(MY_VOICE_REPLY_KEY); } return null; } |