Rheinwerk Computing < openbook >

 
Inhaltsverzeichnis
Vorwort
Teil I Grundlagen
1 Android – eine offene, mobile Plattform
2 Hallo Android!
3 Von der Idee zur Veröffentlichung
Teil II Elementare Anwendungsbausteine
4 Wichtige Grundbausteine von Apps
5 Benutzeroberflächen
6 Multitasking
Teil III Gerätefunktionen nutzen
7 Telefonieren und surfen
8 Sensoren, GPS und Bluetooth
Teil IV Dateien und Datenbanken
9 Dateien lesen, schreiben und drucken
10 Datenbanken
Teil V Multimedia und Produktivität
11 Multimedia
12 Kontakte und Organizer
A Einführung in Kotlin
B Jetpack Compose
C Häufig benötigte Codebausteine
D Literaturverzeichnis
E Die Begleitmaterialien
Stichwortverzeichnis

Ihre Meinung?
Spacer
<< zurück
Android 11 von Thomas Künneth
Das Praxisbuch für App-Entwickler
Buch: Android 11

Android 11
Pfeil 11 Multimedia
Pfeil 11.1 Audio
Pfeil 11.1.1 Audio aufnehmen und abspielen
Pfeil 11.1.2 Effekte
Pfeil 11.2 Sprachverarbeitung
Pfeil 11.2.1 Sprachsynthese
Pfeil 11.2.2 Spracherkennung
Pfeil 11.3 Fotos und Video
Pfeil 11.3.1 Vorhandene Funktionen nutzen
Pfeil 11.3.2 Die eigene Kamera-App
Pfeil 11.3.3 Videos drehen
Pfeil 11.4 Zusammenfassung
 
Zum Seitenanfang

11.2    Sprachverarbeitung Zur vorigen ÜberschriftZur nächsten Überschrift

Schon seit Android 1.6 (Donut) enthält die Plattform eine Komponente zur Sprachsynthese. Zunächst wurde das quelloffene Pico verwendet. Mittlerweile ist die Google Sprachausgabe Standard. Diese kann in vielen Sprachen Texte vorlesen, unter anderem auf Deutsch, Englisch, Italienisch, Französisch und Spanisch. In diesem Abschnitt zeige ich Ihnen, wie Sie Ihre Apps um die Fähigkeit erweitern, mit dem Anwender zu »sprechen«. Wie praktisch das ist, wissen wir spätestens durch die Benutzung von Navigationshilfen, aber die Einsatzmöglichkeiten sind weitaus vielfältiger. Lassen Sie sich doch Ihre E-Mails vorlesen. Oder programmieren Sie eine App, die Ihnen auf Knopfdruck die aktuelle Uhrzeit ansagt.

 
Zum Seitenanfang

11.2.1    Sprachsynthese Zur vorigen ÜberschriftZur nächsten Überschrift

Welche Schritte notwendig sind, um geschriebene in gesprochene Sprache umzuwandeln, möchte ich Ihnen anhand der App TextToSpeechDemo zeigen. Bevor ich Sie mit der Implementierung vertraut mache, sollten Sie die App kurz starten. Die Benutzeroberfläche sehen Sie in Abbildung 11.3.

Die App »TextToSpeechDemo«

Abbildung 11.3    Die App »TextToSpeechDemo«

Tippen Sie einen beliebigen Text ins Eingabefeld, und wählen Sie dann die gewünschte Sprache. Bitte beachten Sie, dass Sprachpakete möglicherweise erst über die Systemeinstellungen heruntergeladen und aktiviert werden müssen. Ein Klick auf TEXT VORLESEN startet den Synthesevorgang und anschließend die Wiedergabe. Während der Text vorgelesen wird, ist die Schaltfläche nicht anwählbar.

Die Klasse TextToSpeechDemoActivity leitet von AppCompatActivity ab und implementiert unter anderem onCreate() und onDestroy(). Wenn Sie einen Blick auf Listing 11.5 werfen, fällt Ihnen bestimmt auf, dass onCreate() nicht wie üblich die Benutzeroberfläche initialisiert und anzeigt. Stattdessen wird »nur« die Variable tts mit null belegt und mit startActivityForResult() eine neue Activity aufgerufen. tts zeigt auf ein Objekt des Typs android.speech.tts.TextToSpeech. Diese Klasse bildet die Zugriffsschicht auf die Sprachsynthesekomponente. onDestroy() gibt alle Ressourcen frei, die von der Syntheseeinheit reserviert wurden. Hierzu ruft sie deren Methode shutdown() auf.

