投影されたコンテキストを使用して AI メガネのハードウェアにアクセスする

対応する XR デバイス
このガイダンスは、次のようなタイプの XR デバイス向けのエクスペリエンスを構築する際に役立ちます。
AI グラス

必要な権限をリクエストして付与されると、アプリは AI グラスのハードウェアにアクセスできるようになります。グラスのハードウェア (スマートフォンのハードウェアではなく)にアクセスする鍵は、プロジェクション コンテキストを使用することです。

コードの実行場所に応じて、プロジェクション コンテキストを取得する主な方法は 2 つあります。

コードが AI グラス アクティビティで実行されている場合は、プロジェクション コンテキストを取得する

アプリのコードが AI グラス アクティビティ内から実行されている場合、そのアクティビティ コンテキスト自体がプロジェクション コンテキストになります。このシナリオでは、そのアクティビティ内で行われた呼び出しは、すでにグラスのハードウェアにアクセスできます。

スマートフォン アプリ コンポーネントで実行されているコードのプロジェクション コンテキストを取得する

AI グラス アクティビティ以外のアプリの一部(スマートフォン アクティビティやサービスなど)がグラスのハードウェアにアクセスする必要がある場合は、プロジェクション コンテキストを明示的に取得する必要があります。これを行うには、 createProjectedDeviceContext() メソッドを使用します。

@OptIn(ExperimentalProjectedApi::class)
private fun getGlassesContext(context: Context): Context? {
    return try {
        // From a phone Activity or Service, get a context for the AI glasses.
        ProjectedContext.createProjectedDeviceContext(context)
    } catch (e: IllegalStateException) {
        Log.e(TAG, "Failed to create projected device context", e)
        null
    }
}

有効性を確認する

createProjectedDeviceContext 呼び出しを ProjectedContext.isProjectedDeviceConnected 内にラップします。このメソッドが true を返している間、プロジェクション コンテキストは接続されたデバイスに対して有効なままであり、スマートフォン アプリのアクティビティまたはサービス(CameraManager など)は AI グラスのハードウェアにアクセスできます。

切断時にクリーンアップする

プロジェクション コンテキストは接続されたデバイスのライフサイクルに関連付けられているため、デバイスが切断されると破棄されます。デバイスが切断されると、 ProjectedContext.isProjectedDeviceConnectedfalse を返します。アプリはこの変更をリッスンし、そのプロジェクション コンテキストを使用してアプリが作成したシステム サービス(CameraManager など)またはリソースをクリーンアップする必要があります。

再接続時に再初期化する

AI グラス デバイスが再接続すると、アプリは別のプロジェクション コンテキスト インスタンスを createProjectedDeviceContext() を使用して取得し、新しいプロジェクション コンテキストを使用してシステム サービスまたはリソースを再初期化できます。

Bluetooth を使用して音声にアクセスする

現在、AI グラスは標準の Bluetooth オーディオ デバイスとしてスマートフォンに接続します。ヘッドセット プロファイルと A2DP(Advanced Audio Distribution Profile) プロファイルの両方がサポートされています。このアプローチを使用すると、グラスをサポートするように意図的に構築されていない場合でも、音声の入出力に対応する Android アプリをグラスで動作させることができます。場合によっては、プロジェクション コンテキストを使用してグラスのハードウェアにアクセスする代わりに、Bluetooth を使用する方がアプリのユースケースに適していることがあります。

標準の Bluetooth オーディオ機器と同様に、 RECORD_AUDIO 権限を付与する権限は、グラスではなくスマートフォンによって制御されます。

AI グラスのカメラで画像をキャプチャする

AI グラスのカメラで画像をキャプチャするには、アプリの正しい コンテキストを使用して、CameraX の ImageCapture ユースケースをグラスのカメラに設定してバインドします。

