Vị trí và cảm biến

Bạn truy cập vào dữ liệu vị trí và cảm biến bằng các API nền tảng Android tiêu chuẩn.

Vị trí

Vị trí trên Glass bao gồm việc sử dụng API nền tảng Android tiêu chuẩn để nhận dữ liệu vị trí từ các nhà cung cấp vị trí có sẵn.

Bạn sẽ sử dụng các lớp SDK Android sau đây để nhận dữ liệu vị trí:

  • LocationManager – Cung cấp quyền truy cập vào dịch vụ hệ thống vị trí Android có chức năng xử lý giao tiếp với LocationProvider.

  • LocationProvider – Cung cấp dữ liệu vị trí dựa trên một số tiêu chí. Glass cung cấp các nhà cung cấp "từ xa" đặc biệt cho phép bạn lấy dữ liệu vị trí từ một thiết bị đã ghép nối có cài đặt ứng dụng đồng hành MyGlass.

  • Criteria – Cho phép bạn tạo một tập hợp các tiêu chí chọn LocationProvider tốt nhất dựa trên các tiêu chí mà bạn đã đặt.

Tổng quan

Để có được dữ liệu vị trí, bạn cần sử dụng lớp LocationManager để nhận dữ liệu từ một hoặc nhiều nhà cung cấp vị trí.

Các ứng dụng trên điện thoại hoặc máy tính bảng Android sẽ truy xuất dữ liệu vị trí từ các nhà cung cấp vị trí GPS và GPS cục bộ trên thiết bị. Tuy nhiên, trên Glass, nhóm các nhà cung cấp vị trí hiện có đều là động và có thể bao gồm các nhà cung cấp vị trí từ xa cung cấp dữ liệu vị trí từ một nguồn khác, chẳng hạn như thiết bị ghép nối Bluetooth có cài đặt ứng dụng đồng hành MyGlass. Để xử lý các nhà cung cấp bổ sung này, hãy theo dõi thông tin cập nhật về vị trí từ nhiều nhà cung cấp thay vì một nhà cung cấp duy nhất.

Để yêu cầu dữ liệu từ tất cả các nhà cung cấp vị trí có sẵn:

  1. Tạo đối tượng Criteria theo các yêu cầu về vị trí của bạn.
  2. Hãy gọi getProviders() để truy xuất danh sách các nhà cung cấp đã bật đáp ứng các tiêu chí của bạn.
  3. Lặp lại danh sách nhà cung cấp và yêu cầu cập nhật từ tất cả nhà cung cấp. Điều này đảm bảo rằng bạn nhận được thông tin cập nhật từ các nhà cung cấp từ xa nếu có, nhưng cũng từ các nhà cung cấp tại địa phương trên Glass (chẳng hạn như nhà cung cấp mạng không dây).
  4. Sử dụng thông tin về độ chính xác và thời gian được cung cấp trong mỗi bản cập nhật để xác định xem bản cập nhật có đủ tốt không hoặc bạn nên đợi một bản cập nhật khác.

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

Cảm biến

Ly

Glass có một cảm biến chuyên dụng để phát hiện xem thiết bị có ở trên đầu của người dùng hay không. Khi được bật, chế độ cài đặt này giúp tiết kiệm pin khi thiết bị không được sử dụng. Bạn có thể sử dụng tính năng này trong Glassware để tắt hoặc điều tiết các dịch vụ nền. Bắt đầu bằng cách triển khai BroadcastReceiver để phát hiện các sự kiện ACTION_ON_HEAD_STATE_CHANGE.

Ví dụ sau đây trì hoãn và tắt tính năng cập nhật điểm số trò chơi dựa trên việc người dùng đã xoá Glass khỏi đầu hay chưa:

  1. Triển khai một BroadcastReceiver để xử lý thay đổi trạng thái.
  2. Trong dịch vụ của bạn, hãy triển khai phương thức onCreate() và đăng ký trình nhận để theo dõi ý định ACTION_ON_HEAD_STATE_CHANGE.
  3. Trong phương thức onDestroy(), hãy huỷ đăng ký trình nhận.

    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

Các cảm biến Android sau đây được hỗ trợ trên Glass:

Các cảm biến Android sau đây không được hỗ trợ:

Dưới đây là một số mẹo khi sử dụng cảm biến trên Glass:

  • Hệ thống toạ độ của cảm biến Glass được hiển thị bên dưới so với màn hình Glass. Để biết thêm thông tin, vui lòng xem nội dung hệ thống toạ độ cảm biến.

  • Gia tốc kế, con quay hồi chuyển và từ kế nằm trên vỏ quang học của thiết bị Glass. Người dùng có thể xoay để căn chỉnh thiết bị với tầm nhìn của họ. Bạn không thể đo lường trực tiếp góc của nhóm quang học, vì vậy, xin lưu ý điều này khi sử dụng các góc từ các cảm biến này cho ứng dụng như tiêu đề la bàn.

  • Để duy trì thời lượng pin, bạn chỉ nên nghe cảm biến khi cần. Ví dụ: nếu Glassware sử dụng Service để kết xuất LiveCard và bạn chỉ cần cảm biến khi thẻ trực tiếp xuất hiện, hãy sử dụng LiveCard phương thức gọi lại trên bề mặt để bắt đầu và dừng nghe cảm biến.

  • Các lệnh gọi lại sự kiện cảm biến chạy trên luồng giao diện người dùng, vì vậy, hãy xử lý các sự kiện và trả về nhanh nhất có thể. Cân nhắc việc đẩy các sự kiện cảm biến vào hàng đợi và sử dụng chuỗi trong nền để xử lý các sự kiện đó nếu quá trình xử lý mất quá nhiều thời gian.

  • 50 Hz thường là tốc độ lấy mẫu đủ để theo dõi chuyển động của đầu.

Để biết thêm thông tin về cách sử dụng cảm biến, hãy xem Hướng dẫn dành cho nhà phát triển Android.