1page.title=Providing Messaging for Auto 2page.tags="auto", "car", "automotive", "messaging" 3page.article=true 4 5@jd:body 6 7<div id="tb-wrapper"> 8<div id="tb"> 9 <h2>Dependencies and Prerequisites</h2> 10 <ul> 11 <li>Android 5.0 (API level 21) or higher</li> 12 </ul> 13 14 <h2>This class teaches you to:</h2> 15 16 <ul> 17 <li><a href="#overview">Provide Messaging Services</a></li> 18 <li><a href="#manifest">Configure Your Manifest</a></li> 19 <li><a href="#support-lib">Import Support Library for Messaging</a></li> 20 <li><a href="#messaging">Notify Users of Messages</a></li> 21 <li><a href="#handle_actions">Handle User Actions</a></li> 22 </ul> 23 24 <h2>Related Samples</h2> 25 26 <ul> 27 <li><a href="{@docRoot}samples/MessagingService/index.html"> 28 MessagingService</a></li> 29 </ul> 30 31 <h2>See Also</h2> 32 33 <ul> 34 <li><a href="{@docRoot}shareables/auto/AndroidAuto-messaging-apps.pdf"> 35 User Experience Guidelines: Messaging Apps</a></li> 36 <li><a href="{@docRoot}guide/topics/ui/notifiers/notifications.html"> 37 Notifications</a></li> 38 </ul> 39</div> 40</div> 41 42<a class="notice-developers-video wide" 43 href="https://www.youtube.com/watch?v=gSVLuaOTIPk"> 44<div> 45 <h3>Video</h3> 46 <p>DevBytes: Android Auto Messaging</p> 47</div> 48</a> 49 50<p> 51 Staying connected through text messages is important to many drivers. Chat apps can let users 52 know if a child need to be picked up, or if a dinner location has been changed. Apps that provide 53 sports information might tell the user who just won the big game, and let the user ask questions 54 about other games being played. The Android framework enables messaging apps to extend their 55 services into car dashboards using a standard user interface that lets drivers keep their eyes 56 on the road. 57</p> 58 59<p> 60 Apps that support messaging can be extended to pass messaging notifications to Auto 61 dashboard systems, alerting them to new messages and allowing them to respond. You can configure 62 your messaging app to provide these services when an Android mobile device with your app 63 installed is connected to an Auto dashboard. Once connected, your app can provide text 64 information to users and allow them to respond. The Auto dashboard system handles displaying the 65 notification and the interface for replies. 66</p> 67 68<p> 69 This lesson assumes that you have built an app that displays messages to the user and receive the 70 user's replies, such as a chat app. It shows you how to extend your app to hand those messages 71 off to an Auto device for display and replies. 72</p> 73 74 75<h2 id="overview">Provide Messaging Services</h2> 76 77<p> 78 Messaging apps do not run directly on the Android dashboard hardware. They are installed on 79 separate, Android mobile device. When the mobile device is plugged into a dashboard, 80 the installed messaging apps can offer services for viewing and responding to messages 81 through the Auto user interface. 82</p> 83 84<p>To enable your app to provide messaging services for Auto devices:</p> 85 86<ul> 87 <li>Configure your app manifest to indicate that your app provides messaging services which are 88 compatible with Android Auto dashboard devices. 89 </li> 90 <li>Build and send a specific type of <a href= 91 "{@docRoot}guide/topics/ui/notifiers/notifications.html">notification</a> for display on Auto 92 devices. 93 </li> 94 <li>Configure your app to receive {@link android.content.Intent} objects that indicate a user 95 has read or replied to a message. 96</ul> 97 98 99<h2 id="#manifest">Configure Your Manifest</h2> 100 101<p> 102 You configure your app <a href="{@docRoot}guide/topics/manifest/manifest-intro.html">manifest</a> 103 to indicate that it supports messaging services for Auto devices and handle message actions. This 104 section describes what changes to make to your manifest to support messaging for Auto devices. 105</p> 106 107 108<h3 id="manifest-messaging">Declare Auto messaging support</h3> 109 110<p> 111 When a user connects a Android mobile device to a dashboard running Android, the dashboard 112 device looks for apps that declare support for vehicle services, such as messaging. You indicate 113 that your app supports cars capabilities using the following manifest entry: 114</p> 115 116<pre> 117<application> 118 ... 119 <meta-data android:name="com.google.android.gms.car.application" 120 android:resource="@xml/automotive_app_desc" /> 121 ... 122<application> 123</pre> 124 125<p> 126 This manifest entry refers to a secondary xml file, where you declare what Auto capabilities your 127 app supports. For an app that supports messaging for Auto devices, add an xml file to the {@code 128 res/xml/} your app's development project directory as {@code automotive_app_desc.xml}, with the 129 following content: 130</p> 131 132<pre> 133<automotiveApp> 134 <uses name="notification"/> 135</automotiveApp> 136</pre> 137 138<p> 139 For more information about declaring capabilities for Auto devices, see <a href= 140 "{@docRoot}training/auto/start/index.html#auto-metadata">Getting Started with Auto</a>. 141</p> 142 143 144<h3 id="manifest-intent">Define read and reply intent filters</h3> 145 146<p> 147 Auto devices use {@link android.content.Intent} objects that indicate a user has read or replied 148 to a message provided by your app. Your app defines intent types for reading and replying to 149 messages and adds this information to messaging notifications for Auto devices, so that the 150 dashboard system can notify your app when a user takes one of these actions. 151</p> 152 153<p> 154 You define the read action and reply action intents types for your app and the {@link 155 android.content.BroadcastReceiver} classes that handle them in the manifest. The following code 156 example demonstrates how to declare these intents and their associated receivers. 157</p> 158 159<pre> 160<application> 161 ... 162 <receiver android:name="<em>.MyMessageReadReceiver</em>"> 163 <intent-filter> 164 <action android:name="<em>com.myapp.messagingservice.ACTION_MESSAGE_HEARD</em>"/> 165 </intent-filter> 166 </receiver> 167 168 <receiver android:name="<em>.MyMessageReplyReceiver</em>"> 169 <intent-filter> 170 <action android:name="<em>com.myapp.messagingservice.ACTION_MESSAGE_REPLY</em>"/> 171 </intent-filter> 172 </receiver> 173 ... 174</application> 175</pre> 176 177<p> 178 The definition of the {@link android.content.BroadcastReceiver} classes shown in this example 179 is discussed in <a href="#handle_actions">Handle User Actions</a>. 180</p> 181 182 183<h2 id="support-lib">Import Support Library for Messaging</h3> 184 185<p> 186 Building notifications for use with Auto devices requires classes from the 187 <a href="{@docRoot}tools/support-library/features.html#v4">v4 support library</a>. Use the 188 <a href="{@docRoot}tools/help/sdk-manager.html">Android SDK Manager</a> to update the 189 <em>Extras > Android Support Repository</em> to version 9 or higher and the 190 <em>Extras > Android Support Library</em> to version 21.0.2 or higher. 191</p> 192 193<p> 194 After you have updated the support libraries, import them into your Android Studio development 195 project by adding this dependency to your 196 <a href="{@docRoot}sdk/installing/studio-build.html#configBuild">build.gradle</a> file: 197</p> 198 199<pre> 200dependencies { 201 ... 202 compile 'com.android.support:support-v4:21.0.+' 203} 204</pre> 205 206<p> 207 For information about importing the support library into development projects for other 208 development environments, see <a href="{@docRoot}tools/support-library/setup.html">Support 209 Library Setup</a>. 210</p> 211 212 213 214<h2 id="messaging">Notify Users of Messages</h2> 215 216<p> 217 A messaging app provides messages to a connected Auto dashboard using the <a href= 218 "{@docRoot}guide/topics/ui/notifiers/notifications.html">notifications</a> framework. When your 219 messaging app has a message for a user, you build a specially configured notification that is 220 received by the dashboard system and presented to the user. The Auto device manages the 221 presentation on the dashboard screen and may play the message via text-to-speech. The dashboard 222 system also handles voice interaction if the user replies to a message using verbal input. 223</p> 224 225<p> 226 The messaging user interface for Auto presents users with two levels of information about 227 messages. The first level of notification tells users what <em>conversations</em> are 228 available, and who they are with, but not the content of the messages. Typically, a 229 conversation is one or more messages from another user to the Auto user. 230</p> 231 232<p> 233 The second level of the notification is the actual content of messages in the conversation. If a 234 user indicates they want to hear the messages in a conversation, the Auto user interface plays 235 the messages using text-to-speech. 236</p> 237 238<p> 239 This section describes how to notify Auto users that conversations are available and 240 provide the content of messages in those conversations. 241</p> 242 243 244<h3 id="build_conversation">Build message conversations</h4> 245 246<p> 247 Messaging notifications for Auto organize messages into conversations using the {@link 248 android.support.v4.app.NotificationCompat.CarExtender.UnreadConversation} class, 249 that represents an unread or new 250 portion of a conversation from a particular sender. It contains a list of messages from the 251 sender. 252</p> 253 254<p> 255 Use the {@link android.support.v4.app.NotificationCompat.CarExtender.UnreadConversation.Builder} class to create an unread conversation object, 256 as shown in the following example code: 257</p> 258 259<pre> 260// Build a RemoteInput for receiving voice input in a Car Notification 261RemoteInput remoteInput = new RemoteInput.Builder(EXTRA_VOICE_REPLY) 262 .setLabel(getApplicationContext().getString(R.string.notification_reply)) 263 .build(); 264 265// Create an unread conversation object to organize a group of messages 266// from a particular sender. 267UnreadConversation.Builder unreadConvBuilder = 268 new UnreadConversation.Builder(participantName) 269 .setReadPendingIntent(msgHeardPendingIntent) 270 .setReplyAction(replyPendingIntent, remoteInput); 271</pre> 272 273<p> 274 This conversation object includes a {@link android.app.PendingIntent}, which allows the Auto 275 device to signal your app that the conversation has been read by the Auto user. The construction 276 of this intent is discussed in the <a href="#conversation-intents">Creating conversation read and 277 reply intents</a> section. 278</p> 279 280<p> 281 If your app supports replying to a conversation, you must call the {@link android.support.v4.app.NotificationCompat.CarExtender.UnreadConversation.Builder#setReplyAction setReplyAction()} 282 method and provide a pending intent to pass that user action back to your app. The 283 {@link android.support.v4.app.NotificationCompat.CarExtender.UnreadConversation} 284 object you create must also include a {@link 285 android.support.v4.app.RemoteInput} object. When the Auto user 286 receiving this conversation speaks a reply, the remote input objects lets your app get a text 287 version of the voice reply. 288</p> 289 290 291<h4 id="conversation-messages">Associate messages with conversations</h4> 292 293<p> 294 Messages provided for Auto must be associated with a conversation using the 295 {@link android.support.v4.app.NotificationCompat.CarExtender.UnreadConversation} 296 class. The following code example shows how 297 to associate individual messages with a conversation object. 298</p> 299 300<pre> 301// Note: Add messages from oldest to newest to the UnreadConversation.Builder 302for (Iterator<String> messages = conversation.getMessages().iterator(); 303 messages.hasNext(); ) { 304 String message = messages.next(); 305 unreadConvBuilder.addMessage(message); 306} 307</pre> 308 309<p> 310 When a new message arrives in a particular conversation, your app should check if there is 311 already a conversation object for that particular conversation. If there is, associate the new 312 message with the existing conversation instead of building a new one. 313</p> 314 315 316<h4 id="conversation-intents">Create conversation read and reply intents</h4> 317 318<p> 319 Unread conversation objects contain intents for reading and replying to a conversation. You 320 create a {@link android.app.PendingIntent} object for each of these actions, so the Auto device 321 can notify your app of action taken by the Auto user on a particular conversation. 322</p> 323 324<p> 325 The following example code demonstrates how to define a {@link android.app.PendingIntent} to let 326 your app know if a conversation was listened to by the Auto user: 327</p> 328 329<pre> 330Intent msgHeardIntent = new Intent() 331 .addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES) 332 .setAction(<em>com.myapp.messagingservice.ACTION_MESSAGE_HEARD</em>) 333 .putExtra("conversation_id", <em>conversationId</em>); 334 335PendingIntent msgHeardPendingIntent = 336 PendingIntent.getBroadcast(getApplicationContext(), 337 <em>conversationId</em>, 338 msgHeardIntent, 339 PendingIntent.FLAG_UPDATE_CURRENT); 340</pre> 341 342<p> 343 In this example, {@code conversationId} is an integer that identifies the current conversation. 344 The value of {@link android.content.Intent#setAction setAction()} is an intent filter identifier for heard messages which is 345 defined in your app manifest, as shown in <a href="#manifest-intent">Define read and reply intent 346 filters</a>. 347</p> 348 349<p> 350 If your app supports replying to conversations, you also create a {@link 351 android.app.PendingIntent} for each conversation to notify your app that the user has replied. 352 The following code example shows you how to build this intent for use with a particular 353 conversation: 354</p> 355 356<pre> 357Intent msgReplyIntent = new Intent() 358 .addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES) 359 .setAction(<em>com.myapp.messagingservice.ACTION_MESSAGE_REPLY</em>) 360 .putExtra("conversation_id", <em>conversationId</em>); 361 362PendingIntent msgReplyPendingIntent = PendingIntent.getBroadcast( 363 getApplicationContext(), 364 <em>conversationId</em>, 365 msgReplyIntent, 366 PendingIntent.FLAG_UPDATE_CURRENT); 367</pre> 368 369<p> 370 Once again, {@code conversationId} is an integer that uniquely identifies this conversation. The 371 value of {@link android.content.Intent#setAction setAction()} is an intent filter identifier for replies which is defined in your 372 app manifest, as shown in <a href="#manifest-intent">Define read and reply intent filters</a>. 373</p> 374 375 376<h3 id="sending_messages">Sending Messages</h4> 377 378<p> 379 When a message arrives for a conversation, you take the following steps to dispatch it as a 380 notification to Auto. 381</p> 382 383<p>First, add the message to the {@link 384android.support.v4.app.NotificationCompat.CarExtender.UnreadConversation.Builder} 385for this conversation, and update its timestamp:</p> 386 387<pre> 388unreadConvBuilder.addMessage(<em>messageString</em>) 389 .setLatestTimestamp(<em>currentTimestamp</em>); 390</pre> 391 392<p>Then create a {@link android.support.v4.app.NotificationCompat.Builder} 393object that you'll use to build the actual notification. You'll need to use the 394pending intents you created in the previous step.</p> 395 396<pre> 397NotificationCompat.Builder notificationBuilder = 398 new NotificationCompat.Builder(getApplicationContext()) 399 .setSmallIcon(R.drawable.<em>notification_icon</em>) 400 .setLargeIcon(<em>icon_bitmap</em>) 401 .setContentText(<em>messageString</em>) 402 .setWhen(<em>currentTimestamp</em>) 403 .setContentTitle(<em>participant_name</em>) 404 .setContentIntent(msgHeardPendingIntent); 405 406</pre> 407 408<p>You'll also need to extend the {@link 409android.support.v4.app.NotificationCompat.Builder} with the {@link 410android.support.v4.app.NotificationCompat.CarExtender}. This is where you 411actually create the {@link android.support.v4.app.NotificationCompat.CarExtender.UnreadConversation} object using the builder you 412just created, and attach it to the {@link 413android.support.v4.app.NotificationCompat.CarExtender}:</p> 414 415<pre> 416notificationBuilder.extend(new CarExtender() 417 .setUnreadConversation(unreadConvBuilder.build()); 418</pre> 419 420<p>Once you've done all this, you use your app's {@link 421android.support.v4.app.NotificationManagerCompat} to send the notification:</p> 422 423<pre> 424NotificationManagerCompat msgNotificationManager = 425 NotificationManagerCompat.from(context); 426msgNotificationManager.notify(<em>notificationId</em>, notificationBuilder.build()); 427</pre> 428 429<h2 id="handle_actions">Handle User Actions</h2> 430 431<p> 432 When your create and dispatch a notification for messaging, you specify intents to be triggered 433 when the Auto user hears the message and when the user dictates a reply. Your app indicates to 434 the Android framework that it handles these intends by registering them through it's manifest, as 435 discussed in <a href="#manifest-intent">Define read and reply intent filters</a>. 436</p> 437 438<p> 439 In addition to registering these intent filters, your app must provide code to handle these 440 actions. Your app can do this by providing a service or {@link android.content.BroadcastReceiver} 441 objects that handle these intents.</p> 442 443<p> 444 For more information about intents, see <a href= 445 "{@docRoot}guide/components/intents-filters.html">Intents and Intent Filters</a>. 446</p> 447 448 449<h3 id="handling_msg_heard">Handling a message heard action</h3> 450 451<p> 452 When a user listens to a messaging conversation through the Auto user interface, the dashboard 453 device sends a read intent based on how your app defined the messaging notification. Your app 454 catches that intent and invokes the broadcast receiver class associated with it, or the service 455 method set up to handle that action. 456</p> 457 458<p> 459 The following code example shows how to define a {@link android.content.BroadcastReceiver} class 460 to handle a received message heard intent: 461</p> 462 463<pre> 464public class MessageHeardReceiver extends BroadcastReceiver { 465 466 @Override 467 public void onReceive(Context context, Intent intent) { 468 469 // If you set up the intent as described in 470 // "Create conversation read and reply intents", 471 // you can get the conversation ID by calling: 472 int conversationId = intent.getIntExtra("conversation_id", -1); 473 474 // Remove the notification to indicate it has been read 475 // and update the list of unread conversations in your app. 476 } 477} 478</pre> 479 480<p> 481 Once a notification is read, your app can remove it by calling 482 {@link android.support.v4.app.NotificationManagerCompat#cancel} with the notification ID. 483 Within your app, you should mark the messages provided in the notification as read. 484</p> 485 486 487<p class="note"> 488 <strong>Note:</strong> An alternative to this implementation is to use a service in a 489 {@link android.app.PendingIntent}. 490</p> 491 492 493<h3 id="handling_reply">Handling a reply action</h3> 494 495<p> 496 When a user replies to a messaging conversation through the Auto user interface, the dashboard 497 system sends a reply intent based on how your app defined the messaging notification. Your app 498 catches that intent and invokes the broadcast receiver class associated with it, or the service 499 method set up to handle that action. 500</p> 501 502<p> 503 The following code example shows how to define a {@link android.content.BroadcastReceiver} class 504 to handle a received message reply intent: 505</p> 506 507<pre> 508 public class MessageReplyReceiver extends BroadcastReceiver { 509 510 511 @Override 512 public void onReceive(Context context, Intent intent) { 513 // If you set up the intent as described in 514 // "Create conversation read and reply intents", 515 // you can get the conversation ID by calling: 516 int conversationId = intent.getIntExtra("conversation_id", -1). 517 518 } 519 520 /** 521 * Get the message text from the intent. 522 * Note that you should call 523 * RemoteInput.getResultsFromIntent() to process 524 * the RemoteInput. 525 */ 526 private CharSequence getMessageText(Intent intent) { 527 Bundle remoteInput = 528 RemoteInput.getResultsFromIntent(intent); 529 if (remoteInput != null) { 530 return remoteInput.getCharSequence("extra_voice_reply"); 531 } 532 return null; 533 } 534 535}</pre> 536