Installation prüfen

Die eigentliche Sprachsynthesesoftware ist zwar Bestandteil der Plattform, allerdings steht es Geräteherstellern frei, die Sprachdaten nicht vorzuinstallieren, um Platz zu sparen. Deshalb wird ein Intent mit der Action ACTION_CHECK_TTS_DATA gefeuert, um deren Verfügbarkeit zu prüfen. Meldet das System beim Aufruf von startActivityForResult() mit CHECK_VOICE_DATA_PASS, dass alles in Ordnung ist, kann das Text-to-Speech-Modul mit tts = TextToSpeech(this, this) initialisiert werden. Andernfalls müssen Sie mit einem weiteren Intent mit der Aktion ACTION_INSTALL_TTS_DATA den Download der fehlenden Daten initiieren. Meine Implementierung beendet sich nach dem Aufruf der Methode startActivityForResult() mit finish(). Alternativ könnten Sie zum Beispiel einen Fortschrittsbalken anzeigen.

package com.thomaskuenneth.androidbuch.texttospeechdemo

import android.content.Intent
import android.os.*
import android.speech.tts.TextToSpeech
import android.speech.tts.UtteranceProgressListener
import android.util.Log
import android.widget.ArrayAdapter
import androidx.appcompat.app.AppCompatActivity
import kotlinx.android.synthetic.main.activity_main.*
import java.io.File
import java.util.*

private const val CHECK_TTS_DATA = 1
private val TAG = TextToSpeechDemoActivity::class.simpleName
class TextToSpeechDemoActivity : AppCompatActivity(), TextToSpeech.OnInitListener {
private val supportedLanguages = Hashtable<String, Locale>()
private var tts: TextToSpeech? = null
private var lastUtteranceId: String? = null

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// die Sprachsynthesekomponente wurde
// noch nicht initialisiert
tts = null
// prüfen, ob Sprachpakete vorhanden sind
val intent = Intent()
intent.action = TextToSpeech.Engine.ACTION_CHECK_TTS_DATA
startActivityForResult(intent, CHECK_TTS_DATA)
}

// ggf. Ressourcen freigeben
override fun onDestroy() {
super.onDestroy()
tts?.shutdown()
}

override fun onActivityResult(
requestCode: Int,
resultCode: Int,
data: Intent?
) {
super.onActivityResult(requestCode, resultCode, data)
// Sind Sprachpakete vorhanden?
if (requestCode == CHECK_TTS_DATA) {
if (resultCode ==
TextToSpeech.Engine.CHECK_VOICE_DATA_PASS
) {
// Initialisierung der Sprachkomponente starten
tts = TextToSpeech(this, this)
} else {
// Installation der Sprachpakete vorbereiten
val installIntent = Intent()
installIntent.action =
TextToSpeech.Engine.ACTION_INSTALL_TTS_DATA
startActivity(installIntent)
// Activity beenden
finish()
}
}
}

override fun onInit(status: Int) {
if (status != TextToSpeech.SUCCESS) {
// die Initialisierung war nicht erfolgreich
finish()
}
Log.d(TAG, "Standard: ${tts?.defaultEngine}")
tts?.engines?.forEach {
Log.d(TAG, "${it.label} (${it.name})")
}
// Activity initialisieren
setContentView(R.layout.activity_main)
button.setOnClickListener {
val text = input.text.toString()
val key = spinner.selectedItem as String
supportedLanguages[key]?.let {
button.isEnabled = false
tts?.language = it
lastUtteranceId = System
.currentTimeMillis().toString()
tts?.speak(
text, TextToSpeech.QUEUE_FLUSH,
null, lastUtteranceId
)
// in Datei schreiben
val file = File(filesDir, "${lastUtteranceId}.wav")
tts?.synthesizeToFile(text, null, file, lastUtteranceId)
Log.d(TAG, file.absolutePath)
}
}
tts?.setOnUtteranceProgressListener(
object : UtteranceProgressListener() {
override fun onStart(utteranceId: String) {
Log.d(TAG, "onStart(): $utteranceId")
}

override fun onDone(utteranceId: String) {
Log.d(TAG, "onDone(): $utteranceId")
if (utteranceId == lastUtteranceId) {
Handler(Looper.getMainLooper()).post {
button.isEnabled = true
}
}
}

override fun onError(utteranceId: String) {
Log.d(TAG, "onError(): $utteranceId")
}
})
// Liste der Sprachen ermitteln
val languages = Locale.getISOLanguages()
for (lang in languages) {
val loc = Locale(lang)
when (tts?.isLanguageAvailable(loc)) {
TextToSpeech.LANG_MISSING_DATA,
TextToSpeech.LANG_NOT_SUPPORTED -> {
Log.d(TAG, "language not available for $loc")
}
else -> {
val key = loc.displayLanguage
if (!supportedLanguages.containsKey(key)) {
supportedLanguages[key] = loc
}
}
}
}
val adapter = ArrayAdapter<Any>(
this,
android.R.layout.simple_spinner_item, supportedLanguages
.keys.toTypedArray()
)
adapter.setDropDownViewResource(
android.R.layout.simple_spinner_dropdown_item
)
spinner.adapter = adapter
}
}

