Sensoren und Spracheingabe

Android Wear: Auf Tuchfühlung mit dem Anwender

Peter Friese

©Shutterstock/Estherpoon

Gyroskop, GPS, Schrittzähler, Herzfrequenzmesser, Mikrophon, Magnetometer – was sich wie die Spezifikation für das nächste James-Bond-Gadget anhört, ist nichts anderes als die mittlerweile ganz normale Grundausstattung von Smartwatches.

Der wohl größte Unterschied zwischen Smartwatches und normalen Uhren sind die in Smartwatches verbauten Sensoren, die Smartwatches zu idealen Begleitern der Generation der Self Quantification machen: Wie viele Schritte bin ich heute gegangen, wie viele Kalorien habe ich dabei verbraucht, und wie sieht der heutige Tag im Vergleich zu gestern aus? Diese und andere Fragen lassen sich aufgrund der mittels einer Smartwatch ermittelten Daten leicht beantworten.

Nachdem wir uns in den beiden vorigen Artikeln mit Watchfaces sowie der Entwicklung von Micro-Apps beschäftigt haben, soll es in diesem Artikel um die Auswertung der unter Android Wear verfügbaren Sensordaten gehen. Mithilfe der so gesammelten Daten lassen sich interessante Use Cases implementieren – die einzige Grenze ist die eigene Vorstellungskraft.

Bedingt durch die vergleichsweise geringen Displayabmessungen sind die manuellen Eingabemöglichkeiten auf Smartwatches ziemlich begrenzt, weswegen menschliche Sprache ein wichtiges Eingabemedium darstellt. Doch das in Android Wearables eingebaute Mikrofon kann nicht nur für die Erkennung von Sprache verwendet werden, sondern als generischer Akustiksensor. Grund genug, sich im vorliegenden Artikel auch mit diesem Sensor zu beschäftigen.

Sensoren

Es gibt eine Vielzahl unterschiedlicher Sensoren, die allgemein betrachtet wie folgt kategorisiert werden können: Bewegungssensoren messen Beschleunigungskräfte und Drehbewegungen, Umgebungssensoren ermitteln Daten wie z. B. die Helligkeit und Lagesensoren schließlich geben Auskunft über die physikalische Lage des Geräts. Man unterscheidet dabei zwischen Basissensoren und Verbundsensoren (Base Sensor vs. Composite Sensor). Während die meisten Basissensoren physikalische Sensoren sind, gewinnen Verbundsensoren ihre Daten aus der Aufbereitung von Daten eines oder mehrerer Basissensoren. Beispiele für Basissensoren sind Accelerometer, Magnetfeldsensoren, Gyroscope oder Herzfrequenzsensoren. Beispiele für Verbundsensoren sind Schrittzähler, die ihre Daten aus dem Accelerometer beziehen und Schwerkraftsensoren, die ihre Daten aus Accelerometer und dem Gyroscope gewinnen.

Nicht jedes Android-Gerät verfügt über alle hier aufgelisteten Sensoren, daher muss entsprechend defensiv programmiert und vor der Verwendung eines Sensors überprüft werden, ob er überhaupt auf dem aktuellen Device zur Verfügung steht.

Android abstrahiert den Zugriff auf die Sensoren mittels des Sensor-Frameworks, das die Klassen SensorManager, Sensor, SensorEvent und SensorEventListener umfasst und auch auf der Android-Wear-Plattform zur Verfügung steht. Die zentrale Klasse des Sensor-Frameworks ist der SensorManager, der über die Methode getDefaultSensor() den Zugriff auf die einzelnen Sensoren erlaubt und die Registrierung und Deregistrierung von SensorEventHandlern ermöglicht. Der Zugriff auf Sensordaten erfolgt dabei nach folgendem Schema:

  1. SensorManager holen
  2. Gewünschte Sensoren holen
  3. Prüfen, ob es den gewünschten Sensor gibt
  4. Gegebenenfalls einen EventListener registrieren
  5. Wurden die benötigen Daten gelesen, darf nicht vergessen werden, den EventListener zu deregistrieren, um den Batterieverbrauch zu minimieren

Um sicherzustellen, dass eine App auf einen nicht vorhandenen Sensor zuzugreifen versucht, kann man folgende Strategien anwenden:

  1. Auflistung der erforderlichen Sensoren im Android-Manifest mittels <uses-feature> (Listing 1). Wird die App über Google Play verteilt, sorgt dieses Attribut dafür, dass die App nur für Geräte mit dem entsprechenden Feature zum Download angeboten wird.
  2. Um wirklich sicherzugehen, dass sich eine App auch dann korrekt verhält, wenn ein benötigter Sensor nicht zur Verfügung steht, sollte man zur Laufzeit überprüfen, ob die gewünschten Sensoren zur Verfügung stehen. Steht ein angeklagter Sensor nicht zur Verfügung, gibt die Methode getSensor() den Wert null zurück.
<uses-feature
  android:name= "android.hardware.sensor.accelerometer"
  android:required="true" />

