入力とセンサー

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);
       }
     }
   }
  }

使用例

アクティビティ レベルのジェスチャー検出を利用するには、次のタスクを完了する必要があります。

  1. マニフェスト ファイルのアプリケーション宣言内に次の宣言を追加します。これにより、アプリはアクティビティで MotionEvent を受け取ることができます。
    <application>
    <!-- Copy below declaration into your manifest file -->
    <meta-data
      android:name="com.google.android.glass.TouchEnabledApplication"
      android:value="true" />
    </application>
  2. アクティビティの dispatchTouchEvent(motionEvent) メソッドをオーバーライドして、モーション イベントをジェスチャー検出器の onTouchEvent(motionEvent) メソッドに渡します。
  3. アクティビティに 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 は、音声認識のネイティブ実装をサポートしています。この機能は英語でのみサポートされています。

Google Glass の音声認識の画像。

音声認識 UI は、ユーザーが話すのを待ってから、話し終わると文字起こしされたテキストを返します。アクティビティを開始する手順は次のとおりです。

  1. ACTION_RECOGNIZE_SPEECH インテントを使用して startActivityForResult() を呼び出します。アクティビティの開始時に、次のインテント エクストラがサポートされます。
  2. 次のコードサンプルに示すように、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 で作成しますが、ユーザーはタッチの代わりに音声コマンドでメニュー項目を呼び出すことができます。

特定のアクティビティで音声コマンドを有効にする手順は次のとおりです。

  1. 目的のアクティビティで getWindow().requestFeature(FEATURE_VOICE_COMMANDS) を呼び出して、音声コマンドを有効にします。この機能を有効にすると、このアクティビティがフォーカスを受け取るたびに、画面の左下にマイクアイコンが表示されます。
  2. アプリで RECORD_AUDIO 権限をリクエストします。
  3. onCreatePanelMenu() をオーバーライドして、メニュー リソースをインフレートします。
  4. 検出された音声コマンドを処理するには、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 オーバーレイが表示されます。
  • Glass の音声認識でコマンドが認識されなかった場合の画像。

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 アップデート以降、次のアクションを含むインテントがランチャー アプリケーションから送信されます。

センサー

Glass EE2 でアプリケーションを開発する際に、デベロッパーが利用できるセンサーは多岐にわたります。

Glass では、次の標準の Android センサーがサポートされています。

Glass では次の Android センサーはサポートされていません。

Google Glass のセンサー座標系を次の図に示します。Glass ディスプレイを基準としています。詳細については、 センサーの座標系をご覧ください。

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 ソリューションでこれらの設定を変更できる必要があります。