Статьи

Android SDK: создайте приложение «Говори и повторяй»

Платформа Android обеспечивает поддержку как распознавания речи, так и синтеза речи. В этом уроке мы создадим простое приложение для Android, которое позволяет пользователю говорить, пытается распознать то, что он говорит, а затем повторяет то, что было ему распознано, с помощью механизма преобразования текста в речь.

Мы будем использовать ту же технику для движка TTS, что и в Android SDK: с использованием движка Text to Speech Engine , поэтому основное внимание в этом уроке будет уделено элементу распознавания речи. Как распознавание, так и синтез речи относительно легко реализовать на платформе Android, поэтому вы сможете выполнить шаги, описанные в этом руководстве, даже если вы новичок в Android.


Создайте новый проект Android в Eclipse. В качестве альтернативы, если вы хотите реализовать функцию распознавания речи в существующем приложении, откройте его. Для этого урока у нас есть минимальная версия SDK 8, и вам не нужно вносить какие-либо конкретные дополнения в ваш файл манифеста, достаточно содержимого по умолчанию.


Давайте начнем с определения пользовательского интерфейса. Когда приложение запустится, пользователю будет представлена ​​кнопка. При нажатии на кнопку приложение предложит им говорить, прослушивая их голосовой ввод. Когда утилита распознавания речи обрабатывает ввод речи, приложение представляет пользователю список предлагаемых слов. Как вы знаете, если вы пробовали распознавать речь как пользователь, распознаватель не всегда точен, поэтому этот список необходим. Когда пользователь выбирает элемент из списка, приложение сообщит его ему с помощью механизма TTS. Часть приложения TTS является необязательной, поэтому вы можете опустить ее, если хотите.

Приложение будет использовать несколько текстовых строк в качестве части интерфейса, поэтому определите их, открыв файл res / values ​​/ strings.xml и введя следующее содержимое:

1
2
3
4
5
6
<resources>
    <string name=»intro»>Press the button to speak!</string>
    <string name=»app_name»>SpeechRepeat</string>
    <string name=»speech»>Speak now!</string>
    <string name=»word_intro»>Suggested words&#8230;</string>
</resources>

Конечно, вы можете изменять содержимое String так, как вам нравится.

Откройте файл «res / layout / main.xml», чтобы создать основной макет приложения. Переключитесь на редактор XML, если графический редактор отображается по умолчанию. Введите линейный макет в качестве основного макета для запуска приложения.

1
2
3
4
5
6
7
8
<LinearLayout xmlns:android=»http://schemas.android.com/apk/res/android»
    android:layout_width=»fill_parent»
    android:layout_height=»fill_parent»
    android:orientation=»vertical»
    android:background=»#ff330066″
    android:paddingBottom=»5dp» >
 
</LinearLayout>

Линейный макет содержит различные объявления стиля, включая цвет фона. Внутри линейного макета сначала введите информативное текстовое представление:

1
2
3
4
5
6
7
8
<TextView android:layout_width=»fill_parent»
    android:layout_height=»wrap_content»
    android:text=»@string/intro»
    android:padding=»5dp»
    android:textStyle=»bold»
    android:textSize=»16dp»
    android:gravity=»center»
    android:textColor=»#ffffff33″ />

Обратите внимание, что текстовое представление относится к одной из определенных нами строк. Он также устанавливает различные свойства дисплея, которые вы можете изменить, если хотите. После просмотра текста добавьте кнопку:

1
2
3
4
<Button android:id=»@+id/speech_btn»
    android:layout_width=»match_parent»
    android:layout_height=»wrap_content»
    android:text=»@string/speech» />

Пользователь будет нажимать эту кнопку, чтобы говорить. Мы даем кнопке идентификатор, чтобы мы могли идентифицировать ее в коде Java и отобразить одну из строк, которые мы определили для нее. После кнопки добавьте еще один информативный текстовый вид, который будет предшествовать списку предлагаемых слов:

1
2
3
4
5
<TextView android:layout_width=»fill_parent»
    android:layout_height=»wrap_content»
    android:padding=»5dp»
    android:text=»@string/word_intro»
    android:textStyle=»italic» />

Опять же, это текстовое представление использует ресурс String и содержит свойства стиля. Последний элемент нашего main.xml Linear Layout — это список предлагаемых слов:

01
02
03
04
05
06
07
08
09
10
11
12
13
<ListView android:id=»@+id/word_list»
    android:layout_width=»fill_parent»
    android:layout_height=»0dip»
    android:layout_weight=»1″
    android:paddingLeft=»10dp»
    android:paddingTop=»3dp»
    android:paddingRight=»10dp»
    android:paddingBottom=»3dp»
    android:layout_marginLeft=»20dp»
    android:layout_marginRight=»20dp»
    android:layout_marginTop=»5dp»
    android:layout_marginBottom=»5dp»
    android:background=»@drawable/words_bg» />

