Eingänge und Sensoren

Über das Android SDK haben Sie Zugriff auf die verschiedenen Eingänge und Sensoren, die in Glass EE2 verfügbar sind. Auf dieser Seite erhältst du einen Überblick über die verfügbaren Funktionen, Details zur Implementierung und nützliche Tipps.

Einfaches Tippen

Sie können das Android SDK verwenden, um den Zugriff auf Rohdaten über das Glass-Touchpad zu ermöglichen. Dazu wird ein Gestenerkennung eingesetzt, mit der gängige Gesten in Glass wie Tippen, Wischen und Scrollen automatisch erkannt werden.

Du kannst diesen Gesten-Detektor auch in deinen Apps verwenden, um das Tippen zu erfassen, vorwärts zu wischen, zurückzugehen und nach unten zu wischen. Dies ist mit früheren Glass-Geräten vergleichbar.

Diese Touch-Gesten sollten am besten auf folgende Weise verwendet werden:

  • Tippen: Bestätigen oder eingeben.
  • Nach vorn wischen, nach hinten wischen: Hiermit können Sie durch die Karten und Bildschirme blättern.
  • Nach unten wischen: Zurück oder schließen

Ausführliche Informationen zur Implementierung finden Sie im Beispiel für einen Gesten-Detektor.

Bewegungen mit dem Android-Gestenerkennung erkennen

Mit Android GestureDetector kannst du einfache und komplexe Gesten erkennen, z. B. Bewegungen mit mehreren Fingern oder Scrollen.

Bewegungen auf Aktivitätsebene erkennen

Erkennt Gesten auf Aktivitätsebene nur, wenn es auf einem bestimmten Bereich der Benutzeroberfläche fokussiert ist. Möchtest du beispielsweise ein Menü aufrufen, wenn ein Nutzer auf das Touchpad tippt, unabhängig davon, welche Ansicht fokussiert ist, kannst du das MotionEvent innerhalb der Aktivität verwenden.

Das folgende Beispiel zeigt die Erkennung von Gesten auf Aktivitätsebene. Dabei wird GestureDetector verwendet und GestureDetector.OnGestureListener zur Verarbeitung erkannter Gesten implementiert, die dann verarbeitet und in folgende Sprachen übersetzt werden:

  • TAP
  • SWIPE_FORWARD
  • SWIPE_BACKWARD
  • SWIPE_UP
  • SWIPE_DOWN

Kotlin