private fun startCameraOnGlasses(activity: ComponentActivity) {
    // 1. Get the CameraProvider using the projected context.
    // When using the projected context, DEFAULT_BACK_CAMERA maps to the AI glasses' camera.
    val projectedContext = try {
        ProjectedContext.createProjectedDeviceContext(activity)
    } catch (e: IllegalStateException) {
        Log.e(TAG, "AI Glasses context could not be created", e)
        return
    }

    val cameraProviderFuture = ProcessCameraProvider.getInstance(projectedContext)

    cameraProviderFuture.addListener({
        val cameraProvider: ProcessCameraProvider = cameraProviderFuture.get()
        val cameraSelector = CameraSelector.DEFAULT_BACK_CAMERA

        // 2. Check for the presence of a camera.
        if (!cameraProvider.hasCamera(cameraSelector)) {
            Log.w(TAG, "The selected camera is not available.")
            return@addListener
        }

        // 3. Query supported streaming resolutions using Camera2 Interop.
        val cameraInfo = cameraProvider.getCameraInfo(cameraSelector)
        val camera2CameraInfo = Camera2CameraInfo.from(cameraInfo)
        val cameraCharacteristics = camera2CameraInfo.getCameraCharacteristic(
            CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP
        )

        // 4. Define the resolution strategy.
        val targetResolution = Size(1920, 1080)
        val resolutionStrategy = ResolutionStrategy(
            targetResolution,
            ResolutionStrategy.FALLBACK_RULE_CLOSEST_LOWER
        )
        val resolutionSelector = ResolutionSelector.Builder()
            .setResolutionStrategy(resolutionStrategy)
            .build()

        // 5. If you have other continuous use cases bound, such as Preview or ImageAnalysis,
        // you can use  Camera2 Interop's CaptureRequestOptions to set the FPS
        val fpsRange = Range(30, 60)
        val captureRequestOptions = CaptureRequestOptions.Builder()
            .setCaptureRequestOption(CaptureRequest.CONTROL_AE_TARGET_FPS_RANGE, fpsRange)
            .build()

        // 6. Initialize the ImageCapture use case with options.
        val imageCapture = ImageCapture.Builder()
            // Optional: Configure resolution, format, etc.
            .setResolutionSelector(resolutionSelector)
            .build()

        try {
            // Unbind use cases before rebinding.
            cameraProvider.unbindAll()

            // Bind use cases to camera using the Activity as the LifecycleOwner.
            cameraProvider.bindToLifecycle(
                activity,
                cameraSelector,
                imageCapture
            )
        } catch (exc: Exception) {
            Log.e(TAG, "Use case binding failed", exc)
        }
    }, ContextCompat.getMainExecutor(activity))
}

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

  • ProcessCameraProvider を使用して プロジェクション デバイス コンテキスト のインスタンスを取得します。
  • プロジェクション コンテキストのスコープ内で、カメラを選択すると、AI グラスのプライマリ カメラ(外向き)が DEFAULT_BACK_CAMERA にマッピングされます。
  • プリバインディング チェックでは、cameraProvider.hasCamera(cameraSelector) を使用して、選択したカメラがデバイスで使用可能であることを確認してから 処理を進めます。
  • Camera2CameraInfoCamera2 Interop を使用して、基盤となる CameraCharacteristics#SCALER_STREAM_CONFIGURATION_MAP を読み取ります。これは、サポートされている解像度に関する高度なチェックに役立ちます。
  • カスタム ResolutionSelector は、出力 画像解像度を正確に制御するために ImageCapture 構築されています。
  • カスタム ResolutionSelector で構成された ImageCapture ユースケースを作成します。
  • ImageCapture ユースケースをアクティビティのライフサイクルにバインドします。これにより、アクティビティの状態に基づいてカメラの開閉が自動的に管理されます(たとえば、アクティビティが一時停止するとカメラが停止します)。

AI グラスのカメラを設定したら、CameraX の ImageCapture クラスで画像をキャプチャできます。画像をキャプチャする方法については、CameraX のドキュメントを 参照して、takePicture()の使用について学習してください。

AI グラスのカメラで動画をキャプチャする

AI グラスのカメラで画像の代わりに動画をキャプチャするには、 ImageCapture コンポーネントを対応する VideoCapture コンポーネント に置き換え、キャプチャ実行ロジックを変更します。

主な変更点は、別のユースケースを使用し、別の出力ファイルを作成し、適切な動画録画方法を使用してキャプチャを開始することです。 VideoCapture API とその使用方法について詳しくは、 CameraX の動画キャプチャのドキュメントをご覧ください

次の表に、アプリのユースケースに応じた推奨解像度とフレームレートを示します。

ユースケース 解像度 フレームレート
ビデオ通話 1280 x 720 15 FPS
コンピュータ ビジョン 640 x 480 10 FPS
AI 動画ストリーミング 640 x 480 1 FPS

AI グラス アクティビティからスマートフォンのハードウェアにアクセスする

AI グラス アクティビティは、スマートフォンのハードウェア(カメラ やマイクなど)にアクセスすることもできます。これには、ホスト デバイス(スマートフォン)のコンテキストを取得するために createHostDeviceContext(context) を使用します。

@OptIn(ExperimentalProjectedApi::class)
private fun getPhoneContext(activity: ComponentActivity): Context? {
    return try {
        // From an AI glasses Activity, get a context for the phone.
        ProjectedContext.createHostDeviceContext(activity)
    } catch (e: IllegalStateException) {
        Log.e(TAG, "Failed to create host device context", e)
        null
    }
}

ハイブリッド アプリ(モバイルと AI グラスの両方のエクスペリエンスを含むアプリ)でホスト デバイス(スマートフォン)に固有のハードウェアまたはリソースにアクセスする場合は、アプリが正しいハードウェアにアクセスできるように、正しいコンテキストを明示的に選択する必要があります。

  • スマートフォンのコンテキストを取得するには、スマートフォンの Activity コンテキストまたは ProjectedContext.createHostDeviceContext() を使用します。Activity
  • getApplicationContext() は使用しないでください。グラス アクティビティが最後に起動されたコンポーネントである場合、アプリケーション コンテキスト が AI グラスのコンテキストを誤って返す可能性があります。