Locais e sensores

Você acessa dados de local e sensor usando as APIs da Plataforma Android padrão.

Local

O recurso de localização no Google Glass envolve o uso das APIs padrão da Plataforma Android para receber dados de local dos provedores de localização disponíveis.

Você usará as seguintes classes do SDK do Android para coletar dados de local:

  • LocationManager: fornece acesso ao serviço do sistema de localização do Android que gerencia a comunicação com um LocationProvider.

  • LocationProvider: fornece dados de local com base em alguns critérios. O Google Glass fornece provedores "remotos" especiais que permitem receber dados de local de um dispositivo pareado com o app complementar MyGlass instalado.

  • Criteria: permite criar um conjunto de critérios que seleciona o melhor LocationProvider com base nos critérios definidos por você.

Visão geral

Para coletar dados de local, você precisa usar a classe LocationManager para acessar dados de um ou mais provedores de localização.

Os apps em smartphones ou tablets Android recuperam dados de local dos provedores locais de GPS e de rede do dispositivo. No entanto, no Glass, o conjunto de provedores de localização disponíveis é dinâmico e pode incluir provedores de localização remota que fornecem dados de localização de outra fonte, como um dispositivo pareado com Bluetooth com o app complementar MyGlass instalado. Para gerenciar esses provedores adicionais, detecte atualizações de local de vários provedores em vez de um único provedor.

Para solicitar dados de todos os provedores de local disponíveis, faça o seguinte:

  1. Crie um objeto Criteria com os requisitos de localização.
  2. Chame getProviders() para recuperar a lista de provedores ativados que atendem aos seus critérios.
  3. Itere a lista de provedores e solicite atualizações de todos eles. Isso garante que você receba atualizações dos provedores remotos, se estiverem disponíveis, mas também dos provedores locais do Google Glass, como um provedor de rede sem fio.
  4. Use as informações de precisão e tempo fornecidas em cada atualização para determinar se ela é boa o suficiente ou se é necessário esperar por outra.

    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

Copo

O Google Glass tem um sensor especializado para detectar se o dispositivo está ou não na cabeça do usuário. Quando ativada, essa configuração ajuda a economizar bateria quando o dispositivo não está em uso. Você pode usar esse recurso no Glassware para desativar ou limitar os serviços em segundo plano. Comece implementando um BroadcastReceiver para detectar eventos ACTION_ON_HEAD_STATE_CHANGE.

O exemplo a seguir atrasa e desativa as atualizações da pontuação do jogo com base no fato de o usuário ter removido o Glass da cabeça:

  1. Implemente um BroadcastReceiver para processar a mudança de estado.
  2. No seu serviço, implemente o método onCreate() e registre um receptor que detecte a intent ACTION_ON_HEAD_STATE_CHANGE.
  3. No método onDestroy(), cancele o registro do 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

Os seguintes sensores Android são compatíveis com o Google Glass:

Os seguintes sensores Android não são compatíveis:

Veja algumas dicas para usar sensores no Google Glass:

  • O sistema de coordenadas do sensor do Google Glass é mostrado abaixo em relação à tela do Google Glass. Para ver mais informações, consulte sistema de coordenadas do sensor.

  • O acelerômetro, o giroscópio e o magnetômetro estão localizados no pod óptico do dispositivo Glass, que os usuários giram para alinhar o dispositivo com a visão. Não é possível medir o ângulo do pod óptico diretamente. Portanto, esteja ciente disso ao usar ângulos desses sensores para aplicativos como a orientação da bússola.

  • Para preservar a duração da bateria, escute os sensores somente quando precisar deles. Por exemplo, se o seu Glassware usa um Service para renderizar um LiveCard e você só precisa dos sensores quando o cartão ao vivo está visível, use os métodos de callback de superfície LiveCard para iniciar e parar de detectar os sensores.

  • Os callbacks de evento do sensor são executados na linha de execução de IU. Portanto, processe eventos e retorne o mais rápido possível. Considere enviar eventos do sensor para uma fila e usar uma linha de execução em segundo plano para processá-los se o processamento demorar muito.

  • Normalmente, 50 Hz é uma taxa de amostragem suficiente para rastrear o movimento da cabeça.

Para ver mais informações sobre o uso de sensores, consulte o Guia do desenvolvedor Android.