class GlassGestureDetector(context: Context, private val onGestureListener: OnGestureListener) :
    GestureDetector.OnGestureListener {

    private val gestureDetector = GestureDetector(context, this)

    enum class Gesture {
        TAP,
        SWIPE_FORWARD,
        SWIPE_BACKWARD,
        SWIPE_UP,
        SWIPE_DOWN
    }

    interface OnGestureListener {
        fun onGesture(gesture: Gesture): Boolean
    }

    fun onTouchEvent(motionEvent: MotionEvent): Boolean {
        return gestureDetector.onTouchEvent(motionEvent)
    }

    override fun onDown(e: MotionEvent): Boolean {
        return false
    }

    override fun onShowPress(e: MotionEvent) {}

    override fun onSingleTapUp(e: MotionEvent): Boolean {
        return onGestureListener.onGesture(Gesture.TAP)
    }

    override fun onScroll(
        e1: MotionEvent,
        e2: MotionEvent,
        distanceX: Float,
        distanceY: Float
    ): Boolean {
        return false
    }

    override fun onLongPress(e: MotionEvent) {}

    /**
     * Swipe detection depends on the:
     * - movement tan value,
     * - movement distance,
     * - movement velocity.
     *
     * To prevent unintentional SWIPE_DOWN and SWIPE_UP gestures, they are detected if movement
     * angle is only between 60 and 120 degrees.
     * Any other detected swipes, will be considered as SWIPE_FORWARD and SWIPE_BACKWARD, depends
     * on deltaX value sign.
     *
     * ______________________________________________________________
     * |                     \        UP         /                    |
     * |                       \               /                      |
     * |                         60         120                       |
     * |                           \       /                          |
     * |                             \   /                            |
     * |  BACKWARD  <-------  0  ------------  180  ------>  FORWARD  |
     * |                             /   \                            |
     * |                           /       \                          |
     * |                         60         120                       |
     * |                       /               \                      |
     * |                     /       DOWN        \                    |
     * --------------------------------------------------------------
     */
    override fun onFling(
        e1: MotionEvent,
        e2: MotionEvent,
        velocityX: Float,
        velocityY: Float
    ): Boolean {
        val deltaX = e2.x - e1.x
        val deltaY = e2.y - e1.y
        val tan =
            if (deltaX != 0f) abs(deltaY / deltaX).toDouble() else java.lang.Double.MAX_VALUE

        return if (tan > TAN_60_DEGREES) {
            if (abs(deltaY) < SWIPE_DISTANCE_THRESHOLD_PX || Math.abs(velocityY) < SWIPE_VELOCITY_THRESHOLD_PX) {
                false
            } else if (deltaY < 0) {
                onGestureListener.onGesture(Gesture.SWIPE_UP)
            } else {
                onGestureListener.onGesture(Gesture.SWIPE_DOWN)
            }
        } else {
            if (Math.abs(deltaX) < SWIPE_DISTANCE_THRESHOLD_PX || Math.abs(velocityX) < SWIPE_VELOCITY_THRESHOLD_PX) {
                false
            } else if (deltaX < 0) {
                onGestureListener.onGesture(Gesture.SWIPE_FORWARD)
            } else {
                onGestureListener.onGesture(Gesture.SWIPE_BACKWARD)
            }
        }
    }

    companion object {

        private const val SWIPE_DISTANCE_THRESHOLD_PX = 100
        private const val SWIPE_VELOCITY_THRESHOLD_PX = 100
        private val TAN_60_DEGREES = tan(Math.toRadians(60.0))
    }
}

Java

  public class GlassGestureDetector implements GestureDetector.OnGestureListener {

   enum Gesture {
     TAP,
     SWIPE_FORWARD,
     SWIPE_BACKWARD,
     SWIPE_UP,
     SWIPE_DOWN,
   }

   interface OnGestureListener {
     boolean onGesture(Gesture gesture);
   }

   private static final int SWIPE_DISTANCE_THRESHOLD_PX = 100;
   private static final int SWIPE_VELOCITY_THRESHOLD_PX = 100;
   private static final double TAN_60_DEGREES = Math.tan(Math.toRadians(60));

   private GestureDetector gestureDetector;
   private OnGestureListener onGestureListener;

   public GlassGestureDetector(Context context, OnGestureListener onGestureListener) {
     gestureDetector = new GestureDetector(context, this);
     this.onGestureListener = onGestureListener;
   }

   public boolean onTouchEvent(MotionEvent motionEvent) {
     return gestureDetector.onTouchEvent(motionEvent);
   }

   @Override
   public boolean onDown(MotionEvent e) {
     return false;
   }

   @Override
   public void onShowPress(MotionEvent e) {
   }

   @Override
   public boolean onSingleTapUp(MotionEvent e) {
     return onGestureListener.onGesture(Gesture.TAP);
   }

   @Override
   public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
     return false;
   }

   @Override
   public void onLongPress(MotionEvent e) {
   }

   /**
    * Swipe detection depends on the:
    * - movement tan value,
    * - movement distance,
    * - movement velocity.
    *
    * To prevent unintentional SWIPE_DOWN and SWIPE_UP gestures, they are detected if movement
    * angle is only between 60 and 120 degrees.
    * Any other detected swipes, will be considered as SWIPE_FORWARD and SWIPE_BACKWARD, depends
    * on deltaX value sign.
    *
    *           ______________________________________________________________
    *          |                     \        UP         /                    |
    *          |                       \               /                      |
    *          |                         60         120                       |
    *          |                           \       /                          |
    *          |                             \   /                            |
    *          |  BACKWARD  <-------  0  ------------  180  ------>  FORWARD  |
    *          |                             /   \                            |
    *          |                           /       \                          |
    *          |                         60         120                       |
    *          |                       /               \                      |
    *          |                     /       DOWN        \                    |
    *           --------------------------------------------------------------
    */
   @Override
   public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
     final float deltaX = e2.getX() - e1.getX();
     final float deltaY = e2.getY() - e1.getY();
     final double tan = deltaX != 0 ? Math.abs(deltaY/deltaX) : Double.MAX_VALUE;

     if (tan > TAN_60_DEGREES) {
       if (Math.abs(deltaY) < SWIPE_DISTANCE_THRESHOLD_PX || Math.abs(velocityY) < SWIPE_VELOCITY_THRESHOLD_PX) {
         return false;
       } else if (deltaY < 0) {
         return onGestureListener.onGesture(Gesture.SWIPE_UP);
       } else {
         return onGestureListener.onGesture(Gesture.SWIPE_DOWN);
       }
     } else {
       if (Math.abs(deltaX) < SWIPE_DISTANCE_THRESHOLD_PX || Math.abs(velocityX) < SWIPE_VELOCITY_THRESHOLD_PX) {
         return false;
       } else if (deltaX < 0) {
         return onGestureListener.onGesture(Gesture.SWIPE_FORWARD);
       } else {
         return onGestureListener.onGesture(Gesture.SWIPE_BACKWARD);
       }
     }
   }
  }

