Расширенные возможности для аудио- и дисплейных очков основаны на существующем API фреймворка Android Activity и включают дополнительные концепции для поддержки уникальных особенностей этих очков. В отличие от XR-гарнитур, которые запускают полноценный APK-файл на устройстве, аудио- и дисплейные очки используют специальную активность, которая работает внутри существующего приложения вашего телефона. Эта активность проецируется с устройства-носителя на очки.
Для создания интерфейса вашего приложения для аудио- и дисплейных очков вы расширяете существующее мобильное приложение, создавая новую проекционную Activity . Эта активность служит основной точкой входа для запуска вашего приложения на очках. Такой подход упрощает разработку, поскольку вы можете совместно использовать и повторно применять бизнес-логику между интерфейсами для телефона и очков.
Совместимость версий
Проверьте требования к совместимости Android SDK для Jetpack XR SDK.
Зависимости
Добавьте следующие зависимости библиотек для аудио- и дисплейных очков :
Классный
dependencies {
implementation "androidx.xr.runtime:runtime:1.0.0-alpha14"
implementation "androidx.xr.glimmer:glimmer:1.0.0-alpha12"
implementation "androidx.xr.glimmer:glimmer-google-fonts:1.0.0-alpha12"
implementation "androidx.xr.projected:projected:1.0.0-alpha07"
implementation "androidx.xr.arcore:arcore:1.0.0-alpha13"
}
Котлин
dependencies {
implementation("androidx.xr.runtime:runtime:1.0.0-alpha14")
implementation("androidx.xr.glimmer:glimmer:1.0.0-alpha12")
implementation("androidx.xr.glimmer:glimmer-google-fonts:1.0.0-alpha12")
implementation("androidx.xr.projected:projected:1.0.0-alpha07")
implementation("androidx.xr.arcore:arcore:1.0.0-alpha13")
}
Укажите тип активности в манифесте вашего приложения.
Как и в случае с другими типами действий, вам необходимо объявить о своем действии в файле манифеста вашего приложения, чтобы система могла его увидеть и запустить.
<application>
<activity
android:name="com.example.xr.projected.GlassesMainActivity"
android:exported="true"
android:requiredDisplayCategory="xr_projected"
android:label="Example activity for audio glasses and display glasses">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
</intent-filter>
</activity>
</application>
Основные моменты, касающиеся кода.
- Указывает
xr_projectedдля атрибутаandroid:requiredDisplayCategory, чтобы сообщить системе, что это действие должно использовать проецируемый контекст для доступа к оборудованию подключенного устройства.
Создайте свою активность
Далее вам нужно будет создать небольшое приложение, которое будет отображать что-либо на очках с искусственным интеллектом всякий раз, когда дисплей включен.
@OptIn(ExperimentalProjectedApi::class) class GlassesMainActivity : ComponentActivity() { private var displayController: ProjectedDisplayController? = null private var isVisualUiSupported by mutableStateOf(false) private var areVisualsOn by mutableStateOf(true) private var isPermissionDenied by mutableStateOf(false) // 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 } } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) lifecycle.addObserver(object : DefaultLifecycleObserver { override fun onDestroy(owner: LifecycleOwner) { displayController?.close() displayController = null } }) if (hasCameraPermission()) { initializeGlassesFeatures() } else { requestHardwarePermissions() } setContent { GlimmerTheme { HomeScreen( areVisualsOn = areVisualsOn, isVisualUiSupported = isVisualUiSupported, isPermissionDenied = isPermissionDenied, onRetryPermission = { requestHardwarePermissions() }, onClose = { finish() } ) } } } private fun initializeGlassesFeatures() { lifecycleScope.launch { // Check device capabilities val projectedDeviceController = ProjectedDeviceController.create(this@GlassesMainActivity) isVisualUiSupported = projectedDeviceController.capabilities.contains(CAPABILITY_VISUAL_UI) val controller = ProjectedDisplayController.create(this@GlassesMainActivity) displayController = controller val observer = GlassesLifecycleObserver( context = this@GlassesMainActivity, controller = controller, onVisualsChanged = { visualsOn -> areVisualsOn = visualsOn } ) lifecycle.addObserver(observer) } } private fun hasCameraPermission(): Boolean { return ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA) == PackageManager.PERMISSION_GRANTED } 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)) } }
Основные моменты, касающиеся кода.
- Выбирает использование API из библиотеки Jetpack Projected, доступных по желанию.
-
GlassesMainActivityнаследуетComponentActivity, как и следовало ожидать в мобильной разработке. - Поскольку не все очки имеют дисплей, проверка наличия дисплея на устройстве выполняется с помощью
ProjectedDeviceController. - Блок
setContentвнутри функцииonCreateопределяет корень дерева Composable UI для активности. Вы реализуете ComposableHomeScreenс помощью Jetpack Compose Glimmer . - Инициализирует пользовательский интерфейс во время вызова метода
onCreateактивности (см. прогнозируемый жизненный цикл активности ). - Для подготовки к работе с функциями камеры, которые обращаются к аппаратному обеспечению очков , запрашиваются разрешения на использование оборудования путем регистрации средства запуска разрешений, определения функций
hasCameraPermissionиrequestHardwarePermissionsи проверки наличия предоставленных разрешений перед вызовом функцииinitializeGlassesFeatures.
Реализуйте составной модуль.
Созданное вами действие ссылается на составную функцию HomeScreen , которую вам необходимо реализовать. Следующий код использует Jetpack Compose Glimmer для определения составного элемента, который может отображать текст на дисплее очков:
@Composable fun HomeScreen( areVisualsOn: Boolean, isVisualUiSupported: Boolean, isPermissionDenied: Boolean, onRetryPermission: () -> Unit, onClose: () -> Unit, modifier: Modifier = Modifier ) { Box( modifier = modifier .surface() .focusable(false) .fillMaxSize(), contentAlignment = Alignment.Center ) { if (isPermissionDenied) { Card( title = { Text("Permission Required") }, action = { Button(onClick = onClose) { Text("Exit") } } ) { Text("Camera access is needed to use AI glasses features.") Button(onClick = onRetryPermission) { Text("Retry") } } } else if (isVisualUiSupported) { Card( title = { Text("Android XR") }, action = { Button(onClick = onClose) { Text("Close") } } ) { if (areVisualsOn) { Text("Hello, AI Glasses!") } else { Text("Display is off. Audio guidance active.") } } } else { Text("Audio Guidance Mode Active") } } }
Основные моменты, касающиеся кода.
- Как вы уже указали в своем предыдущем задании, функция
HomeScreenвключает в себя составной контент, который пользователь видит, когда дисплей очков включен. - Компонент Jetpack Compose Glimmer
Textотображает текст "Привет, очки с искусственным интеллектом!" на экране очков. - Кнопка Jetpack Compose Glimmer
Buttonзакрывает активность, вызываяfinish()черезonCloseв проецируемой активности.
Проверьте, подключены ли аудиоочки или очки для просмотра изображения.
Чтобы определить, подключены ли аудио- или дисплейные очки пользователя к его телефону перед запуском вашего приложения, используйте метод ProjectedContext.isProjectedDeviceConnected . Этот метод возвращает Flow<Boolean> , который ваше приложение может отслеживать для получения обновлений о состоянии подключения в реальном времени.
Начать свою активность
Теперь, когда вы создали базовую активность, вы можете запустить её на своих очках. Для доступа к аппаратному обеспечению очков ваше приложение должно запустить активность с определёнными параметрами, которые указывают системе использовать проецируемый контекст , как показано в следующем коде:
val options = ProjectedContext.createProjectedActivityOptions(context) val intent = Intent(context, GlassesMainActivity::class.java) context.startActivity(intent, options.toBundle())
Метод createProjectedActivityOptions в ProjectedContext генерирует необходимые параметры для запуска активности в проецируемом контексте. Параметр context может представлять собой контекст телефона или очков.
Следующие шаги
Теперь, когда вы создали свою первую активность для аудио- и дисплейных очков, изучите другие способы расширения ее функциональности:
- Обработка аудиовывода с помощью преобразования текста в речь.
- Обработка аудиовхода с помощью автоматического распознавания речи.
- Создавайте пользовательский интерфейс с помощью Jetpack Compose и Glimmer.
- Доступ к аппаратному обеспечению на аудиоочках и очках с дисплеем