Вы находитесь на странице: 1из 5

Implementing voice recognition

Now that our prototype can handle different presets, we should provide a fast way to
change, create, or edit user presets through voice recognition. One of the easiest ways to
manage voice recognition is to use Android's Intent messaging object to delegate this
action to another application component. As we discussed at the beginning of the chapter, if
we install and configure a compliant voice input application, Android can use it for voice
recognition.
The main goal is to provide an abstract class that will be extended by our activities in order
to manage recognition callback, while avoiding code repetition. The overall design is as
follows:

We should provide a common interface for activities that need voice recognition.

We should provide a startRecognition() method to launch the recognition


activity through the Intent object.

We should implement the onActivityResult() callback that will be called by the


launched activity when voice recognition ends. In this callback, we use the best
among all the results produced during the voice recognition process.

Note
Job delegation is one of the most useful features of the Android operating system. If
you need more information about how it works under the hood, take a look at the
Android official documentation at
http://developer.android.com/guide/components/intents-filters.html.
The preceding abstraction to reuse voice recognition capability can be achieved with the
following steps:
1. Add in the IRecognitionListener interface in the chronotherm package that
defines the onRecognitionDone() callback used to send back the result to the
caller activity. We can achieve this with the following code:
2. public interface IRecognitionListener {
3.
void onRecognitionDone(int requestCode, String bestMatch);
}

4. Create a new package called voice and add a new abstract class called
RecognizerActivity. This class should be defined as follows:
5. public abstract class RecognizerActivity extends ActionBarActivity
implements IRecognitionListener {

6. Add a public method to initialize the recognition phase, delegating the responsibility
for retrieving the results, with the following code:
7. public void startRecognition(String what, int requestCode) {
8.
Intent intent = new
Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH);
9.
intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE, "en-US");
10.
intent.putExtra(RecognizerIntent.EXTRA_PROMPT, what);
11.
startActivityForResult(intent, requestCode);
}

The requestCode parameter is the recognition Intent identifier and is used by the
caller activity to properly identify the result and how to handle it. The what
parameter is used to provide an on-screen message if the external application
supports it.
12. Add the onActivityResult() callback to extract the best result and pass it to the
caller activity through the common interface:
13. @Override
14. protected void onActivityResult(int requestCode, int resultCode,
Intent data) {
15.
if (resultCode == RESULT_OK) {
16.
ArrayList<String> matches =
data.getStringArrayListExtra(RecognizerIntent.EXTRA_RESULTS);
17.
this.onRecognitionDone(requestCode, matches.get(0));
18.
}
}

Using voice recognition to add or edit presets


Through the RecognizerActivity class, we delegate the hard work to the Android
framework. According to the nature of the activity, we should handle results in different
ways. We start using voice inputs with the Settings activity asking the name of the preset
we want to create or edit during the activity creation phase. If the preset exists, we should
load stored setpoints and update them during the save process. Otherwise, we should create
a new record in our preferences. To achieve this behavior, perform the following steps:
1. From the Settings class, extend RecognizerActivity in line with the following
snippet:
2. public class Settings extends RecognizerActivity {
3.
//...
}

4. Declare the intent request code that we will use to identify and handle the
recognized result. At the top of the class, add the highlighted code:

5. public class Settings extends RecognizerActivity {


6.
private static final int VOICE_SETTINGS = 1001;
7.
private TemperatureBar[] mBars;
8.
// ...
}

9. At the bottom of the onCreate() callback, add the following code to start voice
recognition as soon as possible:
10. mBars = TemperatureWidget.addTo(this, container, true);
11. startRecognition("Choose the preset you want to edit",
VOICE_SETTINGS);

12. Implement the onRecognitionDone() callback, required by the


IRecognitionListener interface previously defined, to handle the results returned
from the recognition intent. At the bottom of the class, add the following code:
13. @Override
14. public void onRecognitionDone(int requestCode, String bestMatch) {
15.
if (requestCode == VOICE_SETTINGS) {
16.
boolean result = readPreferences(bestMatch);
17.
mEditingPreset = bestMatch;
18.
}
}

If the recognition is related to the VOICE_SETTINGS intent code, the bestMatch


argument is passed to the readPreferences parameter that loads and sets all
temperature bars with preset setpoints. The mEditingPreset variable is set so that
we can reuse the preset name during the save process.
We have made all required changes for the Settings activity and now can proceed to use
voice recognition in the Overview activity to load and set the activated preset.

Using voice recognition to change active presets


Now that users can store different presets, we have to provide a way to change activated
setpoints in the Overview activity. Previously, we added a TextView class showing the
name of the current preset; to keep the interface lean, we could use this component also to
start voice recognition. The user can change the active preset through the current flow:
1. When users click on the TextView option, the system should start voice recognition
to get the preset name.
2. If the preset is found, the activated preset should be replaced with the one chosen by
the user and the Overview temperature bars should be updated.
3. If the preset is not found, nothing should happen.

To achieve the preceding interaction flow, proceed with the following steps:
1. As we did for the Settings activity, extend the RecognizerActivity class from
the Overview class, in line with the following snippet:
2. public class Overview extends RecognizerActivity implements
OnDataChangeListener {
3.
//...
}

4. Declare the intent request code that we will use to identify and handle the
recognized result. At the top of the class, add the highlighted code:
5. public class Overview extends RecognizerActivity implements
OnDataChangeListener {
6.
public static final int VOICE_PRESET = 1000;
7.
private AdkManager mAdkManager;
8.
//...
}

9. At the bottom of the class, add a method to start the preset name recognition:
10. public void changePreset(View v) {
11.
startRecognition("Choose the current preset", VOICE_PRESET);
}

12. Implement the onRecognitionDone() callback to handle the results returned from
the recognition intent. Within this method, we call the setPreset() member
function to update the active preset and load temperature setpoints, if the given
preset is found. At the bottom of the class, add the following code:
13. @Override
14. public void onRecognitionDone(int requestCode, String bestMatch) {
15.
if (requestCode == VOICE_PRESET) {
16.
setPreset(bestMatch);
17.
}
}

18. Implement the setPreset() method to handle the best recognized result. At the
bottom of the class, add the following code:
19. private void setPreset(String name) {
20.
ArrayList<Integer> values = Preset.get(this, name);
21.
if (values.size() > 0) {
22.
Preset.setCurrent(this, name);
23.
readPreferences();
24.
}
}

25. Connect the changePreset() method that starts voice recognition with the
TextView component. In the activity_overview.xml file under res/layout/,
make the current_preset view clickable with the highlighted code:
26. <TextView
27.
android:id="@+id/current_preset"
28.
android:clickable="true"
29.
android:onClick="changePreset"
30.
android:text="NO PRESET ACTIVATED"
31.
android:gravity="center"
32.
android:textColor="@color/coral_red"
33.
android:textSize="@dimen/text_title"
34.
android:layout_width="0dp"
35.
android:layout_weight="2"
android:layout_height="match_parent" />

With this last section, we have created an abstraction to handle voice recognition through
Android intents and we have updated the Settings and the Overview activities to use it.
Now we can upload the Chronotherm application and start using the application again with
presets and voice recognition features.

Вам также может понравиться