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

Вы получаете доступ к данным о местоположении и датчикам, используя стандартные 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 показана ниже относительно дисплея Glass. Для получения дополнительной информации см. систему координат датчика .

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

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

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

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

Дополнительные сведения об использовании датчиков см. в руководстве для разработчиков Android .