Schauen wir uns den gesamten Ablauf am Beispiel des Zugriffs auf den Schrittsensor an. In onCreate() holen wir zunächst eine Referenz auf den SensorManager, um direkt anschließend mittels getDefaultSensor(Sensor.TYPE_STEP_COUNTER) eine Referenz auf den Schrittsensor anzufordern. Im nächsten Schritt registrieren wir die aktuelle Activity als SensorEventListener, um über Sensorereignisse (in unserem Fall neue Schritte) informiert zu werden. Alle derzeit am Markt befindlichen Android-Wear-Geräte verfügen über einen Schrittsensor, allerdings ist durchaus denkbar, dass zukünftige Devices nicht über einen Schrittsensor verfügen. Aus diesem Grund überprüfen wir die Referenz auf den Sensor auf null, bevor wir den EventListener registrieren. Der gesamte Ablauf ist in Listing 2 zu sehen.

@Override
protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);

  // . . .

  mSensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
  stepCounterSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_STEP_COUNTER);

  if (stepCounterSensor != null) {
    mSensorManager.registerListener(
      this, 
      stepCounterSensor, 
      SensorManager.SENSOR_DELAY_NORMAL);
  }
  else {
    Log.d(TAG, "No Step Counter Sensor found");
  }
}

Für den Empfang von Sensorereignissen müssen wir die beiden Methoden onAccuracyChanged und onSensorChanged implementieren. onSensorChanged wird jedes Mal aufgerufen, wenn einer der registrierten Sensoren ein Ereignis sendet. Da wir potenziell auf Ereignisse von mehreren Sensoren lauschen, sollten wir zunächst überprüfen, von welchem Sensortyp das Ereignis gesendet wurde, um anschließend die Sensordaten entsprechend auslesen zu können. Die Anzahl der gezählten Schritte des Schrittsensors wird im ersten Feld des Arrays event.values gesendet (Listing 3).

public void onSensorChanged(SensorEvent event) {
  Log.d(TAG, "Received sensor data for sensor " + event.sensor.getName());
  if (event.sensor.getType() == Sensor.TYPE_STEP_COUNTER) {
    if (event.values.length > 0) {
      float steps = event.values[0];
      mTextView.setText(steps + " steps");
    }
  }
}

Das Auslesen von Sensordaten ist mithilfe des Sensorframeworks recht einfach, für weitere Informationen zu den einzelnen Sensoren sei auf das Sensors Overview und die Sensor Types verwiesen.

Spracheingabe

Seit Erfindung des Computers haben wir verschiedene Arten der Mensch-Maschine-Kommunikation durchlebt. Von einfachen Schaltern und Hebeln über Tastaturen, Stifte, Zeichentablets, Mäuse und Trackballs bis hin zu berührungsempfindlichen Displays wurden die unterschiedlichsten Technologien mit mehr oder weniger Erfolg eingesetzt, doch keine hat die Menschen so fasziniert wie die Kommunikation über das gesprochene Wort: Sprachein- und ausgabe ist seit Langem ein wichtiges Forschungsgebiet der Informatik, und die Qualität der für den Massenmarkt verfügbaren Implementierungen hat sich seit dem Aufkommen der ersten kommerziellen Softwarepakete für computerbasierte Diktate erheblich verbessert.

Bedingt durch das kleine Display ist die Eingabe von Daten über eine Bildschirmtastatur auf Android Wear indiskutabel (es gibt zwar einige Taschenrechner für Android Wear, doch selbst die wenigen für einen Taschenrechner benötigten Tasten lassen sich kaum auf dem kleinen Display unterbringen und sind viel zu winzig, um vernünftig bedient werden zu können). Um dennoch eingabeorientierte Use Cases zu ermöglichen, unterstützt Android Wear mehrere Formen der Spracheingabe.

Grob gesagt lässt sich zwischen Voice Actions und Freiformspracheingabe unterscheiden. Voice Actions werden über das Hotword „OK, Google“ eingeleitet und sowohl vom System selbst als auch von den einzelnen Android-Wear-Apps bereitgestellt.

Voice Actions

Die Android-Wear-Plattform stellt eine Reihe von Voice Intents zur Verfügung, die für oft wiederkehrende Aktionen des Benutzers gedacht sind, wie z. B. um eine Notiz anzulegen, ein Taxi zu rufen, die Herzfrequenz anzuzeigen, oder einen Alarm zu setzen. Android-Wear-Apps können Intent-Filter einsetzen, um auf diese Intents zu reagieren. Wenn mehrere Apps für den gleichen Intent registriert sind, fragt Android Wear den Benutzer, welche dieser Apps er zur Ausführung seines Sprachkommandos verwenden möchte. Listing 4 zeigt eine Beispiel-Activity, die sich für die Action _Note to self_ registriert. Sobald der Benutzer „OK, Google. Take a note.“ sagt, stellt Android Wear den Voice Input Prompt dar und wartet darauf, dass der Benutzer spricht. Die vom System erkannte Äußerung (engl. Utterance) des Benutzers wird mittels des Extra Intent.EXTRA_TEXT an die Activity gesendet, wo sie dann ausgelesen und verarbeitet werden kann.