Представление списка будет заполняться данными при запуске приложения, поэтому мы даем ему идентификатор для идентификации в Java. Элемент также ссылается на ресурс drawable, который вы должны добавить в каждую из папок drawables в каталоге res вашего приложения, сохранив его как «words_bg.xml» и введя следующее содержимое:

01
02
03
04
05
06
07
08
09
10
11
12
<shape xmlns:android=»http://schemas.android.com/apk/res/android»
    android:dither=»true»>
    <gradient
    android:startColor=»#ff000000″
    android:endColor=»#ff000000″
    android:centerColor=»#00000000″
    android:angle=»180″ />
    <corners android:radius=»10dp» />
    <stroke
    android:width=»2dp»
    android:color=»#66ffffff» />
</shape>

Это простая фигура, которую можно отобразить за списком. Конечно, вы можете изменить это и свойства стиля представления списка, если хотите. Единственный оставшийся элемент пользовательского интерфейса, который нам нужно определить сейчас, — это макет для одного элемента в списке, каждый из которых будет отображать предложение слова. Создайте новый файл в «res / layout» с именем «word.xml», а затем введите следующий код:

1
2
3
4
5
6
7
8
<TextView xmlns:android=»http://schemas.android.com/apk/res/android»
    android:layout_width=»fill_parent»
    android:layout_height=»fill_parent»
    android:gravity=»center»
    android:padding=»5dp»
    android:textColor=»#ffffffff»
    android:textSize=»16dp» >
</TextView>

Каждый элемент в списке будет простым текстовым представлением. Это наш дизайн интерфейса завершен. Вот как приложение появляется при первом запуске:

Говорить и повторять запуск

Примечание: не беспокойтесь по поводу отсутствия сглаживания, именно так это выглядит на скриншоте DDMS. На самом устройстве градиент идеально плавный.


Теперь мы можем реализовать наш код Java. Откройте главное действие вашего приложения и добавьте следующие операторы импорта вверху:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
 
import android.app.Activity;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.os.Bundle;
import android.speech.RecognizerIntent;
import android.speech.tts.TextToSpeech.OnInitListener;
import android.speech.tts.TextToSpeech;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.ListView;
import android.widget.Toast;
import android.widget.TextView;

Вам может не понадобиться все это, если вы не реализуете функциональность TTS — Eclipse должен выделить импорт, который вы не использовали, поэтому проверяйте его, когда закончите кодирование. Расширьте строку объявления начального класса следующим образом, изменив имя Activity в соответствии со своим:

1
public class SpeechRepeatActivity extends Activity implements OnClickListener, OnInitListener {

OnInitListener требуется только для функции TTS. Добавьте следующие переменные экземпляра в объявление класса перед методом «onCreate»:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
//voice recognition and general variables
 
//variable for checking Voice Recognition support on user device
private static final int VR_REQUEST = 999;
     
//ListView for displaying suggested words
private ListView wordList;
     
//Log tag for output information
private final String LOG_TAG = «SpeechRepeatActivity»;//***enter your own tag here***
 
//TTS variables
 
//variable for checking TTS engine data on user device
private int MY_DATA_CHECK_CODE = 0;
     
//Text To Speech instance
private TextToSpeech repeatTTS;

Внутри вашего метода onCreate ваш класс уже должен вызывать метод суперкласса и устанавливать основной макет. Если нет, это должно начаться так:

1
2
3
4
//call superclass
super.onCreate(savedInstanceState);
//set content view
setContentView(R.layout.main);

Затем, все еще внутри вашего метода «onCreate», извлеките ссылку на кнопку речи и список, который мы создали, используя их значения ID:

1
2
3
4
//gain reference to speak button
Button speechBtn = (Button) findViewById(R.id.speech_btn);
//gain reference to word list
wordList = (ListView) findViewById(R.id.word_list);

Представление списка — это переменная экземпляра, доступная по всему классу. Теперь нам нужно выяснить, имеет ли пользовательское устройство поддержку распознавания речи:

01
02
03
04
05
06
07
08
09
10
11
12
13
//find out whether speech recognition is supported
PackageManager packManager = getPackageManager();
List<ResolveInfo> intActivities = packManager.queryIntentActivities(new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH), 0);
if (intActivities.size() != 0) {
    //speech recognition is supported — detect user button clicks
    speechBtn.setOnClickListener(this);
}
else
{
    //speech recognition not supported, disable button and output message
    speechBtn.setEnabled(false);
    Toast.makeText(this, «Oops — Speech recognition not supported!», Toast.LENGTH_LONG).show();
}