Verwendungsbeispiel

Damit Sie die Gestenerkennung auf Aktivitätsebene nutzen können, müssen Sie die folgenden Aufgaben ausführen:

  1. Fügen Sie der Manifestdatei in der Anwendungsdeklaration die folgende Deklaration hinzu. Dadurch kann deine App die MotionEvent in der Aktivität empfangen:
    <application>
    <!-- Copy below declaration into your manifest file -->
    <meta-data
      android:name="com.google.android.glass.TouchEnabledApplication"
      android:value="true" />
    </application>
    
  2. Überschreiben Sie die Methode dispatchTouchEvent(motionEvent) der Aktivität, um die Bewegungsereignisse an die Methode onTouchEvent(motionEvent) der Bewegungserkennung zu übergeben.
  3. Implementiere GlassGestureDetector.OnGestureListener in deiner Aktivität.

Hier ist ein Beispiel für einen Bewegungsmelder auf Aktivitätsebene:

Kotlin

class MainAcvitiy : AppCompatActivity(), GlassGestureDetector.OnGestureListener {

    private lateinit var glassGestureDetector: GlassGestureDetector

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        glassGestureDetector = GlassGestureDetector(this, this)
    }

    override fun onGesture(gesture: GlassGestureDetector.Gesture): Boolean {
        when (gesture) {
            TAP ->
                // Response for TAP gesture
                return true
            SWIPE_FORWARD ->
                // Response for SWIPE_FORWARD gesture
                return true
            SWIPE_BACKWARD ->
                // Response for SWIPE_BACKWARD gesture
                return true
            else -> return false
        }
    }

    override fun dispatchTouchEvent(ev: MotionEvent): Boolean {
        return if (glassGestureDetector.onTouchEvent(ev)) {
            true
        } else super.dispatchTouchEvent(ev)
    }
}

