Home | History | Annotate | Download | only in notifications
      1 page.title=Receiving Voice Input in a Notification
      2 
      3 @jd:body
      4 
      5 <div id="tb-wrapper">
      6 <div id="tb">
      7 
      8 <h2>This lesson teaches you to</h2>
      9 <ol>
     10   <li><a href="#VoiceInput">Define the Voice Input</a></li>
     11   <li><a href="#AddAction">Add the Voice Input as a Notification Action</li>
     12   <li><a href="#ReceiveInput">Receiving the Voice Input as a String</a>
     13 </ol>
     14 
     15 </div>
     16 </div>
     17 
     18 <p>If you have handheld notifications that include an action to input text,
     19 such as reply to an email, it should normally launch an activity
     20 on the handheld device to input the text. However, when your notification appears on a wearable,
     21 there is no keyboard input, so you can let users dictate a reply or provide pre-defined text messages
     22 using {@link android.support.v4.app.RemoteInput}.
     23 </p>
     24 
     25 <p>When users reply with voice or select one of the available
     26 messages, the system attaches the text response to the {@link android.content.Intent} you specified
     27 for the notification action and sends that intent to your handheld app.</p>
     28 
     29 <img src="{@docRoot}wear/images/13_voicereply.png" height="200" width="169"
     30 style="float:right;margin:0 0 20px 40px;clear:right" />
     31 <img src="{@docRoot}wear/images/03_actions.png" height="200" width="169"
     32 style="float:right;margin:0 0 20px 40px" />
     33 
     34 <p class="note"><strong>Note:</strong> The Android emulator does not support voice input. When
     35 using the emulator for a wearable device, enable <b>Hardware keyboard present</b> in the AVD settings
     36 so you can type replies instead.</p>
     37 
     38 <h2 id="VoiceInput">Define the Voice Input</h2>
     39 
     40 <p>To create an action that supports voice input, create an instance of 
     41   {@link android.support.v4.app.RemoteInput.Builder} that you can add to your notification action.
     42   This class's constructor accepts a string that the system uses as
     43   the key for the voice input, which you'll later use to retrieve the text of the
     44   input in your handheld app.</p>
     45 
     46 <p>For example, here's how to create a
     47 {@link android.support.v4.app.RemoteInput} object that provides a custom
     48 label for the voice input prompt:</p>
     49 
     50 <pre class="prettyprint">
     51 // Key for the string that's delivered in the action's intent
     52 private static final String EXTRA_VOICE_REPLY = "extra_voice_reply";
     53 
     54 String replyLabel = getResources().getString(R.string.reply_label);
     55 
     56 RemoteInput remoteInput = new RemoteInput.Builder(EXTRA_VOICE_REPLY)
     57         .setLabel(replyLabel)
     58         .build();
     59 </pre>
     60 
     61 
     62 <h3>Add Pre-defined Text Responses</h3>
     63 
     64 <img src="{@docRoot}wear/images/12_voicereply.png" height="200"
     65 style="float:right;margin:0 0 20px 40px" />
     66 
     67 <p>In addition to allowing voice input, you can
     68     provide up to five text responses that the user can select for quick replies. Call
     69  {@link android.support.v4.app.RemoteInput.Builder#setChoices setChoices()} and pass it a string array.</p>
     70 
     71 <p>For example, you can define some responses in a resource array:</p>
     72 
     73 <p class="code-caption">res/values/strings.xml</code>
     74 <pre class="prettyprint">
     75 &lt;?xml version="1.0" encoding="utf-8"?>
     76 &lt;resources>
     77     &lt;string-array name="reply_choices">
     78         &lt;item>Yes&lt;/item>
     79         &lt;item>No&lt;/item>
     80         &lt;item>Maybe&lt;/item>
     81     &lt;/string-array>
     82 &lt;/resources>
     83 </pre>
     84 
     85 <p>Then, inflate the string array and add it to the
     86  {@link android.support.v4.app.RemoteInput}:</p>
     87 
     88 <pre>
     89 public static final EXTRA_VOICE_REPLY = "extra_voice_reply";
     90 ...
     91 String replyLabel = getResources().getString(R.string.reply_label);
     92 String[] replyChoices = getResources().getStringArray(R.array.reply_choices);
     93 
     94 RemoteInput remoteInput = new RemoteInput.Builder(EXTRA_VOICE_REPLY)
     95         .setLabel(replyLabel)
     96         .setChoices(replyChoices)
     97         .build();
     98 </pre>
     99 
    100 <h2 id="AddAction">Add the Voice Input as a Notification Action</h2>
    101 
    102 <p>
    103 To set the voice input, attach your
    104 {@link android.support.v4.app.RemoteInput} object to an action using
    105 {@link android.support.v4.app.NotificationCompat.Action.Builder#addRemoteInput addRemoteInput()}.
    106 You can then apply the action to the notification. For example:
    107 </p>
    108 
    109 <pre>
    110 // Create an intent for the reply action
    111 Intent replyIntent = new Intent(this, ReplyActivity.class);
    112 PendingIntent replyPendingIntent =
    113         PendingIntent.getActivity(this, 0, replyIntent,
    114                 PendingIntent.FLAG_UPDATE_CURRENT);
    115 
    116 // Create the reply action and add the remote input
    117 NotificationCompat.Action action =
    118         new NotificationCompat.Action.Builder(R.drawable.ic_reply_icon,
    119                 getString(R.string.label, replyPendingIntent))
    120                 .addRemoteInput(remoteInput)
    121                 .build();
    122 
    123 // Build the notification and add the action via WearableExtender
    124 Notification notification =
    125         new NotificationCompat.Builder(mContext)
    126                 .setSmallIcon(R.drawable.ic_message)
    127                 .setContentTitle(getString(R.string.title))
    128                 .setContentText(getString(R.string.content))
    129                 .extend(new WearableExtender().addAction(action))
    130                 .build();
    131 
    132 // Issue the notification
    133 NotificationManagerCompat notificationManager =
    134         NotificationManagerCompat.from(mContext);
    135 notificationManager.notify(notificationId, notification);
    136 </pre>
    137 <p>
    138 When you issue this notification, users can swipe to the left to see the "Reply" action button.
    139 </p>
    140 
    141 <h2 id="ReceiveInput">Receiving the Voice Input as a String</h2>
    142 <p>
    143 To receive the user's transcribed message in the activity you declared in the reply action's intent,
    144 call {@link android.support.v4.app.RemoteInput#getResultsFromIntent getResultsFromIntent()},
    145 passing in the "Reply" action's intent. This method returns a {@link android.os.Bundle} that
    146 contains the text response. You can then query the {@link android.os.Bundle} to obtain the response.
    147 
    148 <p class="note"><b>Note:</b> Do not use {@link android.content.Intent#getExtras Intent.getExtras()}
    149 to obtain the voice result, because the voice input is stored as
    150 {@link android.content.ClipData}. The {@link android.support.v4.app.RemoteInput#getResultsFromIntent
    151 getResultsFromIntent()} method provides a convenient way to receive a character sequence without
    152 having to process the {@link android.content.ClipData} yourself.
    153 </p>
    154 
    155 <p>
    156 The following code shows a method that accepts an intent and returns the voice response,
    157 which is referenced by the <code>EXTRA_VOICE_REPLY</code> key that is used in the previous examples:
    158 </p>
    159 
    160 <pre>
    161 /**
    162  * Obtain the intent that started this activity by calling
    163  * Activity.getIntent() and pass it into this method to
    164  * get the associated voice input string.
    165  */
    166 
    167 private CharSequence getMessageText(Intent intent) {
    168     Bundle remoteInput = RemoteInput.getResultsFromIntent(intent);
    169         if (remoteInput != null) {
    170             return remoteInput.getCharSequence(EXTRA_VOICE_REPLY);
    171         }
    172     }
    173     return null;
    174 }
    175 </pre>