Ubicaciones y sensores

Puedes acceder a los datos de ubicación y de sensores con las APIs estándar de la plataforma de Android.

Ubicación

La ubicación en Glass implica el uso de las APIs estándar de la plataforma de Android para obtener datos de ubicación de los proveedores de ubicación disponibles.

Usarás las siguientes clases del SDK de Android para obtener datos de ubicación:

  • LocationManager: Proporciona acceso al servicio del sistema de ubicación de Android que controla la comunicación con un LocationProvider.

  • LocationProvider: Proporciona datos de ubicación según algunos criterios. Glass ofrece proveedores "remotos" especiales que te permiten obtener datos de ubicación de un dispositivo vinculado que tenga instalada la app complementaria de MyGlass.

  • Criteria: Te permite crear un conjunto de criterios que selecciona el mejor LocationProvider en función de los criterios que establezcas.

Descripción general

Para obtener datos de ubicación, deberás usar la clase LocationManager para obtener datos de uno o más proveedores de ubicación.

Las aplicaciones en un teléfono o tablet Android recuperan datos de ubicación de los proveedores de ubicación de red y GPS local del dispositivo. Sin embargo, en Glass, el conjunto de proveedores de ubicación disponibles es dinámico y puede incluir proveedores de ubicación remoto que proporcionan datos de ubicación de otra fuente, como un dispositivo vinculado con Bluetooth que tiene instalada la aplicación complementaria MyGlass. Para controlar estos proveedores adicionales, escucha las actualizaciones de ubicación de varios proveedores en lugar de uno solo.

Para solicitar datos de todos los proveedores de ubicación disponibles, sigue estos pasos:

  1. Crea un objeto Criteria con tus requisitos de ubicación.
  2. Llama a getProviders() para recuperar la lista de proveedores habilitados que cumplan con tus criterios.
  3. Itera la lista de proveedores y solicita actualizaciones a todos ellos. Esto garantiza que recibas actualizaciones de los proveedores remotos, si están disponibles, pero también de los proveedores locales en Glass (como un proveedor de red inalámbrica).
  4. Usa la información de precisión y tiempo proporcionada con cada actualización para determinar si la actualización es lo suficientemente buena o si debes esperar una nueva.

    LocationManager locationManager; // initialized elsewhere
    
    // This example requests fine accuracy and requires altitude, but
    // these criteria could be whatever you want.
    Criteria criteria = new Criteria();
    criteria.setAccuracy(Criteria.ACCURACY_FINE);
    criteria.setAltitudeRequired(true);
    
    List<String> providers = locationManager.getProviders(
            criteria, true /* enabledOnly */);
    
    for (String provider : providers) {
        locationManager.requestLocationUpdates(provider, minTime,
                minDistance, listener);
    }
    

Sensores

Vidrio

Glass tiene un sensor especializado para detectar si el dispositivo está o no en la cabeza del usuario. Cuando se habilita, este parámetro de configuración ayuda a ahorrar batería cuando el dispositivo no está en uso. Puedes usar esta función en Glassware para inhabilitar o limitar los servicios en segundo plano. Comienza por implementar un BroadcastReceiver para detectar eventos ACTION_ON_HEAD_STATE_CHANGE.