Java

  public class MainActivity extends AppCompatActivity implements OnGestureListener {

   private GlassGestureDetector glassGestureDetector;

   @Override
   protected void onCreate(Bundle savedInstanceState) {
     super.onCreate(savedInstanceState);
     setContentView(R.layout.activity_main);

     glassGestureDetector = new GlassGestureDetector(this, this);
   }

   @Override
   public boolean onGesture(Gesture gesture) {
     switch (gesture) {
       case TAP:
         // Response for TAP gesture
         return true;
       case SWIPE_FORWARD:
         // Response for SWIPE_FORWARD gesture
         return true;
       case SWIPE_BACKWARD:
         // Response for SWIPE_BACKWARD gesture
         return true;
       default:
         return false;
     }
   }

   @Override
   public boolean dispatchTouchEvent(MotionEvent ev) {
     if (glassGestureDetector.onTouchEvent(ev)) {
       return true;
     }
     return super.dispatchTouchEvent(ev);
   }
  }

Audioeingabe

Glass Enterprise Edition 2 ist ein standardmäßiges AOSP-basiertes Gerät, das grundlegende Audioquellen unterstützt.

Bei den folgenden Audioquellen ist die erweiterte Signalverarbeitung implementiert:

Spracherkennung

Glass Enterprise Edition 2 unterstützt eine native Implementierung für die Spracherkennung. Diese Option wird nur für Englisch unterstützt.

Bild mit Spracherkennung in Glass.

Die Spracherkennungs-UI wartet auf das Sprechen eines Nutzers und gibt den transkribierten Text zurück. So starten Sie die Aktivität:

  1. Rufen Sie startActivityForResult() mit dem Intent ACTION_RECOGNIZE_SPEECH auf. Wenn Sie die Aktivität starten, werden die folgenden Intent-Extras unterstützt:
  2. Überschreiben Sie den onActivityResult()-Callback, um den transkribierten Text aus dem EXTRA_RESULTS-Intent-Extra zu empfangen, wie im folgenden Codebeispiel gezeigt. Dieser Callback wird aufgerufen, wenn der Nutzer zu sprechen beginnt.

Kotlin

private const val SPEECH_REQUEST = 109

private fun displaySpeechRecognizer() {
    val intent = Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH)
    startActivityForResult(intent, SPEECH_REQUEST)
}

override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent) {
    if (requestCode == SPEECH_REQUEST && resultCode == RESULT_OK) {
        val results: List<String>? =
            data.getStringArrayListExtra(RecognizerIntent.EXTRA_RESULTS)
        val spokenText = results?.get(0)
        // Do something with spokenText.
    }
    super.onActivityResult(requestCode, resultCode, data)
}

Java

private static final int SPEECH_REQUEST = 109;

private void displaySpeechRecognizer() {
    Intent intent = new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH);
    startActivityForResult(intent, SPEECH_REQUEST);
}

@Override
protected void onActivityResult(int requestCode, int resultCode,
        Intent data) {
    if (requestCode == SPEECH_REQUEST && resultCode == RESULT_OK) {
        List<String> results = data.getStringArrayListExtra(
                RecognizerIntent.EXTRA_RESULTS);
        String spokenText = results.get(0);
        // Do something with spokenText.
    }
    super.onActivityResult(requestCode, resultCode, data);
}

Ausführliche Informationen zur Implementierung findest du in der Beispiel-Spracherkennungs-App.

Gewichtung nach Keywords

Die Spracherkennung in Glass kann für eine Liste von Keywords verzerrt sein. Die Gewichtung erhöht die Genauigkeit der Keyword-Erkennung. Verwenden Sie folgenden Code, um die Gewichtung für Keywords zu aktivieren:

Kotlin

val keywords = arrayOf("Example", "Biasing", "Keywords")

val intent = Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH)
intent.putExtra("recognition-phrases", keywords)

startActivityForResult(intent, SPEECH_REQUEST)

Java

final String[] keywords = {"Example", "Biasing", "Keywords"};

Intent intent = new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH);
intent.putExtra("recognition-phrases", keywords);

startActivityForResult(intent, SPEECH_REQUEST);

Sprachbefehle

Mit Sprachbefehlen können Nutzer Aktionen aus Aktivitäten ausführen. Sie erstellen Sprachbefehle mit den standardmäßigen Android-Menü-APIs. Nutzer können die Menüoptionen jedoch per Sprachbefehl statt per Berührung aufrufen.

So aktivieren Sie Sprachbefehle für eine bestimmte Aktivität:

  1. Rufe getWindow().requestFeature(FEATURE_VOICE_COMMANDS) in der gewünschten Aktivität auf, um Sprachbefehle zu aktivieren. Wenn diese Funktion aktiviert ist, wird das Mikrofonsymbol unten links auf dem Bildschirm angezeigt, sobald diese Aktivität erkannt wird.
  2. Fordern Sie in Ihrer Anwendung die Berechtigung RECORD_AUDIO an.
  3. Überschreiben Sie onCreatePanelMenu() und erhöhen Sie eine Speisekarte.
  4. Überschreiben Sie onContextItemSelected(), um die erkannten Sprachbefehle zu verarbeiten.

Kotlin

class VoiceCommandsActivity : AppCompatActivity() {

    companion object {
        const val FEATURE_VOICE_COMMANDS = 14
        const val REQUEST_PERMISSION_CODE = 200
        val PERMISSIONS = arrayOf(Manifest.permission.RECORD_AUDIO)
        val TAG = VoiceCommandsActivity::class.java.simpleName
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        window.requestFeature(FEATURE_VOICE_COMMANDS)
        setContentView(R.layout.activity_voice_commands)

        // Requesting permissions to enable voice commands menu
        ActivityCompat.requestPermissions(
            this,
            PERMISSIONS,
            REQUEST_PERMISSION_CODE
        )
    }

    override fun onRequestPermissionsResult(
        requestCode: Int,
        permissions: Array<out String>,
        grantResults: IntArray
    ) {
        if (requestCode == REQUEST_PERMISSION_CODE) {
            for (result in grantResults) {
                if (result != PackageManager.PERMISSION_GRANTED) {
                    Log.d(TAG, "Permission denied. Voice commands menu is disabled.")
                }
            }
        } else {
            super.onRequestPermissionsResult(requestCode, permissions, grantResults)
        }
    }

    override fun onCreatePanelMenu(featureId: Int, menu: Menu): Boolean {
        menuInflater.inflate(R.menu.voice_commands_menu, menu)
        return true
    }

    override fun onContextItemSelected(item: MenuItem): Boolean {
        return when (item.itemId) {
            // Handle selected menu item
            R.id.edit -> {
                // Handle edit action
                true
            }
            else -> super.onContextItemSelected(item)
        }
    }
}

Java

public class VoiceCommandsActivity extends AppCompatActivity {

  private static final String TAG = VoiceCommandsActivity.class.getSimpleName();
  private static final int FEATURE_VOICE_COMMANDS = 14;
  private static final int REQUEST_PERMISSION_CODE = 200;
  private static final String[] PERMISSIONS = new String[]{Manifest.permission.RECORD_AUDIO};

  @Override
  protected void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    getWindow().requestFeature(FEATURE_VOICE_COMMANDS);
    setContentView(R.layout.activity_voice_commands);

    // Requesting permissions to enable voice commands menu
    ActivityCompat.requestPermissions(this, PERMISSIONS, REQUEST_PERMISSION_CODE);
  }

  @Override
  public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
    if (requestCode == REQUEST_PERMISSION_CODE) {
      for (int result : grantResults) {
        if (result != PackageManager.PERMISSION_GRANTED) {
          Log.d(TAG, "Permission denied. Voice commands menu is disabled.");
        }
      }
    } else {
      super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    }
  }

  @Override
  public boolean onCreatePanelMenu(int featureId, @NonNull Menu menu) {
    getMenuInflater().inflate(R.menu.voice_commands_menu, menu);
    return true;
  }

  @Override
  public boolean onContextItemSelected(@NonNull MenuItem item) {
    switch (item.getItemId()) {
      // Handle selected menu item
      case R.id.edit:
        // Handle edit action
        return true;
      default:
        return super.onContextItemSelected(item);
    }
  }
}