Listing 11.5    Die Klasse »TextToSpeechDemoActivity«

Das Sprachausgabemodul darf erst nach einer erfolgreichen Initialisierung verwendet werden. Aus diesem Grund wird dem Konstruktor der Klasse TextToSpeech als zweites Argument ein Objekt des Typs android.speech.tts.TextToSpeech.OnInitListener übergeben. Da die Activity TextToSpeechDemoActivity dieses Interface implementiert, finden Sie an dieser Stelle nur ein this.

Meine Implementierung der Methode onInit() erledigt einige Aufgaben, die sonst üblicherweise in onCreate() ausgeführt werden, beispielsweise das Anzeigen der Benutzeroberfläche mit setContentView(). Das ist notwendig, weil unter anderem die Aufklappliste für die Sprachauswahl erst nach einer erfolgreichen Initialisierung der Synthesekomponente gefüllt werden kann. Vielleicht fragen Sie sich, warum ich die bekannten Sprachen nicht einfach »fest verdrahte«. Ganz einfach: Sollten irgendwann weitere Sprachen hinzukommen, erkennt mein Programm (und Ihre App, sollten Sie auch so vorgehen) diese automatisch.

[+]  Tipp

Treffen Sie niemals Annahmen über die Beschaffenheit eines Systems, wenn es stattdessen Auskunftsfunktionen gibt.

Sie können mit isLanguageAvailable() prüfen, ob eine bestimmte Sprache der Synthesekomponente zur Verfügung steht.

Texte vorlesen und Sprachausgaben speichern

Um einen Text vorlesen zu lassen, rufen Sie die Methode speak() eines TextToSpeech-Objekts auf. Ihr wird unter anderem ein Bundle übergeben, das Daten für die Anfrage enthält. Dieses Bundle kann auf null gesetzt werden. Die Utterance-ID ist eine eindeutige Kennung, mit der der vorzulesende Text identifiziert wird.

Ist Ihnen in der Implementierung der Methode onInit() der Aufruf der Methode setOnUtteranceProgressListener() aufgefallen? Die abstrakte Klasse UtteranceProgressListener enthält die Methoden onStart(), onDone() und onError(), die im Verlauf einer Sprachausgabe angesprungen werden können. Beispielsweise signalisiert der Aufruf von onDone(), dass eine Textausgabe vollständig durchgeführt wurde. Welche das war, können Sie anhand der Utterance-ID erkennen. Die Implementierung in der Klasse TextToSpeechDemoActivity macht die Schaltfläche TEXT VORLESEN wieder anwählbar. Wenn Sie in onDone() den Status von Bedienelementen verändern möchten, sollten Sie sicherstellen, dass Ihre Anweisungen auf dem UI-Thread ausgeführt werden. Instanziieren Sie hierzu mit Handler(Looper.getMainLooper()) ein Objekt des Typs android.os.Handler, und rufen Sie dessen post()-Methode auf. Weitere Informationen hierzu finden Sie in Kapitel 6, »Multitasking«.

Sie können TextToSpeech-Objekte nicht nur für die direkte Ausgabe von Sprache verwenden. Die Klasse enthält die Methode synthesizeToFile(), mit der sich das akustische Signal als .wav-Datei abspeichern lässt. Meine Implementierung nutzt hierfür das private Verzeichnis (filesDir). Um das Speichern auszuprobieren, geben Sie nach dem Start der App einen beliebigen Text ein, und wählen Sie die gewünschte Sprache. Klicken Sie anschließend auf TEXT VORLESEN. Sobald Android die Sprachausgabe beendet, erscheint die Datei im Device File Explorer (Abbildung 11.4).

Mit »synthesizeToFile()« erzeugte Dateien

Abbildung 11.4    Mit »synthesizeToFile()« erzeugte Dateien

