Android SDK では、Glass EE2 で利用可能なさまざまな入力とセンサーにアクセスできます。このページでは、利用可能な機能の概要、実装の詳細、有用なヒントを紹介します。
タップ操作
Android SDK を使用して、Glass タッチパッドの元データへのアクセスを有効にできます。これは、Glass での一般的なタップ、フリング、スクロールなどのジェスチャーを自動的に検出するジェスチャー検出器を使用して実現されます。
このジェスチャー検出器をアプリで使用して、タップ、前方にスワイプ、下にスワイプ、下にスワイプ、下にスワイプすることもできます。これは以前の Glass デバイスに類似しています。
これらのジェスチャーは、次のように使用することをおすすめします。
- タップ: 確定または入力します。
- 前方にスワイプ、後方にスワイプ: カードや画面間を移動
- 下にスワイプ: 戻るまたは終了します。
実装の詳細については、サンプル ジェスチャー検出器をご覧ください。
Android ジェスチャー検出器を使用してジェスチャーを検出する
Android GestureDetector
を使用すると、複数の指やスクロールを使用するジェスチャーなど、シンプルで複雑なジェスチャーを検出できます。
アクティビティ レベルのジェスチャーを検出する
UI のどの部分にフォーカスされているのかに関係なく、アクティビティ レベルでジェスチャーを検出する。
たとえば、ユーザーがタッチパッドをタップしたときにメニューを表示するには、どのビューにフォーカスがあるかにかかわらず、アクティビティ内で MotionEvent
を処理します。
以下は、GestureDetector
を使用し、GestureDetector.OnGestureListener
を実装して認識されたジェスチャーを処理する、アクティビティ レベルのジェスチャー検出の例です。これらは処理されて次のように変換されます。
TAP
SWIPE_FORWARD
SWIPE_BACKWARD
SWIPE_UP
SWIPE_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()
を呼び出します。アクティビティを開始する際に、次のインテント エクストラがサポートされます。- 次のコードサンプルに示すように、
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
を拡張するアクティビティの音声コマンドリストを再読み込みするには、reload-voice-commands
インテント アクションで sendBroadcast()
メソッドを使用します。
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)
Text-to-Speech 機能は、デジタル テキストを合成音声出力に変換します。詳細については、Android デベロッパー ドキュメント TextToSpeech をご覧ください。
Glass EE2 には、Google Text-to-Speech エンジンがインストールされています。デフォルトの TTS エンジンとして設定されており、オフラインで使用できます。
Google テキスト読み上げエンジンには、次のロケールがバンドルされています。
ベンガル語 北京語 チェコ語 デンマーク語 ドイツ語 ギリシャ語 英語 スペイン語 エストニア語 フィンランド語 フランス語 グジャラト語 ヒンディー語 |
ハンガリー語 インドネシア語 イタリア語 日本語 ジャワ語 オーストリア オーストラリア カンナダ語 韓国語 マラヤーラム語 ノルウェー語 オランダ語 |
ポーランド語 ポルトガル語 ロシア語 スロバキア スンダ語 スウェーデン語 タミル語 テルグ語 タイ語 トルコ語 ウクライナ語 ベトナム語 |
カメラ
Glass Enterprise Edition 2 には、絞り値 f/2.4、センサーのアスペクト比 4:3、対角画角 83°(横向き 71° x 57°)の 8 メガピクセルの固定フォーカス カメラが搭載されています。 標準の 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
以下の Android センサーは Glass でサポートされていません。
次の図に、Glass センサー座標系を示します。Glass ディスプレイからの相対距離です。詳しくは、センサー座標系をご覧ください。
加速度計、ジャイロスコープ、磁力計は、Glass デバイスの光学ユニット上に配置され、ユーザーが視野に合わせてデバイスを回転させます。光学ポッドの角度を直接測定することはできません。これらのセンサーからの角度をコンパス方位などで使用する場合は、この点に注意する必要があります。
バッテリーを長持ちさせるため、必要なときのみセンサーに耳を傾けてください。センサーの監視を開始および停止するタイミングを決定する際には、アプリのニーズとライフサイクルを考慮してください。
センサー イベントのコールバックは UI スレッド上で実行されるため、イベントを処理してできるだけ早く返します。処理に時間がかかりすぎる場合は、センサー イベントをキューに push し、バックグラウンド スレッドを使用して処理します。
多くの場合、50 Hz は、ヘッド モーションをトラッキングするのに十分なサンプリング レートです。
センサーの使用方法の詳細については、Android デベロッパー ガイドをご覧ください。
位置情報サービス
Glass Enterprise Edition 2 デバイスには GPS モジュールが装備されておらず、ユーザーの位置情報が提供されません。ただし、位置情報サービスが実装されています。これは、付近の Wi-Fi ネットワークと Bluetooth デバイスのリストを表示するために必要です。
アプリにデバイス所有者の権限がある場合、それを使用して、対応する安全な設定の値をプログラムで変更できます。
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 ソリューションでこれらの設定を変更できる必要があります。