Android SDK 可讓您使用 Glass EE2 提供的各種輸入和感應器。本頁提供可用功能、實作詳細資料和實用提示總覽。
觸控手勢
您可以使用 Android SDK 啟用 Glass 觸控板的原始資料。方法是透過手勢偵測器來自動偵測玻璃上的常用手勢,例如輕觸、快速滑過和捲動等。
你也可以在應用程式中使用這個手勢偵測工具,為輕觸、向前、向後滑動和向下滑動。這項設定與先前的 Glass 裝置類似。
建議採用下列手勢:
- 輕觸:確認或輸入。
- 向前滑動、向後滑動:瀏覽資訊卡和畫面。
- 向下滑動:返回或結束。
如需實作詳細資料,請參閱手勢偵測器範例。
使用 Android 手勢偵測工具偵測手勢
Android GestureDetector 可讓您偵測簡單和複雜的手勢,例如使用多指或捲動的手勢。
偵測活動層級手勢
僅在使用者介面的哪些部分有焦點時,在活動層級偵測手勢。
舉例來說,如果您想在使用者輕觸觸控板時開啟選單,無論焦點為何,都能在活動中處理 MotionEvent。
以下是活動層級手勢偵測的範例,該範例使用 GestureDetector 並導入 GestureDetector.OnGestureListener 來處理可識別的手勢,然後加以處理並轉譯為以下內容:
TAPSWIPE_FORWARDSWIPE_BACKWARDSWIPE_UPSWIPE_DOWN
Kotlin
class GlassGestureDetector(context: Context, private val onGestureListener: OnGestureListener) :
GestureDetector.OnGestureListener {
private val gestureDetector = GestureDetector(context, this)
enum class Gesture {
TAP,
SWIPE_FORWARD,
SWIPE_BACKWARD,
SWIPE_UP,
SWIPE_DOWN
}
interface OnGestureListener {
fun onGesture(gesture: Gesture): Boolean
}
fun onTouchEvent(motionEvent: MotionEvent): Boolean {
return gestureDetector.onTouchEvent(motionEvent)
}
override fun onDown(e: MotionEvent): Boolean {
return false
}
override fun onShowPress(e: MotionEvent) {}
override fun onSingleTapUp(e: MotionEvent): Boolean {
return onGestureListener.onGesture(Gesture.TAP)
}
override fun onScroll(
e1: MotionEvent,
e2: MotionEvent,
distanceX: Float,
distanceY: Float
): Boolean {
return false
}
override fun onLongPress(e: MotionEvent) {}
/**
* Swipe detection depends on the:
* - movement tan value,
* - movement distance,
* - movement velocity.
*
* To prevent unintentional SWIPE_DOWN and SWIPE_UP gestures, they are detected if movement
* angle is only between 60 and 120 degrees.
* Any other detected swipes, will be considered as SWIPE_FORWARD and SWIPE_BACKWARD, depends
* on deltaX value sign.
*
* ______________________________________________________________
* | \ UP / |
* | \ / |
* | 60 120 |
* | \ / |
* | \ / |
* | BACKWARD <------- 0 ------------ 180 ------> FORWARD |
* | / \ |
* | / \ |
* | 60 120 |
* | / \ |
* | / DOWN \ |
* --------------------------------------------------------------
*/
override fun onFling(
e1: MotionEvent,
e2: MotionEvent,
velocityX: Float,
velocityY: Float
): Boolean {
val deltaX = e2.x - e1.x
val deltaY = e2.y - e1.y
val tan =
if (deltaX != 0f) abs(deltaY / deltaX).toDouble() else java.lang.Double.MAX_VALUE
return if (tan > TAN_60_DEGREES) {
if (abs(deltaY) < SWIPE_DISTANCE_THRESHOLD_PX || Math.abs(velocityY) < SWIPE_VELOCITY_THRESHOLD_PX) {
false
} else if (deltaY < 0) {
onGestureListener.onGesture(Gesture.SWIPE_UP)
} else {
onGestureListener.onGesture(Gesture.SWIPE_DOWN)
}
} else {
if (Math.abs(deltaX) < SWIPE_DISTANCE_THRESHOLD_PX || Math.abs(velocityX) < SWIPE_VELOCITY_THRESHOLD_PX) {
false
} else if (deltaX < 0) {
onGestureListener.onGesture(Gesture.SWIPE_FORWARD)
} else {
onGestureListener.onGesture(Gesture.SWIPE_BACKWARD)
}
}
}
companion object {
private const val SWIPE_DISTANCE_THRESHOLD_PX = 100
private const val SWIPE_VELOCITY_THRESHOLD_PX = 100
private val TAN_60_DEGREES = tan(Math.toRadians(60.0))
}
}
Java
public class GlassGestureDetector implements GestureDetector.OnGestureListener {
enum Gesture {
TAP,
SWIPE_FORWARD,
SWIPE_BACKWARD,
SWIPE_UP,
SWIPE_DOWN,
}
interface OnGestureListener {
boolean onGesture(Gesture gesture);
}
private static final int SWIPE_DISTANCE_THRESHOLD_PX = 100;
private static final int SWIPE_VELOCITY_THRESHOLD_PX = 100;
private static final double TAN_60_DEGREES = Math.tan(Math.toRadians(60));
private GestureDetector gestureDetector;
private OnGestureListener onGestureListener;
public GlassGestureDetector(Context context, OnGestureListener onGestureListener) {
gestureDetector = new GestureDetector(context, this);
this.onGestureListener = onGestureListener;
}
public boolean onTouchEvent(MotionEvent motionEvent) {
return gestureDetector.onTouchEvent(motionEvent);
}
@Override
public boolean onDown(MotionEvent e) {
return false;
}
@Override
public void onShowPress(MotionEvent e) {
}
@Override
public boolean onSingleTapUp(MotionEvent e) {
return onGestureListener.onGesture(Gesture.TAP);
}
@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
return false;
}
@Override
public void onLongPress(MotionEvent e) {
}
/**
* Swipe detection depends on the:
* - movement tan value,
* - movement distance,
* - movement velocity.
*
* To prevent unintentional SWIPE_DOWN and SWIPE_UP gestures, they are detected if movement
* angle is only between 60 and 120 degrees.
* Any other detected swipes, will be considered as SWIPE_FORWARD and SWIPE_BACKWARD, depends
* on deltaX value sign.
*
* ______________________________________________________________
* | \ UP / |
* | \ / |
* | 60 120 |
* | \ / |
* | \ / |
* | BACKWARD <------- 0 ------------ 180 ------> FORWARD |
* | / \ |
* | / \ |
* | 60 120 |
* | / \ |
* | / DOWN \ |
* --------------------------------------------------------------
*/
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
final float deltaX = e2.getX() - e1.getX();
final float deltaY = e2.getY() - e1.getY();
final double tan = deltaX != 0 ? Math.abs(deltaY/deltaX) : Double.MAX_VALUE;
if (tan > TAN_60_DEGREES) {
if (Math.abs(deltaY) < SWIPE_DISTANCE_THRESHOLD_PX || Math.abs(velocityY) < SWIPE_VELOCITY_THRESHOLD_PX) {
return false;
} else if (deltaY < 0) {
return onGestureListener.onGesture(Gesture.SWIPE_UP);
} else {
return onGestureListener.onGesture(Gesture.SWIPE_DOWN);
}
} else {
if (Math.abs(deltaX) < SWIPE_DISTANCE_THRESHOLD_PX || Math.abs(velocityX) < SWIPE_VELOCITY_THRESHOLD_PX) {
return false;
} else if (deltaX < 0) {
return onGestureListener.onGesture(Gesture.SWIPE_FORWARD);
} else {
return onGestureListener.onGesture(Gesture.SWIPE_BACKWARD);
}
}
}
}
用法示範
如要使用活動層級手勢偵測,您必須完成下列工作:
- 請在應用程式宣告內將以下宣告加入資訊清單檔案。這可讓應用程式在活動中接收
MotionEvent:<application> <!-- Copy below declaration into your manifest file --> <meta-data android:name="com.google.android.glass.TouchEnabledApplication" android:value="true" /> </application>
- 覆寫活動的
dispatchTouchEvent(motionEvent)方法,將動作事件傳送至手勢偵測工具onTouchEvent(motionEvent)方法。 - 在活動中導入
GlassGestureDetector.OnGestureListener。
以下是活動層級手勢偵測工具的範例:
Kotlin
class MainAcvitiy : AppCompatActivity(), GlassGestureDetector.OnGestureListener {
private lateinit var glassGestureDetector: GlassGestureDetector
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
glassGestureDetector = GlassGestureDetector(this, this)
}
override fun onGesture(gesture: GlassGestureDetector.Gesture): Boolean {
when (gesture) {
TAP ->
// Response for TAP gesture
return true
SWIPE_FORWARD ->
// Response for SWIPE_FORWARD gesture
return true
SWIPE_BACKWARD ->
// Response for SWIPE_BACKWARD gesture
return true
else -> return false
}
}
override fun dispatchTouchEvent(ev: MotionEvent): Boolean {
return if (glassGestureDetector.onTouchEvent(ev)) {
true
} else super.dispatchTouchEvent(ev)
}
}
Java
public class MainActivity extends AppCompatActivity implements OnGestureListener {
private GlassGestureDetector glassGestureDetector;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
glassGestureDetector = new GlassGestureDetector(this, this);
}
@Override
public boolean onGesture(Gesture gesture) {
switch (gesture) {
case TAP:
// Response for TAP gesture
return true;
case SWIPE_FORWARD:
// Response for SWIPE_FORWARD gesture
return true;
case SWIPE_BACKWARD:
// Response for SWIPE_BACKWARD gesture
return true;
default:
return false;
}
}
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
if (glassGestureDetector.onTouchEvent(ev)) {
return true;
}
return super.dispatchTouchEvent(ev);
}
}
音訊輸入
Glass Enterprise Edition 2 是支援 Android 開放原始碼計畫的標準裝置,支援基本音訊來源。
以下音訊來源已導入進階信號處理功能:
語音辨識
Glass Enterprise Edition 2 支援原生語音辨識功能。目前僅支援英文。
語音辨識使用者介面會等待使用者說話,並在完成後傳回轉錄的文字。如要開始活動,請按照下列步驟操作:
- 使用
ACTION_RECOGNIZE_SPEECH意圖呼叫startActivityForResult()。啟動活動時,系統會支援下列意圖額外項目: - 覆寫
onActivityResult()回呼,以便從EXTRA_RESULTS意圖額外呼叫的轉錄文字,如以下程式碼範例所示。使用者完成說話時,系統會呼叫這個回呼。
Kotlin
private const val SPEECH_REQUEST = 109
private fun displaySpeechRecognizer() {
val intent = Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH)
startActivityForResult(intent, SPEECH_REQUEST)
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent) {
if (requestCode == SPEECH_REQUEST && resultCode == RESULT_OK) {
val results: List<String>? =
data.getStringArrayListExtra(RecognizerIntent.EXTRA_RESULTS)
val spokenText = results?.get(0)
// Do something with spokenText.
}
super.onActivityResult(requestCode, resultCode, data)
}
Java
private static final int SPEECH_REQUEST = 109;
private void displaySpeechRecognizer() {
Intent intent = new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH);
startActivityForResult(intent, SPEECH_REQUEST);
}
@Override
protected void onActivityResult(int requestCode, int resultCode,
Intent data) {
if (requestCode == SPEECH_REQUEST && resultCode == RESULT_OK) {
List<String> results = data.getStringArrayListExtra(
RecognizerIntent.EXTRA_RESULTS);
String spokenText = results.get(0);
// Do something with spokenText.
}
super.onActivityResult(requestCode, resultCode, data);
}
如需實作詳細資料,請參閱聲音辨識應用程式範例。
關鍵字偏誤
Google 玻璃的語音辨識功能可能會偏向關鍵字清單。偏誤會提高關鍵字辨識的準確度。如要啟用關鍵字偏誤,請使用下列指令:
Kotlin
val keywords = arrayOf("Example", "Biasing", "Keywords")
val intent = Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH)
intent.putExtra("recognition-phrases", keywords)
startActivityForResult(intent, SPEECH_REQUEST)
Java
final String[] keywords = {"Example", "Biasing", "Keywords"};
Intent intent = new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH);
intent.putExtra("recognition-phrases", keywords);
startActivityForResult(intent, SPEECH_REQUEST);
語音指令
使用者可透過語音指令執行活動相關動作。您可使用標準 Android 選單 API 建構語音指令,但使用者可以透過語音指令 (而非觸控) 叫用選單項目。
如要啟用特定活動的語音指令,請按照下列步驟操作:
- 透過所需活動呼叫
getWindow().requestFeature(FEATURE_VOICE_COMMANDS),即可啟用語音指令。啟用這項功能後,每當該活動獲得焦點時,螢幕左下角就會顯示麥克風圖示。 - 在應用程式中要求
RECORD_AUDIO權限。 - 覆寫
onCreatePanelMenu()並加載選單資源。 - 覆寫
onContextItemSelected()來處理偵測到的語音指令。
Kotlin
class VoiceCommandsActivity : AppCompatActivity() {
companion object {
const val FEATURE_VOICE_COMMANDS = 14
const val REQUEST_PERMISSION_CODE = 200
val PERMISSIONS = arrayOf(Manifest.permission.RECORD_AUDIO)
val TAG = VoiceCommandsActivity::class.java.simpleName
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
window.requestFeature(FEATURE_VOICE_COMMANDS)
setContentView(R.layout.activity_voice_commands)
// Requesting permissions to enable voice commands menu
ActivityCompat.requestPermissions(
this,
PERMISSIONS,
REQUEST_PERMISSION_CODE
)
}
override fun onRequestPermissionsResult(
requestCode: Int,
permissions: Array<out String>,
grantResults: IntArray
) {
if (requestCode == REQUEST_PERMISSION_CODE) {
for (result in grantResults) {
if (result != PackageManager.PERMISSION_GRANTED) {
Log.d(TAG, "Permission denied. Voice commands menu is disabled.")
}
}
} else {
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
}
}
override fun onCreatePanelMenu(featureId: Int, menu: Menu): Boolean {
menuInflater.inflate(R.menu.voice_commands_menu, menu)
return true
}
override fun onContextItemSelected(item: MenuItem): Boolean {
return when (item.itemId) {
// Handle selected menu item
R.id.edit -> {
// Handle edit action
true
}
else -> super.onContextItemSelected(item)
}
}
}
Java
public class VoiceCommandsActivity extends AppCompatActivity {
private static final String TAG = VoiceCommandsActivity.class.getSimpleName();
private static final int FEATURE_VOICE_COMMANDS = 14;
private static final int REQUEST_PERMISSION_CODE = 200;
private static final String[] PERMISSIONS = new String[]{Manifest.permission.RECORD_AUDIO};
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getWindow().requestFeature(FEATURE_VOICE_COMMANDS);
setContentView(R.layout.activity_voice_commands);
// Requesting permissions to enable voice commands menu
ActivityCompat.requestPermissions(this, PERMISSIONS, REQUEST_PERMISSION_CODE);
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
if (requestCode == REQUEST_PERMISSION_CODE) {
for (int result : grantResults) {
if (result != PackageManager.PERMISSION_GRANTED) {
Log.d(TAG, "Permission denied. Voice commands menu is disabled.");
}
}
} else {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
}
}
@Override
public boolean onCreatePanelMenu(int featureId, @NonNull Menu menu) {
getMenuInflater().inflate(R.menu.voice_commands_menu, menu);
return true;
}
@Override
public boolean onContextItemSelected(@NonNull MenuItem item) {
switch (item.getItemId()) {
// Handle selected menu item
case R.id.edit:
// Handle edit action
return true;
default:
return super.onContextItemSelected(item);
}
}
}
以下是先前的活動使用的選單資源範例:
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="@+id/delete"
android:icon="@drawable/ic_delete"
android:title="@string/delete"/>
<item
android:id="@+id/edit"
android:icon="@drawable/ic_edit"
android:title="@string/edit"/>
<item
android:id="@+id/find"
android:icon="@drawable/ic_search"
android:title="@string/find"/>
</menu>
如需完整範例,請參閱筆記筆記應用程式。
語音指令清單重新載入
可以動態重新載入語音指令清單。如要這麼做,請替換 onCreatePanelMenu() 方法中的 menu 資源,或是修改 onPreparePanel() 方法中的選單物件。如要套用變更,請呼叫 invalidateOptionsMenu() 方法。
Kotlin
private val options = mutableListOf<String>()
fun onPreparePanel(featureId: Int, view: View?, menu: Menu): Boolean {
if (featureId != FEATURE_VOICE_COMMANDS) {
return super.onCreatePanelMenu(featureId, menu)
}
for (optionTitle in options) {
menu.add(optionTitle)
}
return true
}
/**
* Method showing example implementation of voice command list modification
*
* If you call [Activity.invalidateOptionsMenu] method, voice command list will be
* reloaded (onCreatePanelMenu and onPreparePanel methods will be called).
*/
private fun modifyVoiceCommandList() {
options.add("Delete")
options.add("Play")
options.add("Pause")
invalidateOptionsMenu()
}
Java
private final List<String> options = new ArrayList<>();
@Override
public boolean onPreparePanel(int featureId, View view, Menu menu) {
if (featureId != FEATURE_VOICE_COMMANDS) {
return super.onCreatePanelMenu(featureId, menu);
}
for (String optionTitle : options) {
menu.add(optionTitle);
}
return true;
}
/**
* Method showing example implementation of voice command list modification
*
* If you call {@link Activity#invalidateOptionsMenu()} method, voice command list will be
* reloaded (onCreatePanelMenu and onPreparePanel methods will be called).
*/
private void modifyVoiceCommandList() {
options.add("Delete");
options.add("Play");
options.add("Pause");
invalidateOptionsMenu();
}
AppCompatActivity 解決方案
如要在擴充 AppCompatActivity 的活動中重新載入語音指令清單,請使用 sendBroadcast() 方法搭配 reload-voice-commands 意圖動作:
Kotlin
sendBroadcast(Intent("reload-voice-commands"))
Java
sendBroadcast(new Intent("reload-voice-commands"));
在執行階段啟用及停用語音指令
您可以在執行階段啟用或停用語音指令。方法是從 onCreatePanelMenu() 方法傳回適當的值,如下所示:
- 如要啟用,請將值設為
true。 - 如要停用,請將值設為
false。
偵錯模式
如要啟用語音指令的偵錯模式,請在所需活動中呼叫 getWindow().requestFeature(FEATURE_DEBUG_VOICE_COMMANDS)。偵錯模式會啟用下列功能:
- Logcat 包含可識別偵錯的記錄檔記錄。
- 偵測到無法辨識的指令時,會顯示使用者介面疊加層,如下所示:
Kotlin
class VoiceCommandsActivity : AppCompatActivity() {
companion object {
const val FEATURE_VOICE_COMMANDS = 14
const val FEATURE_DEBUG_VOICE_COMMANDS = 15
const val REQUEST_PERMISSION_CODE = 200
val PERMISSIONS = arrayOf(Manifest.permission.RECORD_AUDIO)
val TAG = VoiceCommandsActivity::class.java.simpleName
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
window.requestFeature(FEATURE_VOICE_COMMANDS)
window.requestFeature(FEATURE_DEBUG_VOICE_COMMANDS)
setContentView(R.layout.activity_voice_commands)
// Requesting permissions to enable voice commands menu
ActivityCompat.requestPermissions(
this,
PERMISSIONS,
REQUEST_PERMISSION_CODE
)
}
.
.
.
}
Java
public class VoiceCommandsActivity extends AppCompatActivity {
private static final String TAG = VoiceCommandsActivity.class.getSimpleName();
private static final int FEATURE_VOICE_COMMANDS = 14;
private static final int FEATURE_DEBUG_VOICE_COMMANDS = 15;
private static final int REQUEST_PERMISSION_CODE = 200;
private static final String[] PERMISSIONS = new String[]{Manifest.permission.RECORD_AUDIO};
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getWindow().requestFeature(FEATURE_VOICE_COMMANDS);
getWindow().requestFeature(FEATURE_DEBUG_VOICE_COMMANDS);
setContentView(R.layout.activity_voice_commands);
// Requesting permissions to enable voice commands menu
ActivityCompat.requestPermissions(this, PERMISSIONS, REQUEST_PERMISSION_CODE);
}
.
.
.
}
如需實作詳細資料,請參閱重新載入應用程式的範例指令。
文字轉語音 (TTS)
文字轉語音功能會將數位文字轉換成合成語音輸出。詳情請參閱Android 開發人員文件 TextToSpeech。
Glass EE2 已安裝 Google Text-to-Speech 引擎。已設為預設的 TTS 引擎,且可離線使用。
Google 文字轉語音語言套件隨附下列語言代碼:
|
孟加拉文 中文 捷克文 丹麥文 德文 希臘文 英文 西班牙文 愛沙尼亞 芬蘭文 法文 古吉拉特 北印度文 |
匈牙利文 印尼文 義大利文 日語 Javanese Austronesian Austroasiatic Kannada 韓文 馬拉雅拉姆 挪威文 荷蘭文 |
波蘭文 葡萄牙文 俄文 斯洛伐克 巽他文 瑞典文 泰米爾文 泰盧固文 泰文 土耳其文 烏克蘭文 越南文 |
相機
Glass Enterprise Edition 2 配備 800 萬像素的固定對焦鏡頭,具備 f/2.4 光圈、4:3 感應器長寬比、83° 對角線視野 (橫向 71° x 57°)。建議您使用標準的 CameraX 或 Camera2 API。
如需實作詳細資料,請參閱相機應用程式範例。
相機按鈕
相機按鈕是 Glass Enterprise Edition 2 裝置轉軸上的實體按鈕。您可以以標準鍵盤動作的形式處理,並以 KeyEvent#KEYCODE_CAMERA 按鍵碼識別。
在 OPM1.200313.001 OS 更新中,系統會透過啟動器應用程式傳送下列動作的意圖:
- 相機按鈕按
MediaStore#ACTION_IMAGE_CAPTURE。 - 長按相機按鈕的
MediaStore#ACTION_VIDEO_CAPTURE。
感應器
開發人員在 Glass EE2 中開發應用程式時,可以使用多種感應器。
Glass 支援下列標準 Android 感應器:
-
TYPE_ACCELEROMETER -
TYPE_GRAVITY -
TYPE_GYROSCOPE -
TYPE_LIGHT -
TYPE_LINEAR_ACCELERATION -
TYPE_MAGNETIC_FIELD TYPE_ORIENTATION(已淘汰)-
TYPE_ROTATION_VECTOR
Glass 不支援下列 Android 感應器:
下圖為 Glass 感應器座標系統。相對於玻璃螢幕。詳情請參閱感應器座標系統一文。
加速計、陀螺儀和磁力儀位於 Glass 裝置的光學 Pod 上,使用者會輪流將裝置對準自己的視線。您無法直接測量光學 Pod 的角度,因此在使用這些應用程式的角度 (例如指南針方向) 時,請注意這一點。
為了節省電池續航力,請僅在有需要時監聽感應器。決定感應器何時要停止及停止監聽感應器時,請考慮應用程式的需求和生命週期。
感應器事件回呼會在 UI 執行緒上執行,因此請盡快處理事件並盡快傳回。如果處理時間過長,請將感應器事件推送到佇列中,並使用背景執行緒來處理。
50 Hz 通常是足夠的取樣率,可追蹤頭部動作。
如要進一步瞭解如何使用感應器,請參閱 Android 開發人員指南。
定位服務
Glass Enterprise Edition 2 裝置未配備 GPS 模組,但並未提供使用者的位置。但它實作了定位服務,以顯示附近的 Wi-Fi 網路和藍牙裝置。
如果您的應用程式有裝置擁有者權限,即可以程式輔助的方式變更對應安全設定的值:
Kotlin
val devicePolicyManager = context
.getSystemService(Context.DEVICE_POLICY_SERVICE) as DevicePolicyManager
if (devicePolicyManager.isDeviceOwnerApp(context.getPackageName())) {
val componentName = ComponentName(context, MyDeviceAdmin::class.java)
devicePolicyManager.setSecureSetting(
componentName,
Settings.Secure.LOCATION_MODE,
Settings.Secure.LOCATION_MODE_SENSORS_ONLY.toString()
)
}
Java
final DevicePolicyManager devicePolicyManager = (DevicePolicyManager) context
.getSystemService(Context.DEVICE_POLICY_SERVICE);
if (devicePolicyManager.isDeviceOwnerApp(context.getPackageName())) {
final ComponentName componentName = new ComponentName(context, MyDeviceAdmin.class);
devicePolicyManager.setSecureSetting(componentName, Settings.Secure.LOCATION_MODE,
String.valueOf(Settings.Secure.LOCATION_MODE_SENSORS_ONLY));
}
如果您使用第三方行動裝置管理 (MDM) 解決方案,則行動裝置管理 (MDM) 解決方案必須能夠為您變更這些設定。