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()を呼び出します。アクティビティの開始時に、次のインテント エクストラがサポートされます。- 次のコードサンプルに示すように、
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 Developers Documentation TextToSpeech をご覧ください。
Glass EE2 には Google テキスト読み上げエンジンがインストールされています。デフォルトの TTS エンジンとして設定され、オフラインで動作します。
Google テキスト読み上げエンジンには、次のロケールがバンドルされています。
|
ベンガル語 標準中国語 チェコ語 デンマーク語 ドイツ語 ギリシャ語 英語 スペイン語 エストニア語 フィンランド語 フランス語 グジャラート語 ヒンディー語 |
ハンガリー語 インドネシア語 イタリア語 日本語 ジャワ語 オーストロネシア語 オーストロアジア語 カンナダ語 韓国語 マラヤーラム語 ノルウェー語 オランダ語 |
ポーランド語 ポルトガル語 ロシア語 スロバキア語 スンダ語 スウェーデン語 タミル語 テルグ語 タイ語 トルコ語 ウクライナ語 ベトナム語 |
カメラ
Glass Enterprise Edition 2 には、8 メガピクセルの固定フォーカス カメラが搭載されています。このカメラは、絞り値 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 センサーはサポートされていません。
Google Glass のセンサー座標系を次の図に示します。Glass ディスプレイを基準としています。詳細については、 センサーの座標系をご覧ください。
加速度計、ジャイロスコープ、磁力計は、Glass デバイスの光学ポッドに内蔵されています。ユーザーは、この光学ポッドを回転させてデバイスを視線に合わせます。光学ポッドの角度を直接測定することはできません。そのため、コンパスの向きなどのアプリケーションでこれらのセンサーの角度を使用する場合は、この点に注意してください。
バッテリーの消耗を抑えるため、センサーは必要なときにのみ使用します。センサーのリスニングを開始および停止するタイミングを決定する際は、アプリのニーズとライフサイクルを考慮してください。
センサー イベント コールバックは UI スレッドで実行されるため、イベントをできるだけ早く処理して返します。処理に時間がかかりすぎる場合は、センサー イベントをキューにプッシュし、バックグラウンド スレッドを使用して処理します。
50 Hz は、頭の動きを追跡するのに十分なサンプリング レートであることがよくあります。
センサーの使用方法について詳しくは、 Android デベロッパー ガイドをご覧ください。
位置情報サービス
Google 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 ソリューションでこれらの設定を変更できる必要があります。