Локации и датчики

Вы получаете доступ к данным о местоположении и датчикам, используя стандартные API-интерфейсы платформы Android.

Расположение

Местоположение на Glass предполагает использование стандартных API-интерфейсов платформы Android для получения данных о местоположении от доступных поставщиков местоположения.

Для получения данных о местоположении вы будете использовать следующие классы Android SDK:

  • LocationManager — обеспечивает доступ к службе системы определения местоположения Android, которая обрабатывает связь с LocationProvider .

  • LocationProvider — предоставляет данные о местоположении на основе некоторых критериев. Glass предоставляет специальных «удаленных» поставщиков, которые позволяют получать данные о местоположении с сопряженного устройства, на котором установлено сопутствующее приложение MyGlass.

  • Criteria — позволяет создать набор критериев, который выбирает лучший LocationProvider на основе заданных вами критериев.

Обзор

Чтобы получить данные о местоположении, вам нужно будет использовать класс LocationManager для получения данных от одного или нескольких поставщиков местоположений.

Приложения на телефоне или планшете Android получают данные о местоположении от местных поставщиков GPS и сетевых местоположений на устройстве. Однако в Glass набор доступных поставщиков местоположения является динамическим и может включать поставщиков удаленных местоположений, которые предоставляют данные о местоположении из другого источника, например, с устройства, подключенного по Bluetooth, с установленным приложением-компаньоном MyGlass. Чтобы справиться с этими дополнительными поставщиками, прослушивайте обновления местоположения от нескольких поставщиков, а не от одного поставщика.

Чтобы запросить данные у всех доступных поставщиков местоположений:

  1. Создайте объект Criteria с вашими требованиями к местоположению.
  2. Вызовите getProviders() , чтобы получить список включенных поставщиков, соответствующих вашим критериям.
  3. Перебирайте список поставщиков и запрашивайте обновления у всех из них. Это гарантирует получение обновлений от удаленных поставщиков, если они доступны, а также от локальных поставщиков на Glass (например, от поставщика беспроводной сети).
  4. Используйте информацию о точности и времени, предоставляемую с каждым обновлением, чтобы определить, достаточно ли обновление или вам следует подождать следующего.

    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);
    }
    

Датчики

Стекло

Glass имеет специальный датчик, который определяет, находится ли устройство на голове пользователя. Если этот параметр включен, этот параметр помогает экономить заряд батареи, когда устройство не используется. Вы можете использовать эту функцию в своей Glassware, чтобы отключить или ограничить фоновые службы. Начните с реализации BroadcastReceiver для обнаружения событий ACTION_ON_HEAD_STATE_CHANGE .

В следующем примере обновление очков игры задерживается и отключается в зависимости от того, удалил ли пользователь Glass со своей головы:

  1. Реализуйте BroadcastReceiver для обработки изменения состояния.
  2. В своем сервисе реализуйте метод onCreate() и зарегистрируйте получатель, который прослушивает намерение ACTION_ON_HEAD_STATE_CHANGE .
  3. В методе onDestroy() отмените регистрацию получателя.

    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;
        }
    }
    

Андроид

В Glass поддерживаются следующие датчики Android:

Следующие датчики Android не поддерживаются:

Вот несколько советов по использованию датчиков на стекле:

  • Система координат датчика стекла показана ниже относительно дисплея стекла. Для получения дополнительной информации см. систему координат датчика .

  • Акселерометр, гироскоп и магнитометр расположены на оптическом блоке устройства Glass, который пользователи поворачивают, чтобы совместить устройство со своим зрением. Вы не можете измерить угол оптики напрямую, поэтому имейте это в виду при использовании углов от этих датчиков для таких приложений, как направление по компасу.

  • Чтобы продлить срок службы батареи, прислушивайтесь к сигналам датчиков только тогда, когда они вам нужны. Например, если ваша стеклянная посуда использует Service для отображения LiveCard , а датчики нужны только тогда, когда живая карта видна, используйте методы обратного вызова поверхности LiveCard , чтобы начать и прекратить прослушивание датчиков.

  • Обратные вызовы событий датчиков выполняются в потоке пользовательского интерфейса, поэтому события обрабатываются и возвращаются как можно быстрее. Рассмотрите возможность помещения событий датчиков в очередь и использования фонового потока для их обработки, если обработка занимает слишком много времени.

  • Частоты 50 Гц часто бывает достаточной для отслеживания движения головы.

Дополнительную информацию о том, как использовать датчики, можно найти в руководстве для разработчиков Android .