Hier ein Beispiel für die Menüressource, die von der vorherigen Aktivität verwendet wurde:

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
    <item
        android:id="@+id/delete"
        android:icon="@drawable/ic_delete"
        android:title="@string/delete"/>
    <item
        android:id="@+id/edit"
        android:icon="@drawable/ic_edit"
        android:title="@string/edit"/>
    <item
        android:id="@+id/find"
        android:icon="@drawable/ic_search"
        android:title="@string/find"/>
</menu>

Ein vollständiges Beispiel findest du in der Beispiel-App für Notizen.

Liste der Sprachbefehle wird aktualisiert

Sie können die Liste der Sprachbefehle dynamisch aktualisieren. Ersetzen Sie dazu die Ressource menu in der Methode onCreatePanelMenu() oder ändern Sie das Menüobjekt in der Methode onPreparePanel(). Rufen Sie die Methode invalidateOptionsMenu() auf, um Änderungen anzuwenden.

Kotlin

private val options = mutableListOf<String>()

fun onPreparePanel(featureId: Int, view: View?, menu: Menu): Boolean {
  if (featureId != FEATURE_VOICE_COMMANDS) {
    return super.onCreatePanelMenu(featureId, menu)
  }
  for (optionTitle in options) {
    menu.add(optionTitle)
  }
  return true
}

/**
 * Method showing example implementation of voice command list modification
 *
 * If you call [Activity.invalidateOptionsMenu] method, voice command  list will be
 * reloaded (onCreatePanelMenu and onPreparePanel methods will be called).
 */
private fun modifyVoiceCommandList() {
  options.add("Delete")
  options.add("Play")
  options.add("Pause")
  invalidateOptionsMenu()
}

Java

private final List<String> options = new ArrayList<>();

@Override
public boolean onPreparePanel(int featureId, View view, Menu menu) {
  if (featureId != FEATURE_VOICE_COMMANDS) {
    return super.onCreatePanelMenu(featureId, menu);
  }
  for (String optionTitle : options) {
    menu.add(optionTitle);
  }
  return true;
}

/**
 * Method showing example implementation of voice command list modification
 *
 * If you call {@link Activity#invalidateOptionsMenu()} method, voice command  list will be
 * reloaded (onCreatePanelMenu and onPreparePanel methods will be called).
 */
private void modifyVoiceCommandList() {
  options.add("Delete");
  options.add("Play");
  options.add("Pause");
  invalidateOptionsMenu();
}

AppCompatActivity-Lösung

Verwenden Sie die Methode sendBroadcast() mit der Intent-Aktion reload-voice-commands, um eine Sprachbefehlliste in einer Aktivität zu aktualisieren, die AppCompatActivity erweitert:

Kotlin

sendBroadcast(Intent("reload-voice-commands"))

Java

sendBroadcast(new Intent("reload-voice-commands"));

Sprachbefehle zur Laufzeit aktivieren und deaktivieren

Sie können Sprachbefehle zur Laufzeit aktivieren und deaktivieren. Geben Sie dazu einen entsprechenden Wert aus der Methode onCreatePanelMenu() so zurück:

  • Setzen Sie den Wert zum Aktivieren auf true.
  • Setzen Sie den Wert zum Deaktivieren auf false.

Debug-Modus

Um den Fehlerbehebungsmodus für Sprachbefehle zu aktivieren, rufen Sie getWindow().requestFeature(FEATURE_DEBUG_VOICE_COMMANDS) in der gewünschten Aktivität auf. Im Debug-Modus werden die folgenden Funktionen aktiviert:

  • Logcat enthält das Log mit der erkannten Wortgruppe zur Fehlerbehebung.
  • Ein UI-Overlay wird angezeigt, wenn ein unbekannter Befehl erkannt wird:
  • Bild für nicht erkannte Glass-Spracherkennung.