Мы запрашиваем среду, чтобы узнать, присутствует ли намерение распознавателя. Если это так, мы инструктируем приложение для прослушивания пользователя, нажав кнопку речи. Если распознавание речи не поддерживается, мы просто отключаем кнопку и выводим информативное сообщение пользователю.


Давайте настроим прослушиватель щелчков для речевой кнопки, для которой мы указали приложению обнаруживать щелчки. Вне метода «onCreate», но внутри объявления класса Activity добавьте метод «onClick» следующим образом:

1
2
3
4
5
6
7
8
9
/**
 * Called when the user presses the speak button
 */
public void onClick(View v) {
    if (v.getId() == R.id.speech_btn) {
        //listen for results
        listenToSpeech();
    }
}

Теперь реализуем метод, который мы здесь вызвали после метода «onClick»:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
/**
 * Instruct the app to listen for user speech input
 */
private void listenToSpeech() {
         
    //start the speech recognition intent passing required data
    Intent listenIntent = new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH);
    //indicate package
    listenIntent.putExtra(RecognizerIntent.EXTRA_CALLING_PACKAGE, getClass().getPackage().getName());
    //message to display while listening
    listenIntent.putExtra(RecognizerIntent.EXTRA_PROMPT, «Say a word!»);
    //set speech model
    listenIntent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL, RecognizerIntent.LANGUAGE_MODEL_FREE_FORM);
    //specify number of results to retrieve
    listenIntent.putExtra(RecognizerIntent.EXTRA_MAX_RESULTS, 10);
 
    //start listening
    startActivityForResult(listenIntent, VR_REQUEST);
}

Часть этого кода является стандартной для настройки функции прослушивания распознавания речи. Области, на которые следует обратить особое внимание, чтобы включить строку, в которой мы указываем «EXTRA_PROMPT» — вы можете изменить это, чтобы включить текст, который вы хотите отображать для побуждения пользователя говорить. Также обратите внимание на строку «EXTRA_MAX_RESULTS», в которой мы указываем, сколько предложений мы хотим, чтобы распознаватель возвращал, когда говорит пользователь. Поскольку мы вызываем метод «startActivityForResult», мы будем обрабатывать результаты распознавателя в методе «onActivityResult».

Когда приложение прослушивает речь пользователя, оно будет выглядеть следующим образом:

Говорить и повторять прослушивание

Реализуйте метод onActivityResult в объявлении класса следующим образом:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
/**
 * onActivityResults handles:
 * — retrieving results of speech recognition listening
 * — retrieving result of TTS data check
 */
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    //check speech recognition result
    if (requestCode == VR_REQUEST && resultCode == RESULT_OK)
    {
        //store the returned word list as an ArrayList
        ArrayList<String> suggestedWords = data.getStringArrayListExtra(RecognizerIntent.EXTRA_RESULTS);
        //set the retrieved list to display in the ListView using an ArrayAdapter
        wordList.setAdapter(new ArrayAdapter<String> (this, R.layout.word, suggestedWords));
    }
         
    //tss code here
 
    //call superclass method
    super.onActivityResult(requestCode, resultCode, data);
}

Здесь мы получаем результат процесса распознавания речи. Обратите внимание, что оператор «if» проверяет, является ли код запроса переменной, которую мы передали при вызове «startActivityForResult», и в этом случае мы знаем, что этот метод вызывается в результате прослушивания Intent. Распознаватель возвращает список из 10 предложенных слов, который мы храним в виде массива. Затем мы заполняем представление списка этими словами, устанавливая объект адаптера массива в качестве адаптера для представления. Теперь каждый из элементов в представлении списка будет отображать одно из предложенных слов.

Если приложение успешно распознает введенную пользователем речь и возвращает список слов, оно будет выглядеть следующим образом:

Говори и повторяй список слов

Кроме того, если приложение не распознает ввод речи пользователем, появится следующий экран:

Говорить и повторять не удалось распознать

Мы хотим обнаружить, что пользователь выбирает слова из списка, поэтому давайте реализуем прослушиватель щелчков для элементов списка. Вернувшись в метод «onCreate», после существующего кода установите прослушиватель для каждого элемента в списке следующим образом:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
//detect user clicks of suggested words
wordList.setOnItemClickListener(new OnItemClickListener() {
             
    //click listener for items within list
    public void onItemClick(AdapterView<?> parent, View view, int position, long id)
    {
        //cast the view
        TextView wordView = (TextView)view;
        //retrieve the chosen word
        String wordChosen = (String) wordView.getText();
        //output for debugging
        Log.v(LOG_TAG, «chosen: «+wordChosen);
        //output Toast message
        Toast.makeText(SpeechRepeatActivity.this, «You said: «+wordChosen, Toast.LENGTH_SHORT).show();//**alter for your Activity name***
    }
});

