Android SDK 可讓您存取 Glass EE2 提供的各種輸入和感應器。本頁面將概略介紹可用功能、實作詳細資料和實用提示。
觸控手勢
您可以使用 Android SDK 啟用 Glass 觸控板的原始資料存取權。這項功能是透過手勢偵測器達成,可自動偵測 Glass 上的常見手勢,例如輕觸、撥動和捲動。
您也可以在應用程式中使用這個手勢偵測器,處理輕觸、向前滑動、向後滑動和向下滑動手勢。這與先前的 Glass 裝置類似。
建議您按照下列方式使用這些手勢:
- 輕觸:確認或輸入。
- 向前滑動、向後滑動:瀏覽資訊卡和畫面。
- 向下滑動:返回或退出。
如要瞭解實作詳情,請參閱手勢偵測器範例。
使用 Android 手勢偵測器偵測手勢
Android GestureDetector 可偵測簡單和複雜的手勢,例如使用多指或捲動的手勢。
偵測活動層級手勢
只有在 UI 的哪個部分有焦點並不重要時,才在活動層級偵測手勢。
舉例來說,如果想在使用者輕觸觸控板時顯示選單 (不論焦點位於哪個檢視區塊),請在活動內處理 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 是以標準 AOSP 為基礎的裝置,支援基本音訊來源。
下列音訊來源已導入進階信號處理功能:
語音辨識
Glass Enterprise Edition 2 支援語音辨識的原生實作方式。這項功能僅支援英文。
語音辨識 UI 會等待使用者說話,然後在使用者說完後傳回轉錄文字。如要開始活動,請按照下列步驟操作:
- 使用
ACTION_RECOGNIZE_SPEECH意圖呼叫startActivityForResult()。啟動活動時,系統支援下列意圖 Extras: - 覆寫
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); }
如要瞭解實作方式,請參閱語音辨識應用程式範例。
關鍵字偏誤
Glass 的語音辨識功能可能會偏向關鍵字清單。偏向設定可提高關鍵字辨識準確度。如要啟用關鍵字偏誤,請使用下列項目:
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 包含含有辨識片語的記錄,可用於偵錯。
- 偵測到無法辨識的指令時,系統會顯示 UI 疊加畫面,如下所示:
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 文字轉語音引擎。系統會將這個引擎設為預設 TTS 引擎,且支援離線運作。
Google 文字轉語音引擎會隨附下列語言代碼:
|
孟加拉文 中文 捷克文 丹麥文 德文 希臘文 英文 西班牙文 愛沙尼亞文 芬蘭文 法文 古吉拉特文 北印度文 |
匈牙利文 印尼文 義大利文 日文 爪哇文 南島語 南亞語 卡納達文 韓文 馬拉雅拉姆文 挪威文 荷蘭文 |
波蘭文 葡萄牙文 俄文 斯洛伐克文 巽他文 瑞典文 泰米爾文 泰盧固文 泰文 土耳其文 烏克蘭文 越南文 |
相機
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 感應器的座標系統。這是相對於 Google Glass 螢幕的位置。詳情請參閱「 感應器座標系統」。
加速計、陀螺儀和磁力計位於 Glass 裝置的光學元件上,使用者會旋轉光學元件,將裝置對準視線。您無法直接測量光學攝影機的角度,因此使用這些感應器的角度進行應用程式 (例如羅盤方位) 時,請注意這點。
為延長電池續航力,請只在需要時監聽感應器。決定何時開始和停止監聽感應器時,請考量應用程式的需求和生命週期。
感應器事件回呼會在 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 解決方案,該解決方案必須能夠為您變更這些設定。