Как создать первое действие для аудиоочков и очков с дисплеем

Поддерживаемые XR-устройства
Это руководство поможет вам создавать контент для таких устройств.
Аудио- и
видеоочки

Дополненная реальность для аудио- и видеоочков создается на основе существующего Activity API фреймворка Android и включает дополнительные концепции, необходимые для поддержки уникальных особенностей этих устройств. В отличие от шлемов XR, которые запускают APK-файл на устройстве, аудиоочки и очки с дисплеем используют специальное действие, выполняемое в существующем приложении на телефоне. Это действие проецируется с основного устройства на очки.

Чтобы создать приложение для аудио- и видеоочков, расширьте существующее приложение для телефона, добавив в него новый проецируемый Activity. Это действие является основной точкой входа для запуска приложения на очках. Такой подход упрощает разработку, поскольку позволяет использовать одну и ту же бизнес-логику в приложениях для телефона и очков.

Совместимость с версиями

Проверьте требования к совместимости Android SDK для Jetpack XR SDK.

Связанные запросы

Добавьте следующие зависимости библиотеки для аудиоочков и очков с дисплеем:

Яркий

dependencies {
    implementation "androidx.xr.runtime:runtime:1.1.0-alpha01"
    implementation "androidx.xr.glimmer:glimmer:1.0.0-alpha18"
    implementation "androidx.xr.glimmer:glimmer-google-fonts:1.0.0-alpha18"
    implementation "androidx.xr.projected:projected:1.0.0-alpha09"
    implementation "androidx.xr.arcore:arcore:1.0.0-beta02"
}

Kotlin

dependencies {
    implementation("androidx.xr.runtime:runtime:1.1.0-alpha01")
    implementation("androidx.xr.glimmer:glimmer:1.0.0-alpha18")
    implementation("androidx.xr.glimmer:glimmer-google-fonts:1.0.0-alpha18")
    implementation("androidx.xr.projected:projected:1.0.0-alpha09")
    implementation("androidx.xr.arcore:arcore:1.0.0-beta02")
}

Объявите действие в манифесте приложения

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

<application>
  <activity
      android:name="com.example.xr.projected.ProjectedMainActivity"
      android:exported="true"
      android:requiredDisplayCategory="android.hardware.display.category.XR_PROJECTED"
      android:label="Example activity for audio glasses and display glasses">
      <intent-filter>
          <action android:name="android.intent.action.MAIN" />
          <category android:name="android.intent.category.XR_PROJECTED_LAUNCHER"/>
      </intent-filter>
  </activity>
</application>

Ключевые моменты

  • Указывает значение android.hardware.display.category.XR_PROJECTED для атрибута android:requiredDisplayCategory, чтобы сообщить системе, что это спроецированное действие, которое можно проецировать на аудио- и видеоочки.
  • android.intent.action.MAIN задает это действие как действие запуска по умолчанию.
  • android.intent.category.XR_PROJECTED_LAUNCHER – это специальная категория, которая позволяет Gemini находить запланированные вами действия с помощью голосовых команд.

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

Как создать действие

Затем вы создадите небольшое приложение, которое будет показывать что-либо на экране ИИ-очков при его включении.

@OptIn(ExperimentalProjectedApi::class)
class ProjectedMainActivity : ComponentActivity() {

    private var displayController: ProjectedDisplayController? = null
    private var isVisualUiSupported by mutableStateOf(false)
    private var areVisualsOn by mutableStateOf(true)

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        lifecycle.addObserver(object : DefaultLifecycleObserver {
            override fun onDestroy(owner: LifecycleOwner) {
                displayController?.close()
                displayController = null
            }
        })

        initializeGlassesFeatures()

        setContent {
            GlimmerTheme {
                HomeScreen(
                    areVisualsOn = areVisualsOn,
                    isVisualUiSupported = isVisualUiSupported,
                    onClose = { finish() }
                )
            }
        }
    }

    private fun initializeGlassesFeatures() {
        lifecycleScope.launch {
            // Check device capabilities
            val projectedDeviceController = ProjectedDeviceController.create(this@ProjectedMainActivity)
            isVisualUiSupported = projectedDeviceController.capabilities.contains(CAPABILITY_VISUAL_UI)

            val controller = ProjectedDisplayController.create(this@ProjectedMainActivity)
            displayController = controller
            val observer = GlassesLifecycleObserver(
                context = this@ProjectedMainActivity,
                controller = controller,
                onVisualsChanged = { visualsOn -> areVisualsOn = visualsOn }
            )
            lifecycle.addObserver(observer)
        }
    }
}

Ключевые моменты

Как реализовать composable-функцию

Созданное вами действие ссылается на HomeScreen composable-функцию, которую вам нужно реализовать. В следующем коде используется Jetpack Compose Glimmer, чтобы определить composable-функцию, которая может отображать текст на дисплее очков:

@Composable
fun HomeScreen(
    areVisualsOn: Boolean,
    isVisualUiSupported: Boolean,
    onClose: () -> Unit,
    modifier: Modifier = Modifier
) {
    Box(
        modifier = modifier
            .surface()
            .focusable(false)
            .fillMaxSize(),
        contentAlignment = Alignment.Center
    ) {
        if (isVisualUiSupported) {
            ActionCard(
                title = { Text("Android XR") },
                action = {
                    Button(onClick = onClose) {
                        Text("Close")
                    }
                }
            ) {
                if (areVisualsOn) {
                    Text("Hello, Display Glasses!")
                } else {
                    Text("Display is off. Audio guidance active.")
                }
            }
        } else {
            Text("Audio Guidance Mode Active")
        }
    }
}

Ключевые моменты

  • Как вы определили ранее, функция HomeScreen включает контент, который пользователь видит на экране очков.
  • Компонент Glimmer Text из библиотеки Jetpack Compose отображает на экране очков текст "Hello, AI Glasses!" (Привет, ИИ-очки!).
  • Glimmer Button для Jetpack Compose закрывает окно, вызывая finish() через onClose в проецируемом окне.

Проверьте, подключены ли аудиоочки или очки для дисплея

Чтобы определить, подключены ли аудио- или видеоочки пользователя к его телефону, прежде чем запускать действие, используйте метод ProjectedContext.isProjectedDeviceConnected. Этот метод возвращает Flow<Boolean>, за которым ваше приложение может наблюдать, чтобы получать обновления статуса подключения в реальном времени.

Как начать тренировку

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

val options = ProjectedContext.createProjectedActivityOptions(context)
val intent = Intent(context, ProjectedMainActivity::class.java)
context.startActivity(intent, options.toBundle())

Метод createProjectedActivityOptions в ProjectedContext создает необходимые параметры для запуска объекта activity в контексте проекции. Параметр context может представлять собой контекст с телефона или устройства Glass.

Дальнейшие действия

Теперь, когда вы создали первое действие для аудиоочков и дисплейных очков, изучите другие способы расширения его функциональности: