חוויות מציאות רבודה במשקפיים עם ממשק קולי ובמשקפיים עם תצוגה פנימית מבוססות על ה-API של מסגרת Activity הקיימת של Android, וכוללות קונספטים נוספים לתמיכה בהיבטים הייחודיים של המשקפיים האלה. בניגוד למשקפי VR עם Android 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-alpha13"
implementation "androidx.xr.glimmer:glimmer-google-fonts:1.0.0-alpha13"
implementation "androidx.xr.projected:projected:1.0.0-alpha08"
implementation "androidx.xr.arcore:arcore:1.0.0-alpha14"
}
Kotlin
dependencies {
implementation("androidx.xr.runtime:runtime:1.0.0-alpha14")
implementation("androidx.xr.glimmer:glimmer:1.0.0-alpha13")
implementation("androidx.xr.glimmer:glimmer-google-fonts:1.0.0-alpha13")
implementation("androidx.xr.projected:projected:1.0.0-alpha08")
implementation("androidx.xr.arcore:arcore:1.0.0-alpha14")
}
הצהרה על הפעילות במניפסט של האפליקציה
כמו סוגים אחרים של פעילויות, צריך להצהיר על הפעילות בקובץ המניפסט של האפליקציה כדי שהמערכת תוכל לראות אותה ולהריץ אותה.
<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 לגלות את הפעילות המתוכננת שלכם באמצעות פקודות קוליות.כשמשתמש נותן פקודה קולית באמצעות שם האפליקציה (לדוגמה, 'Open the AI catalog sample', 'Launch the AI catalog sample' או 'Start the AI catalog sample'), המערכת משתמשת בקטגוריה הזו כדי לאתר ולהפעיל את הפעילות שצוינה במשקפי השמע או במשקפיים עם תצוגה פנימית.
ליצור את הפעילות
בשלב הבא, תיצרו פעילות קטנה שיכולה להציג משהו במשקפי ה-AI בכל פעם שהתצוגה מופעלת.
@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מגדיר את הרמה הבסיסית (root) של עץ ממשק המשתמש הקומפוזבילי של הפעילות. תטמיעו את הקודHomeScreenקומפוזבילי באמצעות Jetpack Compose Glimmer. - מאתחל את ממשק המשתמש במהלך ה-method
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כוללת את התוכן הקומפוזבילי שהמשתמש רואה כשהמסך של המשקפיים פועל. - רכיב 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, GlassesMainActivity::class.java) context.startActivity(intent, options.toBundle())
ה-method createProjectedActivityOptions ב-ProjectedContext
יוצרת את האפשרויות הנדרשות כדי להתחיל את הפעילות בהקשר מוקרן.
הפרמטר context יכול להיות הקשר מהטלפון או מהמשקפיים.
השלבים הבאים
אחרי שיצרתם את ה-Activity הראשונה למשקפיים עם ממשק קולי ולמשקפיים עם תצוגה פנימית, אתם יכולים לנסות דרכים נוספות להרחבת הפונקציונליות שלה:
- טיפול בפלט אודיו באמצעות המרת טקסט לדיבור
- טיפול בקלט אודיו באמצעות זיהוי אוטומטי של דיבור
- יצירת ממשק משתמש באמצעות Glimmer של Jetpack Compose
- גישה לחומרה במשקפיים עם ממשק קולי ובמשקפיים עם תצוגה פנימית