Мы используем метод «setOnItemClickListener», чтобы назначить слушателя каждому элементу в списке. Внутри нового OnItemClickListener мы реализуем метод onItemClick для реагирования на эти щелчки — этот метод будет срабатывать, когда пользователь выбирает предложенное слово из списка. Сначала мы приводим представление, которое было нажато, к текстовому представлению, а затем извлекаем текст из него. Этот текст — слово, выбранное пользователем. Мы записываем выбранное слово в Журнал для тестирования и выводим его обратно пользователю в виде сообщения Toast. В зависимости от потребностей вашего собственного приложения, вы можете выполнить дальнейшую обработку выбранного слова — этот код предназначен исключительно для демонстрации.

Пользователь может нажимать на сенсорный экран или использовать трекбол для выбора слов в списке.

Говорить и повторять выбор слов

Когда пользователь выбирает слово, появляется сообщение Toast, подтверждающее его.

Говори и повторяй тост

Если вы не хотите реализовывать функциональность Text To Speech, вы можете остановиться и протестировать свое приложение. Нам нужно лишь немного больше обработки, чтобы наше приложение повторяло выбранное пользователем слово. Во-первых, чтобы настроить механизм TTS, добавьте следующий код в раздел метода «onCreate», где вы запросили систему для поддержки распознавания речи. Внутри оператора «if» после «speechBtn.setOnClickListener (this);»:

1
2
3
4
5
6
//prepare the TTS to repeat chosen words
Intent checkTTSIntent = new Intent();
//check TTS data
checkTTSIntent.setAction(TextToSpeech.Engine.ACTION_CHECK_TTS_DATA);
//start the checking Intent — will retrieve result in onActivityResult
startActivityForResult(checkTTSIntent, MY_DATA_CHECK_CODE);

Как и в процессе прослушивания речи, мы получим результат проверки кода для данных TTS в методе «onActivityResult». В этом методе перед строкой, в которой мы вызываем метод суперкласса «onActivityResult», добавьте следующее:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
//returned from TTS data check
if (requestCode == MY_DATA_CHECK_CODE)
{
    //we have the data — create a TTS instance
    if (resultCode == TextToSpeech.Engine.CHECK_VOICE_DATA_PASS)
        repeatTTS = new TextToSpeech(this, this);
    //data not installed, prompt the user to install it
    else
    {
        //intent will take user to TTS download page in Google Play
        Intent installTTSIntent = new Intent();
        installTTSIntent.setAction(TextToSpeech.Engine.ACTION_INSTALL_TTS_DATA);
        startActivity(installTTSIntent);
    }
}

Здесь мы инициализируем TTS, если данные уже установлены, в противном случае мы предлагаем пользователю установить его. Дополнительные инструкции по использованию механизма TTS см. В учебнике по Android SDK: Использование механизма преобразования текста в речь .

Чтобы завершить настройку TTS, добавьте метод onInit к объявлению класса, обрабатывая инициализацию TTS следующим образом:

1
2
3
4
5
6
7
8
/**
 * onInit fires when TTS initializes
 */
public void onInit(int initStatus) {
    //if successful, set locale
    if (initStatus == TextToSpeech.SUCCESS)
        repeatTTS.setLanguage(Locale.UK);//***choose your own locale here***
}

Здесь мы просто устанавливаем локаль для TTS, но вы можете выполнять другие задачи по настройке, если хотите.


Наконец, мы можем повторить выбранное пользователем слово. Вернувшись в метод «onCreate», в метод «OnItemClickListener» «onItemClick», после строки, в которой мы выводим сообщение Toast, добавьте следующее:

1
2
//speak the word using the TTS
repeatTTS.speak(«You said: «+wordChosen, TextToSpeech.QUEUE_FLUSH, null);

Это заставит приложение повторить выбранное пользователем слово как часть простой фразы. Это произойдет одновременно с появлением сообщения Toast.


Это наше полное приложение «Говори и повторяй». Протестируйте его на устройстве Android с поддержкой распознавания речи и поддержкой TTS — эмулятор не поддерживает распознавание речи, поэтому вам необходимо протестировать эту функцию на реальном устройстве . Исходный код прилагается, поэтому вы можете проверить, все ли у вас в нужном месте. Конечно, ваши собственные приложения могут реализовать распознавание речи как часть другой обработки, но это руководство должно было предоставить вам основы поддержки речевого ввода.