Android kann Sprache nicht nur synthetisieren, sondern auch erkennen. Ihre App könnte also ausschließlich in gesprochener Sprache mit dem Anwender kommunizieren. Nutzer von Navigationssystemen haben diese Form der Bedienung schätzen gelernt, und auch in vielen anderen Bereichen ist Spracherkennung äußerst praktisch. Denken Sie an das automatische Wählen nach Nennung eines Kontakts oder an die Steuerung des Telefons durch einfache mündliche Anweisungen. Im folgenden Abschnitt zeige ich Ihnen, wie Sie die in die Plattform integrierte Spracherkennungsfunktion in Ihren Apps nutzen.

 
Zum Seitenanfang

11.2.2    Spracherkennung Zur vorigen ÜberschriftZur nächsten Überschrift

Mein Beispiel SpeechRecognitionDemo zeigt, wie einfach sich eine Spracherkennung in eigenen Programmen einsetzen lässt. Nach dem Start begrüßt die App den Benutzer mit einem bis auf den Button Spracherkennung starten leeren Bildschirm. Ein Klick darauf startet die Spracheingabe (Abbildung 11.5).

Im Anschluss daran wird der Audiostrom analysiert und in geschriebene Sprache umgeformt. Sofern auf dem Gerät Offline-Sprachpakete installiert wurden, ist hierfür keine aktive Netzwerkverbindung erforderlich. Andernfalls müssen die Daten an einen Google-Server geschickt und dort ausgewertet werden. Unabhängig davon kann dies auch zur Verbesserung der Spracherkennung erfolgen. Nach der Umwandlung zeigt die App die erkannten Wörter an (Abbildung 11.6).

Falls die benötigte Komponente nicht zur Verfügung steht, lautet die Beschriftung Spracherkennung nicht verfügbar, und die Schaltfläche kann in diesem Fall nicht angeklickt werden.

Der Aufnahmevorgang

Abbildung 11.5    Der Aufnahmevorgang

Die App zeigt den erkannten Text an.

Abbildung 11.6    Die App zeigt den erkannten Text an.

Verfügbarkeit prüfen

SpeechRecognitionDemoActivity leitet von AppCompatActivity ab und überschreibt onCreate() und onActivityResult(). Nach dem Laden und Anzeigen der Benutzeroberfläche wird mit queryIntentActivities() der Klasse PackageManager eine Liste von Activities ermittelt, die das Intent RecognizerIntent.ACTION_RECOGNIZE_SPEECH verarbeiten können. Ist diese Liste leer, steht die Spracherkennung nicht zur Verfügung. Damit diese Abfrage funktioniert, muss in der Manifestdatei die Berechtigung android.permission.QUERY_ALL_PACKAGES angefordert werden.

package com.thomaskuenneth.androidbuch.speechrecognitiondemo

import android.app.Activity
import android.content.Intent
import android.os.Bundle
import android.speech.RecognizerIntent
import androidx.appcompat.app.AppCompatActivity
import kotlinx.android.synthetic.main.activity_main.*

private const val REQUEST_VOICE_RECOGNITION = 1
class SpeechRecognitionDemoActivity : AppCompatActivity() {

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
button.setOnClickListener { startVoiceRecognitionActivity() }
// Verfügbarkeit der Spracherkennung prüfen
val activities = packageManager.queryIntentActivities(Intent(
RecognizerIntent.ACTION_RECOGNIZE_SPEECH), 0)
if (activities.size == 0) {
button.isEnabled = false
button.text = getString(R.string.not_present)
}
}

override fun onActivityResult(requestCode: Int,
resultCode: Int,
data: Intent?) {
if (requestCode == REQUEST_VOICE_RECOGNITION
&& resultCode == Activity.RESULT_OK) {
val matches =
data?.getStringArrayListExtra(RecognizerIntent.EXTRA_RESULTS)
matches?.let {
if (it.size > 0) {
textview.text = matches[0]
}
}
}
super.onActivityResult(requestCode, resultCode, data)
}

private fun startVoiceRecognitionActivity() {
val intent = Intent(
RecognizerIntent.ACTION_RECOGNIZE_SPEECH)
intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL,
RecognizerIntent.LANGUAGE_MODEL_FREE_FORM)
intent.putExtra(RecognizerIntent.EXTRA_PROMPT,
getString(R.string.prompt))
intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE, "de-DE")
intent.putExtra(RecognizerIntent.EXTRA_MAX_RESULTS, 1)
startActivityForResult(intent, REQUEST_VOICE_RECOGNITION)
}
}

Listing 11.6    Die Klasse »SpeechRecognitionDemoActivity«