<activity android:name=".TakeNoteActivity">
<intent-filter>
<action android:name="android.intent.action.SEND" />
<data android:mimeType="text/plain"/>
<category android:name="com.google.android.voicesearch.SELF_NOTE" />
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</activity>
public class TakeNoteActivity extends Activity {

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    if (intent.getAction().compareTo(android.intent.action.SEND) == 0) {
      String voiceNote =
        getIntent().getStringExtra(Intent.EXTRA_TEXT);
    }
  }
}

Neben den vom System zur Verfügung gestellten Voice Actions können Android-Wear-Apps eigene Voice Actions implementieren. Derzeit unterstützt Android Wear die Implementierung von Voice Actions zum Starten von Activities. Zu diesem Zweck muss die gewünschte Activity per Intent-Filter als Launch-Activity markiert und das Attribut label gesetzt werden. Der Text für das Label kann dann verwendet werden, um die App mittels „OK, Google. Start (Label)“ zu starten. Listing 6 zeigt, wie eine Activity mittels „OK, Google. Start Flashcards.“ gestartet werden kann.

<application>
  <activity 
    android:name="FlashCardActivity" 
    android:label="Flashcards"<
    <intent-filter>
      <action android:name="android.intent.action.MAIN" />
      <category android:name="android.intent.category.LAUNCHER" />
    </intent-filter>
  </activity>
</application>

Freie Spracheingabe

Möchte man innerhalb einer Android-Wear-App auf die Spracherkennung zurückgreifen (z. B. um in einer Fitness-App eine Notiz zu einem gerade durchgeführten Training zu erfassen), so kann man die Spracherkennung direkt aus einer eigenen Activity aufrufen. Mittels der Action RecognizerIntent.ACTION_RECOGNIZE_SPEECH kann der entsprechende Intent gestartet werden, wobei im Extra RecognizerIntent.EXTRA_LANGUAGE_MODEL festgelegt werden kann, ob die vom Benutzer erwartete Äußerung ein Freitext oder eine Suchanfrage ist. Android Wear zeigt dann den Spracheingabe-Prompt an und wartet darauf, dass der Benutzer spricht. Nach erfolgreicher Spracherkennung ruft Android Wear onActivityResult auf und übergibt den erkannten Text im Extra RecognizerIntent.EXTRA_RESULTS des Intent-Parameters. Es handelt sich um eine Liste von Strings, die absteigend nach Erkennungszuverlässigkeit sortiert ist. An Position 0 befindet sich also der Text, den der Benutzer mit höchster Wahrscheinlichkeit gesagt hat.

Die Spracherkennung selbst kann über weitere Intent-Extras konfiguriert werden: Neben dem erforderlichen Parameter EXTRA_LANGUAGE_MODEL (mit dem wie oben erwähnt das Sprachmodell gewählt werden kann), kann mittels EXTRA_PROMPT der UI-Text festgelegt werden, mittels EXTRA_LANGUAGE die zu erkennende Sprache und mittels EXTRA_MAX_RESULTS die maximale Anzahl von Ergebnissen.

private void displaySpeechRecogniser() {
  Intent intent = new
    Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH);
  intent.putExtra(
    RecognizerIntent.EXTRA_LANGUAGE_MODEL,
    RecognizerIntent.LANGUAGE_MODEL_FREE_FORM);
  startActivityForResult(intent, SPEECH_REQUEST_CODE);
}

@Override
protected void onActivityResult(
  int requestCode, int resultCode, Intent data) {
  if (requestCode == SPEECH_REQUEST_CODE 
      && resultCode == RESULT_OK) {
    List results = 
      data.getStringArrayListExtra(
        RecognizerIntent.EXTRA_RESULTS);
    String utterance = results.get(0);
    String text = String.format("You said %s", utterance);
    Toast.makeText(this, text, Toast.LENGTH_LONG).show();
  }
  super.onActivityResult(requestCode, resultCode, data);
}

Fazit

Android-Wear-Geräte enthalten eine erstaunliche Anzahl von Sensoren auf kleinem Raum. Mithilfe des Android-Sensor-Frameworks ist es ein Leichtes, sich die zur Verfügung stehenden Sensoren zu Nutze zu machen. Mit den in den aktuellen Wearables enthaltenen Sensoren lassen sich eine Vielzahl spannender Use Cases umsetzen – fehlt nur noch der integrierte Seilzug aus „Die Welt ist nicht genug“.

Aufmacherbild: Smart watch set von Shutterstock / Urheberrecht: Estherpoon

Verwandte Themen:

Geschrieben von
Peter Friese
Peter Friese
Peter Friese arbeitet als Developer Advocate bei Google im Developer Relations Team in London. Er trägt regelmäßig zu Open-Source-Projekten bei, spricht auf Konferenzen und bloggt unter http://www.peterfriese.de. Auf Twitter findet man ihn unter @peterfriese und auf Google+ unter +PeterFriese.
Kommentare

Hinterlasse einen Kommentar

Hinterlasse den ersten Kommentar!

avatar
4000
  Subscribe  
Benachrichtige mich zu: