オーディオ グラスとディスプレイ グラスのハードウェア権限をリクエストする

対象の XR デバイス
このガイダンスは、次のようなタイプの XR デバイス向けのエクスペリエンスを構築する際に役立ちます。
オーディオと
ディスプレイ メガネ

スマートフォンと同様に、オーディオ グラスやディスプレイ グラスのカメラやマイクなどの機密性の高いハードウェアにアクセスするには、ユーザーの明示的な同意が必要です。これらはメガネ固有の権限と見なされ、アプリがスマートフォンで対応する権限をすでに持っている場合でも、実行時にリクエストする必要があります。

アプリのマニフェストで権限を宣言する

権限をリクエストする前に、<uses-permission> 要素を使用して、アプリのマニフェスト ファイルで権限を宣言する必要があります。この宣言は、権限がスマートフォン固有の機能かグラス固有の機能かに関係なく同じですが、グラス固有のハードウェアまたは機能に対しては明示的にリクエストする必要があります。

<manifest ...>
    <!-- Only declare permissions that your app actually needs. In this example,
    we declare permissions for the camera. -->
    <uses-permission android:name="android.permission.CAMERA"/>
    <application ...>
        ...
    </application>
</manifest>

メガネの権限をリクエストする前に

権限の原則とワークフローを確認して、ユーザーに最適なエクスペリエンスを提供できるようにします。たとえば、アプリが必要とする実行時の権限をユーザーがすでに付与しているかどうかを確認したり、メガネ固有の権限をリクエストする前にアプリがユーザーに根拠を示す必要があるかどうかを確認したりします。

パーミッション シナリオ

オーディオ グラスやディスプレイ グラスで危険なランタイム権限をリクエストするシナリオとして、次のようないくつかの場合があります。

  • プロジェクションされたアクティビティから実行時の権限をリクエストする
  • 電話アクティビティから実行時の権限をリクエストする

各シナリオの詳細については、このガイドの以降のセクションをご覧ください。

投影されたアクティビティから実行時の権限をリクエストして処理する

オーディオ グラスとディスプレイ グラスの権限をリクエストするには、まず ProjectedPermissionsResultContract メソッドで ActivityResultLauncher を使用して、権限ランチャーを登録します。ユーザーが権限のリクエストに応答すると、コールバックは権限名とその付与ステータスのマップを受け取ります。

// Register the permissions launcher using the ProjectedPermissionsResultContract.
private val requestPermissionLauncher: ActivityResultLauncher<List<ProjectedPermissionsRequestParams>> =
    registerForActivityResult(ProjectedPermissionsResultContract()) { results ->
        if (results[Manifest.permission.CAMERA] == true) {
            isPermissionDenied = false
            initializeGlassesFeatures()
        } else {
            // Handle permission denial.
            isPermissionDenied = true
        }
    }

コードに関する主なポイント

  • アプリに必要な権限(Manifest.permission.CAMERAManifest.permission.RECORD_AUDIO など)を指定する必要があります。
  • アプリは、ランチャーのコールバックで、許可された結果と拒否された結果の両方を適切に処理する必要があります。

権限のリクエスト フローをトリガーするには、登録済みの権限ランチャーの launch メソッドに ProjectedPermissionsRequestParams のリストを渡します。ProjectedPermissionsRequestParams オブジェクトは、リクエストされたマニフェスト権限をカスタム rationale 文字列とともにバンドルします。rationale 文字列では、アプリがメガネのハードウェア機能(カメラやマイクなど)へのアクセスを必要とする理由を明確かつ簡潔に説明する必要があります。

private fun requestHardwarePermissions() {
    val params = ProjectedPermissionsRequestParams(
        permissions = listOf(Manifest.permission.CAMERA),
        rationale = "Camera access is required to overlay digital content on your physical environment."
    )
    requestPermissionLauncher.launch(listOf(params))
}

コードに関する主なポイント

権限のリクエストのユーザーフローを理解する

ProjectedPermissionsResultContract メソッドを使用して権限のリクエストを開始すると、システムはメガネとスマートフォンの両方で連携したユーザーフローを開始します。

権限のユーザーフローでは、アプリとユーザーは次のことを想定できます。

  1. メガネ: 投影されたデバイス(メガネ)にアクティビティが表示され、続行するにはスマートフォンを見るようユーザーに指示します。

  2. スマートフォン: 同時に、ホストデバイス(スマートフォン)でアクティビティが起動します。この画面には、指定した理由文字列が表示され、ユーザーは続行またはキャンセルを選択できます。

  3. スマートフォン: ユーザーが理由を受け入れると、スマートフォンに Android システムの権限ダイアログが変更されて表示され、スマートフォンではなくメガネに権限を付与していることがユーザーに伝えられます。ユーザーは正式に権限を付与または拒否できます。

  4. 結果の受信: ユーザーが最終的な選択を行うと、スマートフォンとスマートグラスの両方のアクティビティが閉じられます。次に、リクエストされた各権限の付与ステータスを含むマップを使用して ActivityResultLauncher コールバックが呼び出されます。

スマートフォン アクティビティで実行時の権限をリクエストする

アプリがスマートフォンのアクティビティで実行されていて、音声やディスプレイ グラスの権限を必要とする場合(たとえば、ユーザーが動画ストリームをグラスのカメラに切り替えて一人称視点にする場合など)は、デバイス固有の Activity#requestPermissions(permissions, requestCode, deviceId) メソッドを使用して権限をリクエストします。

オーディオ グラスとディスプレイ グラスをターゲットにするには、プロジェクション デバイス コンテキストで getDeviceId を呼び出して、適切なデバイス ID を取得します。次の例に示すように、スマートフォンのアクティビティから権限をリクエストするときに、この ID を渡します。

// Request the projected permission from phone activity
requestPermissions(
    arrayOf(Manifest.permission.CAMERA),
    // REQUEST_CODE_GLASSES_CAMERA is a developer-defined constant
    REQUEST_CODE_GLASSES_CAMERA,
    projectedDeviceId
)

権限の結果を処理する

ユーザーがスマートフォンで権限ダイアログに応答すると、onRequestPermissionsResult コールバックが呼び出され、その決定がアプリに渡されます。

レスポンスを処理するには、パーミッション リクエストを開始した Activity インスタンス内の onRequestPermissionsResult をオーバーライドします。

次のコード スニペットは、コールバックを処理し、ユーザーがリクエストされた権限を付与したかどうかを確認する方法を示しています。

private companion object {
    // REQUEST_CODE_GLASSES_CAMERA is a developer-defined constant.
    const val REQUEST_CODE_GLASSES_CAMERA = 1001
}

@RequiresApi(Build.VERSION_CODES.VANILLA_ICE_CREAM)
override fun onRequestPermissionsResult(
    requestCode: Int,
    permissions: Array<out String>,
    grantResults: IntArray,
    deviceId: Int
) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults, deviceId)

    // Handle the result of the permission request
    if (requestCode == REQUEST_CODE_GLASSES_CAMERA && deviceId == projectedDeviceId) {
        if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
            // Proceed with glasses camera features
        } else {
            // Handle glasses permission denied
        }
    }
}

コードに関する主なポイント
  • onRequestPermissionsResult コールバックで deviceId オーバーロードを使用し、権限ステータスがホスト スマートフォンではなく、オーディオ グラスやディスプレイ グラスなどの特定のコンテキストに正しくマッピングされるようにします。
  • アプリは、許可された結果と拒否された結果の両方を適切に処理する必要があります。