1page.title=Providing Messaging for Auto 2page.tags="auto", "car", "automotive", "messaging" 3page.article=true 4 5page.metaDescription=Learn how to extend your messaging app for use in Android Auto devices. 6page.image=auto/images/assets/icons/messaging_app_notifications.png 7 8@jd:body 9 10<div id="tb-wrapper"> 11<div id="tb"> 12 <h2>Dependencies and Prerequisites</h2> 13 <ul> 14 <li>Android 5.0 (API level 21) or higher</li> 15 </ul> 16 17 <h2>This class teaches you to:</h2> 18 19 <ul> 20 <li><a href="#overview">Provide Messaging Services</a></li> 21 <li><a href="#manifest">Configure Your Manifest</a></li> 22 <li><a href="#support-lib">Import Support Library for Messaging</a></li> 23 <li><a href="#messaging">Notify Users of Messages</a></li> 24 <li><a href="#handle_actions">Handle User Actions</a></li> 25 </ul> 26 27 <h2>Related Samples</h2> 28 29 <ul> 30 <li><a href="{@docRoot}samples/MessagingService/index.html"> 31 MessagingService</a></li> 32 </ul> 33 34 <h2>See Also</h2> 35 36 <ul> 37 <li><a href="{@docRoot}shareables/auto/AndroidAuto-messaging-apps.pdf"> 38 User Experience Guidelines: Messaging Apps</a></li> 39 <li><a href="{@docRoot}guide/topics/ui/notifiers/notifications.html"> 40 Notifications</a></li> 41 </ul> 42</div> 43</div> 44 45<a class="notice-developers-video wide" 46 href="https://www.youtube.com/watch?v=gSVLuaOTIPk"> 47<div> 48 <h3>Video</h3> 49 <p>DevBytes: Android Auto Messaging</p> 50</div> 51</a> 52 53<p> 54 Staying connected through messages is important to many drivers. Chat apps can let users 55 know if a child need to be picked up, or if a dinner location has been changed. 56 The Android framework enables messaging apps to extend their 57 services into car dashboards using a standard user interface that lets drivers keep their eyes 58 on the road. 59</p> 60 61<p> 62 Apps that support messaging can be extended to pass messaging notifications to Auto 63 dashboard systems, alerting them to new messages and allowing them to respond. You can configure 64 your messaging app to provide these services when an Android mobile device with your app 65 installed is connected to an Auto dashboard. Once connected, your app can provide text 66 information to users and allow them to respond. The Auto dashboard system handles displaying the 67 notification and the interface for replies. 68</p> 69 70<p> 71 This lesson assumes that you have built an app that displays messages to the user and receive the 72 user's replies, such as a chat app. It shows you how to extend your app to hand those messages 73 off to an Auto device for display and replies. 74</p> 75 76 77<h2 id="overview">Provide Messaging Services</h2> 78 79<p> 80 Messaging apps do not run directly on the Android dashboard hardware. They are installed on 81 a separate Android mobile device. When the mobile device is plugged into a dashboard, 82 the installed messaging apps can offer services for viewing and responding to messages 83 through the Auto user interface. 84</p> 85 86<p>To enable your app to provide messaging services for Auto devices:</p> 87 88<ul> 89 <li>Configure your app manifest to indicate that your app provides messaging services which are 90 compatible with Android Auto dashboard devices. 91 </li> 92 <li>Build and send a specific type of <a href= 93 "{@docRoot}guide/topics/ui/notifiers/notifications.html">notification</a> for display on Auto 94 devices. 95 </li> 96 <li>Configure your app to receive {@link android.content.Intent} objects that indicate a user 97 has read or replied to a message. 98</ul> 99 100<h3 id="concepts">Concepts and objects</h3> 101 102<p>Before you start designing your app, it's helpful to understand how Auto 103handles messaging.</p> 104 105<p>Each individual chunk of communication is a <em>message</em>. A message is a 106short length of text, suitable for the Auto device to read aloud. In a chat app, 107this might be a single message from one person to another: <code>"Fitzy -- Jane 108can't come to the ball, her youngest has the croup. :-( --Liz"</code>.</p> 109 110<p>A <em>conversation</em> is a group of messages that are all grouped together 111in some way. Auto uses the conversation information to group the messages 112together when presenting them to the user. In a chat app, a conversation might 113be all the messages between the user and another person (for example, all 114the messages back and forth between Darcy and Elizabeth). Every message 115belongs to a conversation, even if it's the only message in that conversation. 116Each conversation has a <em>conversation name</em>. 117The conversation name is used by Android Auto to 118present the messages; it's up to your app to choose an appropriate conversation 119name. In a chat app, the conversation name is usually the person your user is 120talking to.</p> 121 122<p>The v4 support library defines an {@link 123android.support.v4.app.NotificationCompat.CarExtender.UnreadConversation 124UnreadConversation} object. This object holds all messages in a conversation 125which have not yet been heard by the user. To give those messages to the user, 126you attach that {@link 127android.support.v4.app.NotificationCompat.CarExtender.UnreadConversation 128UnreadConversation} to a notification. However, you do not attach messages to 129the {@link 130android.support.v4.app.NotificationCompat.CarExtender.UnreadConversation 131UnreadConversation} directly. Instead, you must first set up an {@link 132android.support.v4.app.NotificationCompat.CarExtender.UnreadConversation.Builder 133UnreadConversation.Builder} object for the conversation. The messages are added to the builder, 134then when you are ready to send the messages, you use the builder to create the 135actual {@link 136android.support.v4.app.NotificationCompat.CarExtender.UnreadConversation 137UnreadConversation} and attach the {@link 138android.support.v4.app.NotificationCompat.CarExtender.UnreadConversation 139UnreadConversation} to the notification.</p> 140 141<p class="note"><strong>Note:</strong> When Auto presents messages to the 142user, it uses the notification <em>tag</em> and <em>ID</em> to determine which conversation the 143messages belong to. It is important to use the same tag and ID for all messages in 144a conversation, and to not use that tag for other conversations.</p> 145 146<h3 id="#workflow">Workflow</h3> 147 148<p>This section describes how the mobile device interacts with Auto to present 149messages to the user.</p> 150 151<ol> 152 153<li>The app receives a message that it wants to pass on to the user. It attaches 154the message to an {@link 155android.support.v4.app.NotificationCompat.CarExtender.UnreadConversation 156UnreadConversation} object and attaches it to a notification. That notification 157is associated with a {@link 158android.support.v4.app.NotificationCompat.CarExtender CarExtender} object, which 159indicates that the notification can be handled by Android Auto.</li> 160 161<li>The app posts the notification. The Android notification framework passes the 162message to Auto. Auto uses the notification tag and ID to determine which conversation 163the message belongs to, and presents the message to the user in an appropriate 164way.</li> 165 166<li>When the user listens to the message, Auto triggers the app's message heard 167pending intent. The app should discard the {@link 168android.support.v4.app.NotificationCompat.CarExtender.UnreadConversation 169UnreadConversation} object and its builder at this time, since the messages 170contained in those objects have been heard by the user.</li> 171 172<li>If the user sends a reply, Auto triggers the app's "message reply" intent and 173attaches a transcript of the user's response. The app can take appropriate 174action, based on the app's logic. For example, a chat app might interpret the 175reply as a message to go to the other conversation participants.</li> 176 177</ol> 178 179<h2 id="#manifest">Configure Your Manifest</h2> 180 181<p> 182 You configure your app <a href="{@docRoot}guide/topics/manifest/manifest-intro.html">manifest</a> 183 to indicate that it supports messaging services for Auto devices and handle message actions. This 184 section describes what changes to make to your manifest to support messaging for Auto devices. 185</p> 186 187<h3 id="manifest-messaging">Declare Auto messaging support</h3> 188 189<p> 190 When a user connects a Android mobile device to a dashboard running Android, the dashboard 191 device looks for apps that declare support for vehicle services, such as messaging. You indicate 192 that your app supports cars capabilities using the following manifest entry: 193</p> 194 195<pre> 196<application> 197 ... 198 <meta-data android:name="com.google.android.gms.car.application" 199 android:resource="@xml/automotive_app_desc" /> 200 ... 201<application> 202</pre> 203 204<p> 205 This manifest entry refers to a secondary xml file, where you declare what Auto capabilities your 206 app supports. For an app that supports messaging for Auto devices, add an xml file to the {@code 207 res/xml/} your app's development project directory as {@code automotive_app_desc.xml}, with the 208 following content: 209</p> 210 211<pre> 212<automotiveApp> 213 <uses name="notification"/> 214</automotiveApp> 215</pre> 216 217<p> 218 For more information about declaring capabilities for Auto devices, see <a href= 219 "{@docRoot}training/auto/start/index.html#auto-metadata">Getting Started with Auto</a>. 220</p> 221 222 223<h3 id="manifest-intent">Define read and reply intent filters</h3> 224 225<p> 226 Auto devices use {@link android.content.Intent} objects that indicate a user has read or replied 227 to a message provided by your app. Your app defines intent types for reading and replying to 228 messages and adds this information to messaging notifications for Auto devices, so that the 229 dashboard system can notify your app when a user takes one of these actions. 230</p> 231 232<p> 233 You define the read action and reply action intents types for your app and the {@link 234 android.content.BroadcastReceiver} classes that handle them in the manifest. The following code 235 example demonstrates how to declare these intents and their associated receivers. 236</p> 237 238<pre> 239<application> 240 ... 241 <receiver android:name=".MyMessageHeardReceiver"> 242 <intent-filter> 243 <action android:name="com.myapp.messagingservice.MY_ACTION_MESSAGE_HEARD"/> 244 </intent-filter> 245 </receiver> 246 247 <receiver android:name=".MyMessageReplyReceiver"> 248 <intent-filter> 249 <action android:name="com.myapp.messagingservice.MY_ACTION_MESSAGE_REPLY"/> 250 </intent-filter> 251 </receiver> 252 ... 253</application> 254</pre> 255 256<p> In this example, <code>"MyMessageReadReceiver"</code> and 257<code>"MyMessageReplyReceiver"</code> are the names of the {@link 258android.content.BroadcastReceiver} subclasses you define to handle the 259intents. You can choose whatever you like as the action names, but it's best 260to prepend your package name to ensure that the action names are unique. For 261more information about handling actions, see <a href="#handle_actions">Handle 262User Actions</a>. </p> 263 264<h2 id="support-lib">Import Support Library for Messaging</h3> 265 266<p> 267 Building notifications for use with Auto devices requires classes from the 268 <a href="{@docRoot}tools/support-library/features.html#v4">v4 support library</a>. Use the 269 <a href="{@docRoot}tools/help/sdk-manager.html">Android SDK Manager</a> to update the 270 <em>Extras > Android Support Repository</em> to version 9 or higher and the 271 <em>Extras > Android Support Library</em> to version 21.0.2 or higher. 272</p> 273 274<p> 275 After you have updated the support libraries, import them into your Android Studio development 276 project by adding this dependency to your 277 <a href="{@docRoot}sdk/installing/studio-build.html#configBuild">build.gradle</a> file: 278</p> 279 280<pre> 281dependencies { 282 ... 283 compile 'com.android.support:support-v4:21.0.2' 284} 285</pre> 286 287<p> 288 For information about importing the support library into development projects for other 289 development environments, see <a href="{@docRoot}tools/support-library/setup.html">Support 290 Library Setup</a>. 291</p> 292 293 294 295<h2 id="messaging">Notify Users of Messages</h2> 296 297<p> 298 A messaging app provides messages to a connected Auto dashboard using the <a href= 299 "{@docRoot}guide/topics/ui/notifiers/notifications.html">notifications</a> framework. When your 300 messaging app has a message for a user, you build a specially configured notification that is 301 received by the dashboard system and presented to the user. The Auto device manages the 302 presentation on the dashboard screen and may play the message via text-to-speech. The dashboard 303 system also handles voice interaction if the user replies to a message using verbal input. 304</p> 305 306<p> 307 The messaging user interface for Auto presents users with two levels of information about 308 messages. The first level of notification tells users what <em>conversations</em> are 309 available, and who they are with, but not the content of the messages. Typically, a 310 conversation is one or more messages from another user to the Auto user. 311</p> 312 313<p> 314 The second level of the notification is the actual content of messages in the conversation. If a 315 user indicates they want to hear the messages in a conversation, the Auto user interface plays 316 the messages using text-to-speech. 317</p> 318 319<p> 320 This section describes how to notify Auto users that conversations are available and 321 provide the content of messages in those conversations. 322</p> 323 324<h4 id="conversation-intents">Create conversation read and reply intents</h4> 325 326<p> 327 Unread conversation objects contain intents for reading and replying to a conversation. You 328 create a {@link android.app.PendingIntent} object for each of these actions, so the Auto device 329 can notify your app of action taken by the Auto user on a particular conversation. 330</p> 331 332<p> 333 The following example code demonstrates how to define a {@link android.app.PendingIntent} to let 334 your app know if a conversation was read to the Auto user: 335</p> 336 337<pre> 338Intent msgHeardIntent = new Intent() 339 .addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES) 340 .setAction("com.myapp.messagingservice.MY_ACTION_MESSAGE_HEARD") 341 .putExtra("conversation_id", thisConversationId); 342 343PendingIntent msgHeardPendingIntent = 344 PendingIntent.getBroadcast(getApplicationContext(), 345 thisConversationId, 346 msgHeardIntent, 347 PendingIntent.FLAG_UPDATE_CURRENT); 348</pre> 349 350<p>In this example, {@code thisConversationId} is an integer that identifies the 351current conversation. The value of {@link android.content.Intent#setAction 352Intent.setAction()} is the intent filter identifier for heard messages which you 353defined in your app manifest, as shown in <a href="#manifest-intent">Define read 354and reply intent filters</a>. </p> 355 356<p> 357 If your app supports replying to conversations, you also create a {@link 358 android.app.PendingIntent} for each conversation to notify your app that the user has replied. 359 The following code example shows you how to build this intent for use with a particular 360 conversation: 361</p> 362 363<pre> 364Intent msgReplyIntent = new Intent() 365 .addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES) 366 .setAction("com.myapp.messagingservice.MY_ACTION_MESSAGE_REPLY") 367 .putExtra("conversation_id", thisConversationId); 368 369PendingIntent msgReplyPendingIntent = PendingIntent.getBroadcast( 370 getApplicationContext(), 371 thisConversationId, 372 msgReplyIntent, 373 PendingIntent.FLAG_UPDATE_CURRENT); 374</pre> 375 376<p> Once again, {@code thisConversationId} is an integer that uniquely identifies 377this conversation, and the value you pass to {@link 378android.content.Intent#setAction Intent.setAction()} is the intent filter 379identifier you defined for replies in your app manifest. </p> 380 381<h3 id="build_conversation">Set up the conversation builder</h4> 382 383<p> 384 Messaging notifications for Auto organize messages into conversations using the {@link 385 android.support.v4.app.NotificationCompat.CarExtender.UnreadConversation} class, 386 that represents an unread or new 387 portion of a conversation from a particular sender. It contains a list of messages from the 388 sender. 389</p> 390 391<p> 392 You generally do not configure the {@link 393 android.support.v4.app.NotificationCompat.CarExtender.UnreadConversation UnreadConversation} 394 directly. Instead, you configure an 395 {@link android.support.v4.app.NotificationCompat.CarExtender.UnreadConversation.Builder 396 UnreadConversation.Builder} with the information about the conversation, 397 as shown in the following example code. 398</p> 399 400<pre> 401// Build a RemoteInput for receiving voice input in a Car Notification 402RemoteInput remoteInput = new RemoteInput.Builder(MY_VOICE_REPLY_KEY) 403 .setLabel(getApplicationContext().getString(R.string.notification_reply)) 404 .build(); 405 406// Create an unread conversation object to organize a group of messages 407// from a particular sender. 408UnreadConversation.Builder unreadConvBuilder = 409 new UnreadConversation.Builder(conversationName) 410 .setReadPendingIntent(msgHeardPendingIntent) 411 .setReplyAction(msgReplyPendingIntent, remoteInput); 412</pre> 413 414<p class="note"> 415 <strong>Note:</strong> You won't actually create the {@link 416 android.support.v4.app.NotificationCompat.CarExtender.UnreadConversation 417 UnreadConversation} until you are almost ready to send the message. 418</p> 419 420<p> 421 This conversation object includes a {@link android.app.PendingIntent}, which allows the Auto 422 device to signal your app that the conversation has been read by the Auto user. The construction 423 of this intent is discussed in the <a href="#conversation-intents">Creating conversation read and 424 reply intents</a> section. 425</p> 426 427<p> 428 If your app supports replying to a conversation, you must call the 429 {@link android.support.v4.app.NotificationCompat.CarExtender.UnreadConversation.Builder#setReplyAction 430 UnreadConversation.Builder.setReplyAction()} 431 method and provide a pending intent to pass that user action back to your app. The 432 {@link android.support.v4.app.NotificationCompat.CarExtender.UnreadConversation 433 UnreadConversation} 434 object you create must also include a {@link 435 android.support.v4.app.RemoteInput} object. When the Auto user 436 receiving this conversation speaks a reply, the remote input objects lets your app get a text 437 version of the voice reply. 438</p> 439 440<h3 id="sending_messages">Sending Messages</h4> 441 442<p> 443 When a message arrives for a conversation, you take the following steps to dispatch it as a 444 notification to Auto. 445</p> 446 447<p>First, add the message to the {@link 448android.support.v4.app.NotificationCompat.CarExtender.UnreadConversation.Builder 449UnreadConversation.Builder} for this conversation, and update its timestamp:</p> 450 451<pre> 452unreadConvBuilder.addMessage(messageString) 453 .setLatestTimestamp(currentTimestamp); 454</pre> 455 456<p class="note"><strong>Note:</strong> If you are sending several messages at 457once, add them to the {@link 458android.support.v4.app.NotificationCompat.CarExtender.UnreadConversation.Builder 459UnreadConversation.Builder} in order, from oldest to newest.</p> 460 461<p>Then create the {@link android.support.v4.app.NotificationCompat.Builder 462NotificationCompat.Builder} 463object that builds the actual notification. You need to use the 464pending intents you created in the previous step.</p> 465 466<pre> 467NotificationCompat.Builder notificationBuilder = 468 new NotificationCompat.Builder(getApplicationContext()) 469 .setSmallIcon(smallIconResourceID) 470 .setLargeIcon(largeIconBitmap); 471</pre> 472 473<dl> 474 <dt><code>smallIconResourceID</code></dt> 475 <dd>The resource ID of a small icon to use for the conversation. This is 476 typically a generic icon for the messaging app.</dd> 477 478 <dt><code>largeIconBitmap</code></dt> 479 <dd>A {@link android.graphics.Bitmap} of a large version of the icon. This 480 is typically a conversation-specific graphic. For example, if this is a 481 chat app, the large icon would be a picture of the person the user is 482 chatting with.</dd> 483 484 <dt><code>messageString</code></dt> 485 <dd>The text of the message you want to send. (If you are sending several 486 messages at once, concatenate them into a single string, with the oldest 487 message first.)</dd> 488 489 <dt><code>currentTimestamp</code></dt> 490 <dd>The message timestamp. (If you are sending several messages at once, 491 use the timestamp of the most recent message.)</dd> 492 493 <dt><code>conversationName</code></dt> 494 495 <dd>The name you chose for this conversation (for example, the name of the 496 person the user is chatting with). This should be the same conversation 497 name you used when you created the {@link 498android.support.v4.app.NotificationCompat.CarExtender.UnreadConversation.Builder 499 UnreadConversation.Builder}.</dd> 500 501 <dt><code>msgHeardPendingIntent</code></dt> 502 <dd>The pending intent object you created in 503 <a href="#conversation-intents">Create conversation read and reply 504 intents</a>.</dd> 505</dl> 506 507 508<p>You'll also need to extend the {@link 509android.support.v4.app.NotificationCompat.Builder NotificationCompat.Builder} with the {@link 510android.support.v4.app.NotificationCompat.CarExtender CarExtender}. This is where you 511actually create the 512{@link android.support.v4.app.NotificationCompat.CarExtender.UnreadConversation 513UnreadConversation} object using the builder you 514just created, and attach it to the {@link 515android.support.v4.app.NotificationCompat.CarExtender CarExtender}:</p> 516 517<pre> 518notificationBuilder.extend(new CarExtender() 519 .setUnreadConversation(unreadConvBuilder.build()); 520</pre> 521 522<p class="note"><strong>Note:</strong> If you wish, you can set an override icon 523or color for the {@link android.support.v4.app.NotificationCompat.CarExtender 524CarExtender} by calling {@link 525android.support.v4.app.NotificationCompat.CarExtender#setLargeIcon 526setLargeIcon()} or {@link 527android.support.v4.app.NotificationCompat.CarExtender#setColor setColor()}. The 528override icon or color is used when the notification is handled by a car, and 529has no effect if the notification is handled on the Android device. This is 530useful if the notification's default icon or color are not suitable for the 531car's display.</p> 532 533<p>Once you've done all this, you use your app's {@link 534android.support.v4.app.NotificationManagerCompat} to send the notification:</p> 535 536<pre> 537NotificationManagerCompat msgNotificationManager = 538 NotificationManagerCompat.from(context); 539msgNotificationManager.notify(notificationTag, 540 notificationId, notificationBuilder.build()); 541</pre> 542 543<h2 id="handle_actions">Handle User Actions</h2> 544 545<p> 546 When your create and dispatch a notification for messaging, you specify intents to be triggered 547 when the Auto user hears the message and when the user dictates a reply. Your app indicates to 548 the Android framework that it handles these intends by registering them through its manifest, as 549 discussed in <a href="#manifest-intent">Define read and reply intent filters</a>. 550</p> 551 552<p> 553 In addition to registering these intent filters, your app must provide code to handle these 554 actions. Your app can do this by providing a service or {@link android.content.BroadcastReceiver} 555 objects that handle these intents.</p> 556 557<p> 558 For more information about intents, see <a href= 559 "{@docRoot}guide/components/intents-filters.html">Intents and Intent Filters</a>. 560</p> 561 562 563<h3 id="handling_msg_heard">Handling a message heard action</h3> 564 565<p> 566 When a user listens to a messaging conversation through the Auto user interface, the dashboard 567 device sends a read intent based on how your app defined the messaging notification. Your app 568 catches that intent and invokes the broadcast receiver class associated with it, or the service 569 method set up to handle that action. 570</p> 571 572<p> 573 The following code example shows how to define a {@link android.content.BroadcastReceiver} class 574 to handle a received message heard intent: 575</p> 576 577<pre> 578public class MyMessageHeardReceiver extends BroadcastReceiver { 579 580 @Override 581 public void onReceive(Context context, Intent intent) { 582 583 // If you set up the intent as described in 584 // "Create conversation read and reply intents", 585 // you can get the conversation ID by calling: 586 int thisConversationId = intent.getIntExtra("conversation_id", -1); 587 588 // Remove the notification to indicate it has been read 589 // and update the list of unread conversations in your app. 590 } 591} 592</pre> 593 594<p> 595 Once a notification is read, your app can remove it by calling 596 {@link android.support.v4.app.NotificationManagerCompat#cancel 597 NotificationManagerCompat.cancel()} with the notification ID. 598 Within your app, you should mark the messages provided in the notification as read. 599</p> 600 601 602<p class="note"> 603 <strong>Note:</strong> An alternative to this implementation is to use a service in a 604 {@link android.app.PendingIntent}. 605</p> 606 607 608<h3 id="handling_reply">Handling a reply action</h3> 609 610<p> 611 When a user replies to a messaging conversation through the Auto user interface, the dashboard 612 system sends a reply intent based on how your app defined the messaging notification. Your app 613 catches that intent and invokes the broadcast receiver class associated with it, or the service 614 method set up to handle that action. 615</p> 616 617<p> 618 The following code example shows how to define a {@link android.content.BroadcastReceiver} class 619 to handle a received message reply intent: 620</p> 621 622<pre> 623 public class MyMessageReplyReceiver extends BroadcastReceiver { 624 625 626 @Override 627 public void onReceive(Context context, Intent intent) { 628 // If you set up the intent as described in 629 // "Create conversation read and reply intents", 630 // you can get the conversation ID by calling: 631 int thisConversationId = intent.getIntExtra("conversation_id", -1). 632 633 } 634 635 /** 636 * Get the message text from the intent. 637 * Note that you should call 638 * RemoteInput.getResultsFromIntent() to process 639 * the RemoteInput. 640 */ 641 private CharSequence getMessageText(Intent intent) { 642 Bundle remoteInput = 643 RemoteInput.getResultsFromIntent(intent); 644 if (remoteInput != null) { 645 return remoteInput.getCharSequence(MY_VOICE_REPLY_KEY); 646 } 647 return null; 648 } 649 650}</pre> 651