Используйте проецируемый контекст для доступа к оборудованию очков ИИ

Применимые устройства XR
Данное руководство поможет вам создавать приложения для устройств XR такого типа.
Очки с искусственным интеллектом

После того, как вы запросите и получите необходимые разрешения , ваше приложение сможет получить доступ к аппаратному обеспечению очков с искусственным интеллектом. Ключ к доступу к аппаратному обеспечению очков (а не телефона) заключается в использовании проецируемого контекста .

Существует два основных способа получения контекста проекции, в зависимости от того, где выполняется ваш код:

Получите контекст проекции, если ваш код выполняется в активности, использующей очки искусственного интеллекта.

Если код вашего приложения выполняется внутри активности, связанной с очками с искусственным интеллектом, то контекст этой активности уже является проецируемым контекстом. В этом случае вызовы, совершаемые внутри этой активности, уже могут получить доступ к аппаратному обеспечению очков.

Получите контекст выполнения кода в компоненте мобильного приложения.

Если части вашего приложения, находящейся вне среды использования очков с ИИ (например, функция телефона или сервис), требуется доступ к аппаратному обеспечению очков, необходимо явно получить проецируемый контекст. Для этого используйте метод 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
    }
}

Проверьте достоверность

После создания контекста проекции отслеживайте метод ProjectedContext.isProjectedDeviceConnected . Пока этот метод возвращает true , контекст проекции остается действительным для подключенного устройства, и ваше приложение или служба на телефоне (например, CameraManager ) может получить доступ к аппаратному обеспечению очков с искусственным интеллектом.

Очистка при отключении

Проецируемый контекст привязан к жизненному циклу подключенного устройства, поэтому он уничтожается при отключении устройства. При отключении устройства ProjectedContext.isProjectedDeviceConnected возвращает false . Ваше приложение должно отслеживать это изменение и очищать все системные службы (например, CameraManager ) или ресурсы, созданные вашим приложением с использованием этого проецируемого контекста.

Повторная инициализация при повторном подключении.

Когда устройство с ИИ-очками переподключится, ваше приложение сможет получить еще один экземпляр проецируемого контекста с помощью createProjectedDeviceContext() , а затем повторно инициализировать любые системные службы или ресурсы, используя новый проецируемый контекст.

Доступ к аудио через Bluetooth

В настоящее время очки с поддержкой искусственного интеллекта подключаются к телефону как стандартное аудиоустройство Bluetooth. Поддерживаются как сами очки, так и профили A2DP (Advanced Audio Distribution Profile). Такой подход позволяет любому приложению Android, поддерживающему ввод или вывод звука, работать на очках, даже если они не были специально разработаны для работы с очками. В некоторых случаях использование Bluetooth может быть более эффективным для вашего приложения в качестве альтернативы доступу к аппаратному обеспечению очков через контекст проекции.

Как и в случае с любым стандартным Bluetooth-аудиоустройством, разрешение на предоставление параметра RECORD_AUDIO контролируется телефоном, а не очками.

Сделайте снимок с помощью камеры очков с искусственным интеллектом.

Чтобы сделать снимок с помощью камеры очков с искусственным интеллектом, настройте и свяжите сценарий использования ImageCapture модуля CameraX с камерой очков, используя правильный контекст для вашего приложения:

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 , используя контекст проецируемого устройства .
  • В рамках предполагаемого контекста основная, направленная наружу камера очков с искусственным интеллектом сопоставляется с камерой DEFAULT_BACK_CAMERA при выборе камеры.
  • Предварительная проверка с помощью cameraProvider.hasCamera(cameraSelector) подтверждает наличие выбранной камеры на устройстве перед продолжением.
  • Использует Camera2 Interop с Camera2CameraInfo для чтения базового объекта CameraCharacteristics#SCALER_STREAM_CONFIGURATION_MAP , что может быть полезно для расширенной проверки поддерживаемых разрешений.
  • Для точного управления разрешением выходного изображения в ImageCapture создан специальный ResolutionSelector .
  • Создает сценарий использования ImageCapture , настроенный с использованием пользовательского ResolutionSelector .
  • Привязывает сценарий использования ImageCapture к жизненному циклу активности. Это автоматически управляет открытием и закрытием камеры в зависимости от состояния активности (например, останавливает камеру, когда активность приостановлена).

После настройки камеры очков с искусственным интеллектом вы можете сделать снимок с помощью класса ImageCapture из библиотеки CameraX. Чтобы узнать, как использовать takePicture() для захвата изображения , обратитесь к документации CameraX.

Запишите видео с помощью камеры очков с искусственным интеллектом.

Чтобы с помощью камеры очков с искусственным интеллектом захватывать видео, а не изображение, замените компоненты ImageCapture соответствующими компонентами VideoCapture и измените логику выполнения захвата.

Основные изменения касаются использования другого сценария применения, создания другого выходного файла и запуска захвата с помощью соответствующего метода видеозаписи. Для получения дополнительной информации об API VideoCapture и способах его использования см. документацию по захвату видео CameraX .

В таблице ниже приведены рекомендуемые разрешение и частота кадров в зависимости от сценария использования вашего приложения:

Вариант использования Разрешение Частота кадров
Видеосвязь 1280 x 720 15 кадров в секунду
Компьютерное зрение 640 x 480 10 кадров в секунду
Потоковое видео с использованием ИИ 640 x 480 1 кадр в секунду

Получите доступ к аппаратному обеспечению телефона из приложения, использующего очки с искусственным интеллектом.

Активность AI Glasses также может получить доступ к аппаратному обеспечению телефона (например, к камере или микрофону), используя 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
    }
}

При доступе к оборудованию или ресурсам, специфичным для хост-устройства (телефона) в гибридном приложении (приложении, сочетающем в себе мобильный интерфейс и возможности очков с искусственным интеллектом), необходимо явно выбрать правильный контекст, чтобы убедиться, что ваше приложение может получить доступ к нужному оборудованию:

  • Для получения контекста телефона используйте контекст Activity из Activity телефона или вызовите метод ProjectedContext.createHostDeviceContext() .
  • Не используйте getApplicationContext() поскольку контекст приложения может некорректно возвращать контекст очков ИИ, если активность очков была последним запущенным компонентом.