Kotlin

class VoiceCommandsActivity : AppCompatActivity() {

    companion object {
        const val FEATURE_VOICE_COMMANDS = 14
        const val FEATURE_DEBUG_VOICE_COMMANDS = 15
        const val REQUEST_PERMISSION_CODE = 200
        val PERMISSIONS = arrayOf(Manifest.permission.RECORD_AUDIO)
        val TAG = VoiceCommandsActivity::class.java.simpleName
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        window.requestFeature(FEATURE_VOICE_COMMANDS)
        window.requestFeature(FEATURE_DEBUG_VOICE_COMMANDS)
        setContentView(R.layout.activity_voice_commands)

        // Requesting permissions to enable voice commands menu
        ActivityCompat.requestPermissions(
            this,
            PERMISSIONS,
            REQUEST_PERMISSION_CODE
        )
    }
    .
    .
    .
}

Java

public class VoiceCommandsActivity extends AppCompatActivity {

  private static final String TAG = VoiceCommandsActivity.class.getSimpleName();
  private static final int FEATURE_VOICE_COMMANDS = 14;
  private static final int FEATURE_DEBUG_VOICE_COMMANDS = 15;
  private static final int REQUEST_PERMISSION_CODE = 200;
  private static final String[] PERMISSIONS = new String[]{Manifest.permission.RECORD_AUDIO};

  @Override
  protected void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    getWindow().requestFeature(FEATURE_VOICE_COMMANDS);
    getWindow().requestFeature(FEATURE_DEBUG_VOICE_COMMANDS);
    setContentView(R.layout.activity_voice_commands);

    // Requesting permissions to enable voice commands menu
    ActivityCompat.requestPermissions(this, PERMISSIONS, REQUEST_PERMISSION_CODE);
  }
  .
  .
  .
}

Weitere Informationen zur Implementierung finden Sie in der App zum Aktualisieren der Sprachbefehle.

Text-to-Speech (TTS)

Die Sprachausgabe-Funktion konvertiert digitalen Text in synthetisierte Sprachausgabe. Weitere Informationen finden Sie in der Dokumentation für Android Developers-Dokumentation zu TextToSpeech.

In Glass EE2 ist die Google Text-to-Speech-Engine installiert. Sie ist als standardmäßige TTS-Engine festgelegt und funktioniert offline.

Die folgenden Sprachen sind mit der Google Text-to-Speech-Engine gebündelt:

Bengalisch
Chinesisch (Mandarin)
Tschechisch
Dänisch
Deutsch
Griechisch
Englisch
Spanisch
Estnisch
Finnisch
Französisch
Gujarati
Hindi
Ungarisch
Indonesisch
Italienisch
Japanisch
Javanisch
Austronesisch
Austroasiatisch
Kannada
Koreanisch
Malayalam
Niederländisch
Niederländisch
Polnisch
Portugiesisch
Russisch
Slowakisch
Sundanesisch
Schwedisch
Tamil
Telugu
Thai
Türkisch
Ukrainisch
Vietnamesisch

Kamera

Glass Enterprise Edition 2 hat eine 8-Megapixel-Kamera mit festem Fokus, einer Blende von f/2, 4, einem Sensorverhältnis von 4:3 und einem diagonalen Sichtfeld von 83° (71° x 57° im Querformat). Wir empfehlen die Verwendung der standardmäßigen CameraX- oder Camera2-API.

Ausführliche Informationen zur Implementierung finden Sie in der Beispiel-Kamera-App.

Schaltfläche "Kamera"

Die Kamerataste ist die physische Taste am Scharnier des Geräts der Glass Enterprise Edition 2. Sie kann wie eine standardmäßige Tastaturaktion behandelt und durch den Schlüsselcode KeyEvent#KEYCODE_CAMERA identifiziert werden.

