יצירת הפעילות הראשונה למשקפי אודיו ולמשקפי תצוגה

מכשירי XR שמתאימים לשימוש
ההנחיות האלה יעזרו לכם ליצור חוויות למכשירי XR מהסוגים הבאים.
משקפי אודיו ותצוגה

חוויות מציאות רבודה במשקפי שמע ובמשקפיים עם תצוגה מבוססות על ה-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-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"
}

Kotlin

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 מציין למערכת שהפעילות הזו צריכה להשתמש בהקשר מוקרן כדי לגשת לחומרה ממכשיר מחובר.

ליצור את הפעילות

לאחר מכן, תיצרו פעילות קטנה שיכולה להציג משהו במשקפי ה-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))
    }
}

מידע חשוב על הקוד

להטמיע את הרכיב הקומפוזבילי

הפעילות שיצרתם מפנה אל פונקציית 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 של Jetpack Compose‏ Button סוגר את הפעילות על ידי קריאה ל-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 יכול להיות הקשר מהטלפון או מהמשקפיים.

השלבים הבאים

אחרי שיצרתם את הפעילות הראשונה למשקפי שמע ולמשקפי תצוגה, אתם יכולים לנסות דרכים אחרות להרחבת הפונקציונליות שלה: