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. The app 154attaches the message to an {@link 155android.support.v4.app.NotificationCompat.CarExtender.UnreadConversation.Builder 156UnreadConversation.Builder} object, then uses the {@link 157android.support.v4.app.NotificationCompat.CarExtender.UnreadConversation.Builder 158UnreadConversation.Builder} to generate an {@link 159android.support.v4.app.NotificationCompat.CarExtender.UnreadConversation 160UnreadConversation}. The app attaches that {@link 161android.support.v4.app.NotificationCompat.CarExtender.UnreadConversation 162UnreadConversation} to a notification. That notification 163is associated with a {@link 164android.support.v4.app.NotificationCompat.CarExtender CarExtender} object, which 165indicates that the notification can be handled by Android Auto.</li> 166 167<li>The app posts the notification. The Android notification framework passes the 168message to Auto. Auto uses the notification tag and ID to determine which conversation 169the message belongs to, and presents the message to the user in an appropriate 170way.</li> 171 172<li>When the user listens to the message, Auto triggers the app's message heard 173pending intent. The app should discard the {@link 174android.support.v4.app.NotificationCompat.CarExtender.UnreadConversation 175UnreadConversation} object and its builder at this time, since the messages 176contained in those objects have been heard by the user.</li> 177 178<li>If the user sends a reply, Auto triggers the app's "message reply" intent and 179attaches a transcript of the user's response. The app can take appropriate 180action, based on the app's logic. For example, a chat app might interpret the 181reply as a message to go to the other conversation participants.</li> 182 183</ol> 184 185<h2 id="manifest">Configure Your Manifest</h2> 186 187<p> 188 You configure your app <a href="{@docRoot}guide/topics/manifest/manifest-intro.html">manifest</a> 189 to indicate that it supports messaging services for Auto devices and handle message actions. This 190 section describes what changes to make to your manifest to support messaging for Auto devices. 191</p> 192 193<h3 id="manifest-messaging">Declare Auto messaging support</h3> 194 195<p> 196 When a user connects a Android mobile device to a dashboard running Android, the dashboard 197 device looks for apps that declare support for vehicle services, such as messaging. You indicate 198 that your app supports cars capabilities using the following manifest entry: 199</p> 200 201<pre> 202<application> 203 ... 204 <meta-data android:name="com.google.android.gms.car.application" 205 android:resource="@xml/automotive_app_desc" /> 206 ... 207<application> 208</pre> 209 210<p> 211 This manifest entry refers to a secondary xml file, where you declare what Auto capabilities your 212 app supports. For an app that supports messaging for Auto devices, add an xml file to the {@code 213 res/xml/} your app's development project directory as {@code automotive_app_desc.xml}, with the 214 following content: 215</p> 216 217<pre> 218<automotiveApp> 219 <uses name="notification"/> 220</automotiveApp> 221</pre> 222 223<p> 224 For more information about declaring capabilities for Auto devices, see <a href= 225 "{@docRoot}training/auto/start/index.html#auto-metadata">Getting Started with Auto</a>. 226</p> 227 228 229<h3 id="manifest-intent">Define read and reply intent filters</h3> 230 231<p> 232 Auto devices use {@link android.content.Intent} objects that indicate a user has read or replied 233 to a message provided by your app. Your app defines intent types for reading and replying to 234 messages and adds this information to messaging notifications for Auto devices, so that the 235 dashboard system can notify your app when a user takes one of these actions. 236</p> 237 238<p> 239 You define the read action and reply action intents types for your app and the {@link 240 android.content.BroadcastReceiver} classes that handle them in the manifest. The following code 241 example demonstrates how to declare these intents and their associated receivers. 242</p> 243 244<pre> 245<application> 246 ... 247 <receiver android:name=".MyMessageHeardReceiver"> 248 <intent-filter> 249 <action android:name="com.myapp.messagingservice.MY_ACTION_MESSAGE_HEARD"/> 250 </intent-filter> 251 </receiver> 252 253 <receiver android:name=".MyMessageReplyReceiver"> 254 <intent-filter> 255 <action android:name="com.myapp.messagingservice.MY_ACTION_MESSAGE_REPLY"/> 256 </intent-filter> 257 </receiver> 258 ... 259</application> 260</pre> 261 262<p> In this example, <code>"MyMessageReadReceiver"</code> and 263<code>"MyMessageReplyReceiver"</code> are the names of the {@link 264android.content.BroadcastReceiver} subclasses you define to handle the 265intents. You can choose whatever you like as the action names, but it's best 266to prepend your package name to ensure that the action names are unique. For 267more information about handling actions, see <a href="#handle_actions">Handle 268User Actions</a>. </p> 269 270<h2 id="support-lib">Import Support Library for Messaging</h3> 271 272<p> 273 Building notifications for use with Auto devices requires classes from the 274 <a href="{@docRoot}tools/support-library/features.html#v4">v4 support library</a>. Use the 275 <a href="{@docRoot}tools/help/sdk-manager.html">Android SDK Manager</a> to update the 276 <em>Extras > Android Support Repository</em> to version 9 or higher and the 277 <em>Extras > Android Support Library</em> to version 21.0.2 or higher. 278</p> 279 280<p> 281 After you have updated the support libraries, import them into your Android Studio development 282 project by adding this dependency to your 283 <a href="{@docRoot}studio/build/index.html#configBuild">build.gradle</a> file: 284</p> 285 286<pre> 287dependencies { 288 ... 289 compile 'com.android.support:support-v4:21.0.2' 290} 291</pre> 292 293<p> 294 For information about importing the support library into development projects for other 295 development environments, see <a href="{@docRoot}tools/support-library/setup.html">Support 296 Library Setup</a>. 297</p> 298 299 300 301<h2 id="messaging">Notify Users of Messages</h2> 302 303<p> 304 A messaging app provides messages to a connected Auto dashboard using the <a href= 305 "{@docRoot}guide/topics/ui/notifiers/notifications.html">notifications</a> framework. When your 306 messaging app has a message for a user, you build a specially configured notification that is 307 received by the dashboard system and presented to the user. The Auto device manages the 308 presentation on the dashboard screen and may play the message via text-to-speech. The dashboard 309 system also handles voice interaction if the user replies to a message using verbal input. 310</p> 311 312<p> 313 The messaging user interface for Auto presents users with two levels of information about 314 messages. The first level of notification tells users what <em>conversations</em> are 315 available, and who they are with, but not the content of the messages. Typically, a 316 conversation is one or more messages from another user to the Auto user. 317</p> 318 319<p> 320 The second level of the notification is the actual content of messages in the conversation. If a 321 user indicates they want to hear the messages in a conversation, the Auto user interface plays 322 the messages using text-to-speech. 323</p> 324 325<p> 326 This section describes how to notify Auto users that conversations are available and 327 provide the content of messages in those conversations. 328</p> 329 330<h4 id="conversation-intents">Create conversation read and reply intents</h4> 331 332<p> 333 Unread conversation objects contain intents for reading and replying to a conversation. You 334 create a {@link android.app.PendingIntent} object for each of these actions, so the Auto device 335 can notify your app of action taken by the Auto user on a particular conversation. 336</p> 337 338<p> 339 The following example code demonstrates how to define a {@link android.app.PendingIntent} to let 340 your app know if a conversation was read to the Auto user: 341</p> 342 343<pre> 344Intent msgHeardIntent = new Intent() 345 .addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES) 346 .setAction("com.myapp.messagingservice.MY_ACTION_MESSAGE_HEARD") 347 .putExtra("conversation_id", thisConversationId); 348 349PendingIntent msgHeardPendingIntent = 350 PendingIntent.getBroadcast(getApplicationContext(), 351 thisConversationId, 352 msgHeardIntent, 353 PendingIntent.FLAG_UPDATE_CURRENT); 354</pre> 355 356<p>In this example, {@code thisConversationId} is an integer that identifies the 357current conversation. The value of {@link android.content.Intent#setAction 358Intent.setAction()} is the intent filter identifier for heard messages which you 359defined in your app manifest, as shown in <a href="#manifest-intent">Define read 360and reply intent filters</a>. </p> 361 362<p> 363 If your app supports replying to conversations, you also create a {@link 364 android.app.PendingIntent} for each conversation to notify your app that the user has replied. 365 The following code example shows you how to build this intent for use with a particular 366 conversation: 367</p> 368 369<pre> 370Intent msgReplyIntent = new Intent() 371 .addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES) 372 .setAction("com.myapp.messagingservice.MY_ACTION_MESSAGE_REPLY") 373 .putExtra("conversation_id", thisConversationId); 374 375PendingIntent msgReplyPendingIntent = PendingIntent.getBroadcast( 376 getApplicationContext(), 377 thisConversationId, 378 msgReplyIntent, 379 PendingIntent.FLAG_UPDATE_CURRENT); 380</pre> 381 382<p> Once again, {@code thisConversationId} is an integer that uniquely identifies 383this conversation, and the value you pass to {@link 384android.content.Intent#setAction Intent.setAction()} is the intent filter 385identifier you defined for replies in your app manifest. </p> 386 387<h3 id="build_conversation">Set up the conversation builder</h4> 388 389<p> 390 Messaging notifications for Auto organize messages into conversations using the {@link 391 android.support.v4.app.NotificationCompat.CarExtender.UnreadConversation} class, 392 that represents an unread or new 393 portion of a conversation from a particular sender. It contains a list of messages from the 394 sender. 395</p> 396 397<p> 398 You generally do not configure the {@link 399 android.support.v4.app.NotificationCompat.CarExtender.UnreadConversation UnreadConversation} 400 directly. Instead, you configure an 401 {@link android.support.v4.app.NotificationCompat.CarExtender.UnreadConversation.Builder 402 UnreadConversation.Builder} with the information about the conversation, 403 as shown in the following example code. 404</p> 405 406<pre> 407// Build a RemoteInput for receiving voice input in a Car Notification 408RemoteInput remoteInput = new RemoteInput.Builder(MY_VOICE_REPLY_KEY) 409 .setLabel(getApplicationContext().getString(R.string.notification_reply)) 410 .build(); 411 412// Create an unread conversation object to organize a group of messages 413// from a particular sender. 414UnreadConversation.Builder unreadConvBuilder = 415 new UnreadConversation.Builder(conversationName) 416 .setReadPendingIntent(msgHeardPendingIntent) 417 .setReplyAction(msgReplyPendingIntent, remoteInput); 418</pre> 419 420<p class="note"> 421 <strong>Note:</strong> You won't actually create the {@link 422 android.support.v4.app.NotificationCompat.CarExtender.UnreadConversation 423 UnreadConversation} until you are almost ready to send the message. 424</p> 425 426<p> 427 This conversation object includes a {@link android.app.PendingIntent}, which allows the Auto 428 device to signal your app that the conversation has been read by the Auto user. The construction 429 of this intent is discussed in the <a href="#conversation-intents">Creating conversation read and 430 reply intents</a> section. 431</p> 432 433<p> 434 If your app supports replying to a conversation, you must call the 435 {@link android.support.v4.app.NotificationCompat.CarExtender.UnreadConversation.Builder#setReplyAction 436 UnreadConversation.Builder.setReplyAction()} 437 method and provide a pending intent to pass that user action back to your app. The 438 {@link android.support.v4.app.NotificationCompat.CarExtender.UnreadConversation 439 UnreadConversation} 440 object you create must also include a {@link 441 android.support.v4.app.RemoteInput} object. When the Auto user 442 receiving this conversation speaks a reply, the remote input objects lets your app get a text 443 version of the voice reply. 444</p> 445 446<h3 id="sending_messages">Sending Messages</h4> 447 448<p> 449 When a message arrives for a conversation, you take the following steps to dispatch it as a 450 notification to Auto. 451</p> 452 453<p>First, add the message to the {@link 454android.support.v4.app.NotificationCompat.CarExtender.UnreadConversation.Builder 455UnreadConversation.Builder} for this conversation, and update its timestamp:</p> 456 457<pre> 458unreadConvBuilder.addMessage(messageString) 459 .setLatestTimestamp(currentTimestamp); 460</pre> 461 462<p class="note"><strong>Note:</strong> If you are sending several messages at 463once, add them to the {@link 464android.support.v4.app.NotificationCompat.CarExtender.UnreadConversation.Builder 465UnreadConversation.Builder} in order, from oldest to newest.</p> 466 467<p>Then create the {@link android.support.v4.app.NotificationCompat.Builder 468NotificationCompat.Builder} 469object that builds the actual notification. You need to use the 470pending intents you created in the previous step.</p> 471 472<pre> 473NotificationCompat.Builder notificationBuilder = 474 new NotificationCompat.Builder(getApplicationContext()) 475 .setSmallIcon(smallIconResourceID) 476 .setLargeIcon(largeIconBitmap); 477</pre> 478 479<dl> 480 <dt><code>smallIconResourceID</code></dt> 481 <dd>The resource ID of a small icon to use for the conversation. This is 482 typically a generic icon for the messaging app.</dd> 483 484 <dt><code>largeIconBitmap</code></dt> 485 <dd>A {@link android.graphics.Bitmap} of a large version of the icon. This 486 is typically a conversation-specific graphic. For example, if this is a 487 chat app, the large icon would be a picture of the person the user is 488 chatting with.</dd> 489 490 <dt><code>messageString</code></dt> 491 <dd>The text of the message you want to send. (If you are sending several 492 messages at once, concatenate them into a single string, with the oldest 493 message first.)</dd> 494 495 <dt><code>currentTimestamp</code></dt> 496 <dd>The message timestamp. (If you are sending several messages at once, 497 use the timestamp of the most recent message.)</dd> 498 499 <dt><code>conversationName</code></dt> 500 501 <dd>The name you chose for this conversation (for example, the name of the 502 person the user is chatting with). This should be the same conversation 503 name you used when you created the {@link 504android.support.v4.app.NotificationCompat.CarExtender.UnreadConversation.Builder 505 UnreadConversation.Builder}.</dd> 506 507 <dt><code>msgHeardPendingIntent</code></dt> 508 <dd>The pending intent object you created in 509 <a href="#conversation-intents">Create conversation read and reply 510 intents</a>.</dd> 511</dl> 512 513 514<p>You'll also need to extend the {@link 515android.support.v4.app.NotificationCompat.Builder NotificationCompat.Builder} with the {@link 516android.support.v4.app.NotificationCompat.CarExtender CarExtender}. This is where you 517actually create the 518{@link android.support.v4.app.NotificationCompat.CarExtender.UnreadConversation 519UnreadConversation} object using the builder you 520just created, and attach it to the {@link 521android.support.v4.app.NotificationCompat.CarExtender CarExtender}:</p> 522 523<pre> 524notificationBuilder.extend(new CarExtender() 525 .setUnreadConversation(unreadConvBuilder.build()); 526</pre> 527 528<p class="note"><strong>Note:</strong> If you wish, you can set an override icon 529or color for the {@link android.support.v4.app.NotificationCompat.CarExtender 530CarExtender} by calling {@link 531android.support.v4.app.NotificationCompat.CarExtender#setLargeIcon 532setLargeIcon()} or {@link 533android.support.v4.app.NotificationCompat.CarExtender#setColor setColor()}. The 534override icon or color is used when the notification is handled by a car, and 535has no effect if the notification is handled on the Android device. This is 536useful if the notification's default icon or color are not suitable for the 537car's display.</p> 538 539<p>Once you've done all this, you use your app's {@link 540android.support.v4.app.NotificationManagerCompat} to send the notification:</p> 541 542<pre> 543NotificationManagerCompat msgNotificationManager = 544 NotificationManagerCompat.from(context); 545msgNotificationManager.notify(notificationTag, 546 notificationId, notificationBuilder.build()); 547</pre> 548 549<h2 id="handle_actions">Handle User Actions</h2> 550 551<p> 552 When your create and dispatch a notification for messaging, you specify intents to be triggered 553 when the Auto user hears the message and when the user dictates a reply. Your app indicates to 554 the Android framework that it handles these intends by registering them through its manifest, as 555 discussed in <a href="#manifest-intent">Define read and reply intent filters</a>. 556</p> 557 558<p> 559 In addition to registering these intent filters, your app must provide code to handle these 560 actions. Your app can do this by providing a service or {@link android.content.BroadcastReceiver} 561 objects that handle these intents.</p> 562 563<p> 564 For more information about intents, see <a href= 565 "{@docRoot}guide/components/intents-filters.html">Intents and Intent Filters</a>. 566</p> 567 568 569<h3 id="handling_msg_heard">Handling a message heard action</h3> 570 571<p> 572 When a user listens to a messaging conversation through the Auto user interface, the dashboard 573 device sends a read intent based on how your app defined the messaging notification. Your app 574 catches that intent and invokes the broadcast receiver class associated with it, or the service 575 method set up to handle that action. 576</p> 577 578<p> 579 The following code example shows how to define a {@link android.content.BroadcastReceiver} class 580 to handle a received message heard intent: 581</p> 582 583<pre> 584public class MyMessageHeardReceiver extends BroadcastReceiver { 585 586 @Override 587 public void onReceive(Context context, Intent intent) { 588 589 // If you set up the intent as described in 590 // "Create conversation read and reply intents", 591 // you can get the conversation ID by calling: 592 int thisConversationId = intent.getIntExtra("conversation_id", -1); 593 594 // Remove the notification to indicate it has been read 595 // and update the list of unread conversations in your app. 596 } 597} 598</pre> 599 600<p> 601 Once a notification is read, your app can remove it by calling 602 {@link android.support.v4.app.NotificationManagerCompat#cancel 603 NotificationManagerCompat.cancel()} with the notification ID. 604 Within your app, you should mark the messages provided in the notification as read. 605</p> 606 607 608<p class="note"> 609 <strong>Note:</strong> An alternative to this implementation is to use a service in a 610 {@link android.app.PendingIntent}. 611</p> 612 613 614<h3 id="handling_reply">Handling a reply action</h3> 615 616<p> 617 When a user replies to a messaging conversation through the Auto user interface, the dashboard 618 system sends a reply intent based on how your app defined the messaging notification. Your app 619 catches that intent and invokes the broadcast receiver class associated with it, or the service 620 method set up to handle that action. 621</p> 622 623<p> 624 The following code example shows how to define a {@link android.content.BroadcastReceiver} class 625 to handle a received message reply intent: 626</p> 627 628<pre> 629 public class MyMessageReplyReceiver extends BroadcastReceiver { 630 631 632 @Override 633 public void onReceive(Context context, Intent intent) { 634 // If you set up the intent as described in 635 // "Create conversation read and reply intents", 636 // you can get the conversation ID by calling: 637 int thisConversationId = intent.getIntExtra("conversation_id", -1). 638 639 } 640 641 /** 642 * Get the message text from the intent. 643 * Note that you should call 644 * RemoteInput.getResultsFromIntent() to process 645 * the RemoteInput. 646 */ 647 private CharSequence getMessageText(Intent intent) { 648 Bundle remoteInput = 649 RemoteInput.getResultsFromIntent(intent); 650 if (remoteInput != null) { 651 return remoteInput.getCharSequence(MY_VOICE_REPLY_KEY); 652 } 653 return null; 654 } 655 656}</pre> 657