Ab der Aktualisierung des Betriebssystems OPM1.200313.001 werden von der Launcher-Anwendung Intents mit den folgenden Aktionen gesendet:

Sensoren

Entwicklern, die Anwendungen in Glass EE2 entwickeln, stehen verschiedene Sensoren zur Verfügung.

Die folgenden Android-Standardsensoren werden in Glass unterstützt:

Die folgenden Android-Sensoren werden von Glass nicht unterstützt:

Das Koordinatensystem von Glass ist in der folgenden Abbildung dargestellt. Sie ist relativ zum Glass-Display. Weitere Informationen finden Sie unter Sensorkoordinatensystem.

Das Koordinatensystem von Glass ist hier relativ zum Glass-Display zu sehen.

Der Beschleunigungsmesser, das Gyroskop und der Magnetometer befinden sich auf der optischen Kappe des Glass-Geräts, die Nutzer drehen, um das Gerät an das Sichtfeld anzupassen. Sie können den Winkel des optischen Pods nicht direkt messen. Berücksichtigen Sie das also, wenn Sie Winkel von diesen Sensoren für Anwendungen nutzen, zum Beispiel die Kompassausrichtung.

Damit der Akku geschont wird, sollten Sie Sensoren nur verwenden, wenn Sie sie brauchen. Berücksichtigen Sie die Anforderungen und den Lebenszyklus der Anwendung, wenn Sie entscheiden, wann die Sensoren gestartet und beendet werden sollen.

Sensorereignis-Callbacks werden im UI-Thread ausgeführt, sodass Ereignisse und Rückgaben schnellstmöglich verarbeitet werden. Wenn die Verarbeitung zu lange dauert, verschieben Sie die Sensorereignisse in eine Warteschlange und verwenden Sie einen Hintergrundthread, um sie zu verarbeiten.

50 Hz ist oft eine ausreichende Abtastrate, um die Kopfbewegungen zu erfassen.

Weitere Informationen zur Verwendung von Sensoren findest du im Android-Entwicklerleitfaden.

Standortdienste

Das Gerät der Glass Enterprise Edition 2 ist nicht mit einem GPS-Modul ausgestattet und kann nicht den Standort des Nutzers ermitteln. Es sind jedoch Standortdienste implementiert, was zur Anzeige einer Liste von WLANs und Bluetooth-Geräten in der Nähe erforderlich ist.

Wenn Ihre Anwendung Geräteinhaberberechtigungen hat, können Sie damit den Wert der entsprechenden sicheren Einstellung programmatisch ändern:

Kotlin

val devicePolicyManager = context
    .getSystemService(Context.DEVICE_POLICY_SERVICE) as DevicePolicyManager
if (devicePolicyManager.isDeviceOwnerApp(context.getPackageName())) {
    val componentName = ComponentName(context, MyDeviceAdmin::class.java)
    devicePolicyManager.setSecureSetting(
        componentName,
        Settings.Secure.LOCATION_MODE,
        Settings.Secure.LOCATION_MODE_SENSORS_ONLY.toString()
    )
}

Java

final DevicePolicyManager devicePolicyManager = (DevicePolicyManager) context
    .getSystemService(Context.DEVICE_POLICY_SERVICE);
if (devicePolicyManager.isDeviceOwnerApp(context.getPackageName())) {
  final ComponentName componentName = new ComponentName(context, MyDeviceAdmin.class);
  devicePolicyManager.setSecureSetting(componentName, Settings.Secure.LOCATION_MODE,
      String.valueOf(Settings.Secure.LOCATION_MODE_SENSORS_ONLY));
}

Wenn Sie eine MDM-Lösung eines Drittanbieters verwenden, muss die MDM-Lösung diese Einstellungen für Sie ändern können.