El SDK de Android te brinda acceso a los distintos sensores y entradas disponibles con Glass EE2. En esta página, se proporciona una descripción general de las funciones disponibles, detalles de implementación y sugerencias útiles.
Gestos táctiles
Puedes usar el SDK de Android para habilitar el acceso a los datos sin procesar desde el panel táctil de Glass. Esto se logra a través de un detector de gestos que detecta automáticamente gestos comunes en Glass, como presionar, deslizar y desplazarse.
También puedes usar este detector de gestos en tus apps para dar cuenta de cómo presionar, deslizar el dedo hacia adelante, hacia atrás y hacia abajo. Esto es similar a los dispositivos Glass anteriores.
Se recomienda usar estos gestos de las siguientes maneras:
- Presionar: Confirmar o ingresar.
- Deslizar el dedo hacia adelante y deslizar el dedo hacia atrás: Navega por las tarjetas y las pantallas.
- Deslizar hacia abajo: Atrás o Salir.
Para obtener detalles sobre la implementación, lee el detector de gestos de muestra.
Cómo detectar gestos con el detector de gestos de Android
Android GestureDetector
te permite detectar gestos simples y complejos, como los que usan varios dedos o el desplazamiento.
Cómo detectar gestos a nivel de la actividad
Detecta gestos a nivel de la actividad solo cuando no importa en qué parte de la IU se enfoca.
Por ejemplo, si quieres que aparezca un menú cuando un usuario presiona el panel táctil, independientemente de la vista enfocada, controla el MotionEvent
de la actividad.
El siguiente es un ejemplo de detección de gestos a nivel de actividad que usa GestureDetector
e implementa GestureDetector.OnGestureListener
para procesar gestos reconocidos, que luego se manejan y traducen a lo siguiente:
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); } } } }
Ejemplo de uso
Para usar la detección de gestos a nivel de la actividad, debes completar las siguientes tareas:
- Agrega la siguiente declaración a tu archivo de manifiesto, dentro de la declaración de la aplicación. Esto permite que tu app reciba el
MotionEvent
en la actividad:<application> <!-- Copy below declaration into your manifest file --> <meta-data android:name="com.google.android.glass.TouchEnabledApplication" android:value="true" /> </application>
- Anula el método
dispatchTouchEvent(motionEvent)
de la actividad para pasar los eventos de movimiento al métodoonTouchEvent(motionEvent)
del detector de gestos. - Implementa
GlassGestureDetector.OnGestureListener
en tu actividad.
El siguiente es un ejemplo de un detector de gestos a nivel de actividad:
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); } }
Entrada de audio
Glass Enterprise Edition 2 es un dispositivo estándar basado en AOSP que admite fuentes de audio básicas.
Se implementó el procesamiento de señal avanzada en las siguientes fuentes de audio:
Reconocimiento de voz
Glass Enterprise Edition 2 admite una implementación nativa para el reconocimiento de voz. Solo se admite en inglés.
La IU de reconocimiento de voz espera a que los usuarios hablen y, luego, muestra el texto transcrito después de terminar. Para iniciar la actividad, sigue estos pasos:
- Llama a
startActivityForResult()
con el intentACTION_RECOGNIZE_SPEECH
. Los siguientes extras de intents se admiten cuando inicias la actividad: - Anula la devolución de llamada
onActivityResult()
para recibir el texto transcrito del intent adicionalEXTRA_RESULTS
, como se muestra en el siguiente ejemplo de código. Se llama a esta devolución de llamada cuando el usuario termina de hablar.
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); }
Para obtener detalles sobre la implementación, lee la app de reconocimiento de voz de muestra.
Personalización de palabras clave
El reconocimiento de voz en Glass puede estar sesgado para una lista de palabras clave. La personalización aumenta la precisión del reconocimiento de palabras clave. Para habilitar la personalización de palabras clave, utilice lo siguiente:
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);
Comandos por voz
Los comandos por voz permiten a los usuarios realizar acciones a partir de actividades. Puedes compilar comandos por voz con las API de menú estándar de Android, pero los usuarios pueden invocar los elementos del menú con comandos por voz en lugar de tocarlos.
Para habilitar los comandos por voz para una actividad en particular, sigue estos pasos:
- Llama a
getWindow().requestFeature(FEATURE_VOICE_COMMANDS)
en la actividad deseada para habilitar los comandos por voz. Cuando esta función está habilitada, el ícono de micrófono aparece en la esquina inferior izquierda de la pantalla cada vez que esta actividad recibe el foco. - Solicita el permiso
RECORD_AUDIO
en la app. - Anula
onCreatePanelMenu()
y aumenta un recurso de menú. - Anula
onContextItemSelected()
para controlar los comandos por voz detectados.
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); } } }
El siguiente es un ejemplo del recurso de menú que usa la actividad anterior:
<?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>
Lee la app para tomar notas de muestra a fin de obtener un ejemplo completo.
Se está volviendo a cargar la lista de comandos por voz
Puedes volver a cargar la lista de comandos por voz de forma dinámica. Para hacerlo, reemplaza el recurso menu
en el método onCreatePanelMenu()
o modifica el objeto de menú en el método onPreparePanel()
. Para aplicar cambios, llama al método invalidateOptionsMenu()
.
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(); }
Solución AppCompatActivity
Para volver a cargar una lista de comandos por voz en una actividad que extiende AppCompatActivity
, usa el método sendBroadcast()
con la acción de intent reload-voice-commands
:
Kotlin
sendBroadcast(Intent("reload-voice-commands"))
Java
sendBroadcast(new Intent("reload-voice-commands"));
Inhabilitar y habilitar comandos por voz en tiempo de ejecución
Puedes habilitar o inhabilitar los comandos por voz en el entorno de ejecución. Para ello, muestra un valor apropiado del método onCreatePanelMenu()
de la siguiente manera:
- Establece el valor en
true
para habilitarlo. - Establece el valor en
false
para inhabilitarlo.
Modo de depuración
A fin de habilitar el modo de depuración para comandos por voz, llama a getWindow().requestFeature(FEATURE_DEBUG_VOICE_COMMANDS)
en la actividad deseada. El modo de depuración activa las siguientes funciones:
- Logcat contiene el registro con la frase reconocida para la depuración.
- La superposición de la IU se muestra cuando se detecta un comando no reconocido, como se muestra a continuación:
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); } . . . }
Para obtener los detalles de la implementación, lee los ejemplos de la app de recarga de comandos por voz.
Text-to-Speech (TTS)
La función de texto a voz convierte el texto digital en una salida de voz sintetizada. Para obtener más información, consulta la documentación de TextToSpeech para desarrolladores de Android.
Glass EE2 tiene instalado el motor de texto a voz de Google. Se establece como el motor de texto a voz predeterminado y funciona sin conexión.
Las siguientes configuraciones regionales se agrupan con el motor de texto a voz de Google:
Bengalí chino mandarín checo danés alemán griego inglés español estonio finlandés francés guyaratí hindi |
Húngaro Indonesio Italiano Japonés Javanés Austronés Austroasiatic Canarés Coreano Malabar Noruego Holandés |
polaco portugués ruso eslovaco sudanés sueco tamil telugu tailandés turco ucraniano vietnamita |
Cámara
Glass Enterprise Edition 2 está equipado con una cámara de enfoque fijo de 8 megapíxeles, apertura de f/2.4, proporción del sensor de 4:3 y campo visual diagonal de 83° (71° x 57° en orientación horizontal). Te recomendamos que uses la API estándar de CameraX o Camera2.
Para obtener detalles sobre la implementación, lee la app de cámara de muestra.
Botón de cámara
El botón de cámara es el botón físico de la bisagra del dispositivo Glass Enterprise Edition 2.
Se puede manejar como una acción de teclado estándar y se puede identificar con el código de tecla KeyEvent#KEYCODE_CAMERA
.
A partir de la actualización del SO OPM1.200313.001, los intents con las siguientes acciones se envían desde la aplicación Launcher:
- Presiona
MediaStore#ACTION_IMAGE_CAPTURE
en el botón de la cámara. MediaStore#ACTION_VIDEO_CAPTURE
mantén presionado el botón de la cámara.
Sensores
Hay una variedad de sensores disponibles para los desarrolladores a medida que desarrollan aplicaciones en Glass EE2.
Los siguientes sensores de Android estándar son compatibles con Glass:
-
TYPE_ACCELEROMETER
-
TYPE_GRAVITY
-
TYPE_GYROSCOPE
-
TYPE_LIGHT
-
TYPE_LINEAR_ACCELERATION
-
TYPE_MAGNETIC_FIELD
TYPE_ORIENTATION
(obsoleto)-
TYPE_ROTATION_VECTOR
Los siguientes sensores de Android no son compatibles con Glass:
El sistema de coordenadas del sensor de Glass se muestra en la siguiente ilustración. Es relativa a la pantalla de Glass. Para obtener más información, consulta Sistema de coordenadas del sensor.
El acelerómetro, el giroscopio y el magnetómetro se encuentran en la cápsula óptica del dispositivo Glass, que los usuarios rotan para alinear el dispositivo con su vista. No puedes medir directamente el ángulo del pod óptico, así que ten esto en cuenta cuando uses los ángulos de estos sensores para aplicaciones, como el rumbo a una brújula.
Para conservar la duración de la batería, solo escucha los sensores cuando los necesites. Ten en cuenta las necesidades y el ciclo de vida de la app cuando decidas cuándo iniciar y detener la detección de los sensores.
Las devoluciones de llamada de eventos del sensor se ejecutan en el subproceso de IU, por lo que debes procesar los eventos y mostrarlos lo más rápido posible. Si el procesamiento lleva demasiado tiempo, envía los eventos del sensor a una cola y usa un subproceso en segundo plano para controlarlos.
A menudo, una frecuencia de muestreo de 50 Hz es suficiente para realizar un seguimiento del movimiento de la cabeza.
Para obtener más información sobre cómo usar los sensores, consulta la Guía para desarrolladores de Android.
Servicios de ubicación
El dispositivo Glass Enterprise Edition 2 no incluye un módulo de GPS y no proporciona la ubicación del usuario. Sin embargo, tiene implementados servicios de ubicación, que son necesarios para mostrar una lista de redes Wi-Fi y dispositivos Bluetooth cercanos.
Si tu aplicación tiene privilegios de propietario del dispositivo, puedes usarla para cambiar de manera programática el valor de la configuración segura correspondiente:
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)); }
Si usas una solución de MDM de terceros, esta debe poder cambiar esta configuración por ti.