Die Google-App enthält eine Activity, die auf Intents mit der Aktion RecognizerIntent.ACTION_RECOGNIZE_SPEECH reagiert. Grundsätzlich kann dies aber jedes andere Programm ebenfalls tun. Es muss nur in der Lage sein, RecognizerIntent.ACTION_RECOGNIZE_SPEECH zu verarbeiten. Die Klasse android.speech.RecognizerIntent enthält zahlreiche weitere Konstanten, auf die ich gleich noch ausführlicher eingehen werde. Die Spracherkennung wird in startVoiceRecognitionActivity() gestartet. Die Methode wird nach dem Anklicken des Buttons Spracherkennung starten aufgerufen.

Da die Activity ein Ergebnis (nämlich die hoffentlich erkannten Wörter) an Sie übermitteln muss, starten Sie sie mit startActivityForResult(). Mit putExtra() können Sie deren Funktionsweise beeinflussen. Beispielsweise legen Sie mit RecognizerIntent.EXTRA_LANGUAGE die Sprache fest, zum Beispiel de-DE oder en-US. Mit EXTRA_MAX_RESULTS steuern Sie die maximale Anzahl an Ergebnissen. Besonders wichtig ist EXTRA_LANGUAGE_MODEL, denn hiermit charakterisieren Sie die bevorstehende Eingabe. LANGUAGE_MODEL_FREE_FORM bedeutet, dass der Anwender eher ganze Sätze formulieren wird. Denken Sie an einen Texteditor, mit dem Sie E-Mails oder Kurznachrichten erfassen. LANGUAGE_MODEL_WEB_SEARCH hingegen verwenden Sie bei Suchanfragen oder grammatisch unvollständigen Verb-Substantiv-Phrasen. Mit der Konstanten EXTRA_PROMPT können Sie eine kurze Beschreibung festlegen, die während der Eingabe angezeigt wird.

Wenn die Spracherkennungs-Activity ihre Arbeit beendet hat, ruft Android die Methode onActivityResult() auf. Wie üblich müssen Sie zunächst die beiden Werte requestCode und resultCode prüfen. getStringArrayListExtra() ermittelt dann eine Liste mit Ergebnissen.

Sie haben in diesem Kapitel zahlreiche Facetten der Audioverarbeitung unter Android kennengelernt. In den folgenden Abschnitten sehen wir uns an, wie Sie Fotos aufnehmen und Videos drehen. Die Zeiten, in denen die Kameras in Mobiltelefonen gerade einmal zu Spaßfotos taugten, sind glücklicherweise längst vorbei. Aktuelle Android-Geräte liefern durchweg gute Ergebnisse. Dabei sind die Möglichkeiten, die sich aus dem Einsatz der Kamerahardware ergeben, praktisch grenzenlos. Denken Sie an die Überlagerung von Live-Daten mit computergenerierten Grafiken oder mit Informationen aus dem Netz (Augmented Reality) oder an die Erkennung von Sehenswürdigkeiten, Texten, Bildern sowie allerlei anderer Informationen.

 


Ihre Meinung?

Wie hat Ihnen das Openbook gefallen? Wir freuen uns immer über Ihre Rückmeldung. Schreiben Sie uns gerne Ihr Feedback als E-Mail an kommunikation@rheinwerk-verlag.de

<< zurück
Zur Rheinwerk-Konferenz für Kotlin
 Buchempfehlungen
Zum Rheinwerk-Shop: Kotlin

Kotlin


Zum Rheinwerk-Shop: Praxisbuch Usability und UX

Praxisbuch Usability und UX


Zum Rheinwerk-Shop: Flutter und Dart

Flutter und Dart


Zum Rheinwerk-Shop: App-Design

App-Design


 Lieferung
Versandkostenfrei bestellen in Deutschland, Österreich und in die Schweiz
InfoInfo

 
 


Copyright © Rheinwerk Verlag GmbH 2023
Für Ihren privaten Gebrauch dürfen Sie die Online-Version natürlich ausdrucken. Ansonsten unterliegt das Openbook denselben Bestimmungen, wie die gebundene Ausgabe: Das Werk einschließlich aller seiner Teile ist urheberrechtlich geschützt.
Alle Rechte vorbehalten einschließlich der Vervielfältigung, Übersetzung, Mikroverfilmung sowie Einspeicherung und Verarbeitung in elektronischen Systemen.

 
[Rheinwerk Computing]

Rheinwerk Verlag GmbH, Rheinwerkallee 4, 53227 Bonn, Tel.: 0228.42150.0, Fax 0228.42150.77, service@rheinwerk-verlag.de

Cookie-Einstellungen ändern