Ubicaciones y sensores

Puedes acceder a los datos de ubicación y del sensor con las API de plataforma de Android estándar.

Ubicación

La ubicación en Glass implica el uso de las API de la plataforma de Android estándar 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 en función de algunos criterios. Glass proporciona proveedores "remotos" especiales que te permiten obtener datos de ubicación desde un dispositivo sincronizado que tenga instalada la app complementaria de MyGlass.

  • Criteria: Te permite crear un conjunto de criterios que selecciona el mejor LocationProvider según los criterios que establezcas.

Descripción general

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

Las aplicaciones en un teléfono o tablet Android recuperan datos de ubicación de GPS locales y proveedores de ubicación de red en el dispositivo. Sin embargo, en Glass, el conjunto de proveedores de ubicación disponibles es dinámico y puede incluir proveedores de ubicación remota que proporcionan datos de ubicación desde otra fuente, como un dispositivo sincronizado con Bluetooth con la app complementaria de MyGlass instalada. Para controlar estos proveedores adicionales, detecta las actualizaciones de ubicación de varios proveedores en lugar de un solo proveedor.

Para solicitar datos de todos los proveedores de ubicación disponibles:

  1. Crea un objeto Criteria con tus requisitos de ubicación.
  2. Llama a getProviders() para recuperar la lista de proveedores habilitados que cumplen con tus criterios.
  3. Repita la lista de proveedores y solicite 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 sincronización que se proporciona con cada actualización para determinar si es lo suficientemente buena o si debes esperar otra.

    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á sobre la cabeza del usuario. Cuando está habilitada, esta configuración ayuda a conservar la batería cuando el dispositivo no está en uso. Puedes usar esta función en tu Glassware para inhabilitar o limitar los servicios en segundo plano. Comienza por implementar una BroadcastReceiver para detectar eventos ACTION_ON_HEAD_STATE_CHANGE.

En el siguiente ejemplo, se retrasan y se inhabilitan las actualizaciones de la 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(), anula 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 Android son compatibles con Glass:

No se admiten los siguientes sensores Android:

Estas son algunas sugerencias para usar sensores en Glass:

  • A continuación, se muestra el sistema de coordenadas del sensor de Glass en relación con la pantalla Glass. Para obtener más información, consulta el sistema de coordenadas de sensores.

  • El acelerómetro, el giroscopio y el magnetómetro se encuentran en el pod óptico del dispositivo Glass, que los usuarios giran para alinearlo con su visión. No puedes medir directamente el ángulo del pod óptico, así que ten esto en cuenta cuando uses ángulos de estos sensores para aplicaciones como la orientación de la brújula.

  • Para conservar la duración de la batería, solo escucha los sensores cuando los necesites. Por ejemplo, si tu Glassware usa un Service para procesar un LiveCard y solo necesitas los sensores cuando la tarjeta en vivo está visible, usa los métodos de devolución de llamada de superficie LiveCard para iniciar y dejar de escuchar 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. Considera enviar eventos del sensor a una cola y usar un subproceso en segundo plano para controlarlos si el procesamiento lleva demasiado tiempo.

  • 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.