您可以使用标准的 Android 平台 API 访问位置和传感器数据。
位置
Glass 上的位置信息涉及使用标准的 Android 平台 API 从可用的位置信息提供程序获取位置数据。
您将使用以下 Android SDK 类获取位置数据:
LocationManager
- 提供对处理与LocationProvider
通信的 Android 位置信息服务的访问权限。LocationProvider
- 根据某些条件提供位置数据。Glass 提供了特殊的“远程”提供程序,可让您从安装了 MyGlass 配套应用的配对设备获取位置数据。Criteria
- 允许您创建一组条件,用于根据您设置的条件选择最佳LocationProvider
。
概览
如需获取位置数据,您需要使用 LocationManager
类从一个或多个位置信息提供程序获取数据。
Android 手机或平板电脑上的应用通过设备上的本地 GPS 和网络位置信息提供程序检索位置数据。但在 Glass 上,一组可用的位置信息提供程序是动态的,其中可能包括从其他来源(例如安装了 MyGlass 配套应用的蓝牙配对设备)提供位置数据的远程位置信息提供程序。要处理这些额外的提供程序,请监听来自多个提供程序的位置信息更新,而非单个提供程序。
要从所有可用的位置信息提供程序请求数据,请执行以下操作:
- 使用您的位置要求创建
Criteria
对象。 - 调用
getProviders()
可检索符合您的条件的已启用提供程序的列表。 - 遍历提供商列表,并从所有提供商请求更新。 这可确保您能够从远程提供商(如果可用)收到更新,还可以从 Glass 上的本地提供商(如无线网络提供商)收到更新。
使用每次更新时提供的准确性和时间信息来确定更新是否足够好,或者是否应等待下一次更新。
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 来延迟和停用游戏得分更新:
- 实现
BroadcastReceiver
来处理状态更改。 - 在您的服务中,实现
onCreate()
方法并注册一个用于监听ACTION_ON_HEAD_STATE_CHANGE
intent 的接收器。 在
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; } }
Android
Glass 支持以下 Android 传感器:
TYPE_ACCELEROMETER
TYPE_GRAVITY
TYPE_GYROSCOPE
TYPE_LIGHT
TYPE_LINEAR_ACCELERATION
TYPE_MAGNETIC_FIELD
TYPE_ORIENTATION
(已弃用)TYPE_ROTATION_VECTOR
不支持以下 Android 传感器:
以下是在 Glass 上使用传感器的一些提示:
- Glass 传感器坐标系(相对于 Glass 显示屏)在下方显示。如需了解详情,请参阅传感器坐标系。
加速度计、陀螺仪和磁力计位于 Glass 设备的光学元件架上,用户可以旋转设备,使其与视线对齐。您无法直接测量光学元件 Pod 的角度,因此在应用使用来自这些传感器的角度(例如罗盘方向)时,请注意这一点。
为了延长电池续航时间,请仅在需要时监听传感器。例如,如果您的 Glassware 使用
Service
渲染LiveCard
,并且您只需在实时卡片可见时需要使用传感器,请使用LiveCard
Surface 回调方法开始和停止监听传感器。传感器事件回调在界面线程上运行,因此请处理事件并尽快返回。如果处理时间过长,请考虑将传感器事件推送到队列中,并使用后台线程来处理这些事件。
通常,50 Hz 的采样率就足以跟踪头部运动。
如需详细了解如何使用传感器,请参阅 Android 开发者指南。