En el siguiente ejemplo, se inhabilitan y retrasan las actualizaciones de puntuación del juego en función de si el usuario quitó Glass de su cabeza:

  1. Implementa un BroadcastReceiver para controlar el cambio de estado.
  2. En tu servicio, implementa el método onCreate() y registra un receptor que escuche el intent ACTION_ON_HEAD_STATE_CHANGE.
  3. En el método onDestroy(), cancela el registro del receptor.

    import com.google.android.glass.content.Intents;
    ...
    
    public class LiveCardService extends Service {
    
        ...
        private boolean mIsStopped = false;
    
        private final BroadcastReceiver broadCastReceiver = new BroadcastReceiver() {
            @Override
            public void onReceive(Context context, Intent intent) {
    
                if (Intents.ACTION_ON_HEAD_STATE_CHANGED.equals(intent.getAction())) {
                    boolean onHead = intent.getBooleanExtra(Intents.EXTRA_IS_ON_HEAD,
                            false);
                    if (onHead) {
                        mDelay = LiveCardService.DELAY_MILLIS;
                        if (isStopped()) {
                            // Resume updating scores
                            setStop(false);
    
                            // Restart immediately to get a refreshed score
                            mHandler.postDelayed(mUpdateLiveCardRunnable, 0);
                        }
                    } else {
                        // Increase the delay when the device is off head
                        mDelay = LiveCardService.DELAY_MILLIS_EXT;
                    }
                }
            }
        };
    
        private final Runnable mUpdateLiveCardRunnable = new Runnable() {
    
            @Override
            public void run() {
    
                if (mDelay == DELAY_MILLIS_EXT) {
                    // Count the increased delay as a retry attempt
                    mRetryCount++;
                } else if (mDelay == DELAY_MILLIS) {
                    mRetryCount = 0;
                }
    
                if (mRetryCount > MAX_RETRIES) {
                    // Stop updating scores
                    mIsStopped = true;
                }
    
                if (!isStopped()) {
                    // Generate fake points.
                    homeScore += mPointsGenerator.nextInt(3);
                    awayScore += mPointsGenerator.nextInt(3);
    
                    // Update the remote view with the new scores.
                    mLiveCardView = getRemoteViews(homeScore, awayScore);
    
                    // Always call setViews() to update the live card's RemoteViews.
                    mLiveCard.setViews(mLiveCardView);
    
                    // Queue another score update in 30 seconds.
                    mHandler.postDelayed(mUpdateLiveCardRunnable, mDelay);
                }
            }
        };
    
        @Override
        public void onCreate() {
            super.onCreate();
            mPointsGenerator = new Random();
            mDelay = DELAY_MILLIS;
    
            registerReceiver(broadCastReceiver, new IntentFilter(
                    Intents.ACTION_ON_HEAD_STATE_CHANGED));
        }
    
        @Override
        public int onStartCommand(Intent intent, int flags, int startId) {
            if (mLiveCard == null) {
    
                // Get an instance of a live card
                mLiveCard = new LiveCard(this, LIVE_CARD_TAG);
    
                // Inflate a layout into a remote view
                mLiveCardView = new RemoteViews(getPackageName(),
                        R.layout.live_card);
    
                // Set up initial RemoteViews values
                homeScore = 0;
                awayScore = 0;
                mLiveCardView = getRemoteViews(homeScore, awayScore);
    
                // Set up the live card's action with a pending intent
                // to show a menu when tapped
                Intent menuIntent = new Intent(this, LiveCardMenuActivity.class);
                menuIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK |
                        Intent.FLAG_ACTIVITY_CLEAR_TASK);
                mLiveCard.setAction(PendingIntent.getActivity(
                        this, 0, menuIntent, 0));
    
                // Publish the live card
                mLiveCard.publish(PublishMode.REVEAL);
    
                // Queue the update text runnable
                mHandler.post(mUpdateLiveCardRunnable);
            }
    
            return START_STICKY;
        }
    
        @Override
        public void onDestroy() {
            if (mLiveCard != null && mLiveCard.isPublished()) {
                //Stop the handler from queuing more Runnable jobs
                setStop(true);
    
                mLiveCard.unpublish();
                mLiveCard = null;
            }
    
            unregisterReceiver(broadCastReceiver);
    
            super.onDestroy();
        }
    
        @Override
        public IBinder onBind(Intent intent) {
            return null;
        }
    
        private RemoteViews getRemoteViews(int homeScore, int awayScore) {
            RemoteViews remoteViews = new RemoteViews(getPackageName(),
                    R.layout.live_card);
    
            remoteViews.setTextViewText(R.id.home_team_name_text_view,
                    getString(R.string.home_team));
            remoteViews.setTextViewText(R.id.away_team_name_text_view,
                    getString(R.string.away_team));
            remoteViews.setTextViewText(R.id.footer_text,
                    getString(R.string.game_quarter));
    
            remoteViews.setTextViewText(R.id.home_score_text_view,
                    String.valueOf(homeScore));
            remoteViews.setTextViewText(R.id.away_score_text_view,
                    String.valueOf(awayScore));
            return remoteViews;
        }
    
        public boolean isStopped() {
            return mIsStopped;
        }
    
        public void setStop(boolean isStopped) {
            mIsStopped = isStopped;
        }
    }
    

Android

Los siguientes sensores de Android son compatibles con Glass:

Los siguientes sensores de Android no son compatibles:

A continuación, se ofrecen algunas sugerencias para usar sensores en Glass:

  • El sistema de coordenadas del sensor Glass se muestra a continuación en relación con la pantalla 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 el pod de óptica del dispositivo Glass, que los usuarios rotan para alinear el dispositivo con su vista. No puedes medir el ángulo del pod de la óptica directamente, así que ten esto en cuenta cuando uses los ángulos de estos sensores para aplicaciones como la orientación de la brújula.

  • Para preservar la duración de batería, solo escucha los sensores cuando los necesites. Por ejemplo, si tu Glassware usa un Service para renderizar un LiveCard y solo necesitas los sensores cuando la tarjeta activa está visible, usa los métodos de devolución de llamada de superficie LiveCard para comenzar a escuchar los sensores y dejar de hacerlo.

  • Las devoluciones de llamada de eventos de sensor se ejecutan en el subproceso de IU, por lo que debes procesar los eventos y mostrarlos lo más rápido posible. Considera enviar los eventos del sensor a una cola y usar un subproceso en segundo plano para controlarlos si el procesamiento lleva demasiado tiempo.

  • A menudo, 50 Hz es suficiente tasa de muestreo para monitorear el movimiento de la cabeza.

Para obtener más información sobre cómo usar sensores, consulta la guía para desarrolladores de Android.