ऑडियो ग्लास और डिसप्ले ग्लास के लिए, पहली गतिविधि बनाना

एक्सआर डिवाइसों पर लागू होने वाली सुविधाएं
इस गाइड की मदद से, इन तरह के एक्सआर डिवाइसों के लिए अनुभव बनाए जा सकते हैं.
ऑडियो और
डिसप्ले ग्लास

ऑडियो ग्लास और डिसप्ले ग्लास के लिए, ऑगमेंटेड एक्सपीरियंस को Android के मौजूदा Activity फ़्रेमवर्क एपीआई पर बनाया गया है. साथ ही, इनमें इन ग्लास की खास बातों को ध्यान में रखते हुए, अतिरिक्त कॉन्सेप्ट शामिल किए गए हैं. एक्सआर हेडसेट, डिवाइस पर पूरा APK चलाते हैं. हालांकि, ऑडियो ग्लास और डिसप्ले ग्लास, एक खास गतिविधि का इस्तेमाल करते हैं. यह गतिविधि, आपके फ़ोन के मौजूदा ऐप्लिकेशन में चलती है. इस गतिविधि को होस्ट डिवाइस से ग्लास पर प्रोजेक्ट किया जाता है.

ऑडियो ग्लास और डिसप्ले ग्लास के लिए अपने ऐप्लिकेशन का अनुभव बनाने के लिए, आपको अपने मौजूदा फ़ोन ऐप्लिकेशन को बढ़ाना होगा. इसके लिए, एक नया प्रोजेक्टेड Activity बनाएं. यह ऐक्टिविटी, स्मार्ट ग्लास पर आपके ऐप्लिकेशन को लॉन्च करने का मुख्य एंट्री पॉइंट है. इस तरीके से डेवलपमेंट करना आसान हो जाता है, क्योंकि फ़ोन और स्मार्ट ग्लास के बीच कारोबारी नियम को शेयर और फिर से इस्तेमाल किया जा सकता है.

वर्शन के साथ काम करने की सुविधा

Jetpack XR SDK के लिए, Android SDK के साथ काम करने से जुड़ी ज़रूरी शर्तें देखें.

डिपेंडेंसी

ऑडियो ग्लास और डिसप्ले ग्लास के लिए, लाइब्रेरी की ये डिपेंडेंसी जोड़ें:

शानदार

dependencies {
    implementation "androidx.xr.runtime:runtime:1.0.0-alpha15"
    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-alpha15")
    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 को बोलकर दिए गए निर्देशों के ज़रिए, प्रोजेक्ट की गई आपकी गतिविधि का पता चलता है.

    जब कोई व्यक्ति, ऐप्लिकेशन के नाम का इस्तेमाल करके बोलकर निर्देश देता है (उदाहरण के लिए, "एआई कैटलॉग का सैंपल खोलो", "एआई कैटलॉग का सैंपल लॉन्च करो" या "एआई कैटलॉग का सैंपल शुरू करो"), तो सिस्टम इस कैटगरी का इस्तेमाल करके, ऑडियो या डिसप्ले वाले चश्मे पर तय की गई गतिविधि को ढूंढता है और उसे शुरू करता है.

अपनी गतिविधि बनाना

इसके बाद, आपको एक छोटी गतिविधि बनानी होगी. इससे, डिसप्ले चालू होने पर एआई चश्मे पर कुछ दिखाया जा सकेगा.

@OptIn(ExperimentalProjectedApi::class)
class ProjectedMainActivity : 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@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)
        }
    }

    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))
    }
}

कोड के बारे में अहम बातें

  • Jetpack Projected लाइब्रेरी से opt-in APIs का इस्तेमाल करने के लिए ऑप्ट-इन करता है.
  • ProjectedMainActivity, ComponentActivity को बढ़ाता है. यह मोबाइल डेवलपमेंट में आपकी उम्मीद के मुताबिक होता है.
  • सभी चश्मों में डिसप्ले नहीं होता है. इसलिए, यह फ़ंक्शन ProjectedDeviceController का इस्तेमाल करके यह जांच करता है कि डिवाइस में डिसप्ले है या नहीं.
  • onCreate फ़ंक्शन में मौजूद setContent ब्लॉक, ऐक्टिविटी के लिए कंपोज़ेबल यूज़र इंटरफ़ेस (यूआई) ट्री का रूट तय करता है. Jetpack Compose Glimmer का इस्तेमाल करके, HomeScreen कंपोज़ेबल लागू किया जाएगा.
  • यह ऐक्टिविटी के 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 कॉम्पोनेंट, चश्मे के डिसप्ले पर "Hello, AI Glasses!" टेक्स्ट दिखाता है.
  • Jetpack Compose Glimmer Button, प्रोजेक्ट की गई गतिविधि में onClose के ज़रिए finish() को कॉल करके गतिविधि बंद कर देता है.

देखें कि ऑडियो या डिस्प्ले वाले स्मार्ट ग्लास कनेक्ट किए गए हैं या नहीं

यह पता लगाने के लिए कि आपकी गतिविधि शुरू करने से पहले, किसी उपयोगकर्ता के ऑडियो या डिसप्ले वाले चश्मे उसके फ़ोन से कनेक्ट हैं या नहीं, ProjectedContext.isProjectedDeviceConnected तरीके का इस्तेमाल करें. यह तरीका, Flow<Boolean> दिखाता है. आपका ऐप्लिकेशन इस Flow<Boolean> को देखकर, कनेक्शन की स्थिति के बारे में रीयल-टाइम अपडेट पा सकता है.

अपनी गतिविधि शुरू करना

आपने बुनियादी गतिविधि बना ली है. अब इसे अपने चश्मे पर लॉन्च किया जा सकता है. चश्मे के हार्डवेयर को ऐक्सेस करने के लिए, आपके ऐप्लिकेशन को कुछ खास विकल्पों के साथ अपनी गतिविधि शुरू करनी होगी. इससे सिस्टम को प्रोजेक्ट किए गए कॉन्टेक्स्ट का इस्तेमाल करने के बारे में पता चलेगा. यह कोड में दिखाया गया है:

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

ProjectedContext में मौजूद createProjectedActivityOptions तरीके से, अनुमानित कॉन्टेक्स्ट में अपनी गतिविधि शुरू करने के लिए ज़रूरी विकल्प जनरेट किए जाते हैं. context पैरामीटर, फ़ोन या चश्मे के डिवाइस से लिया गया कॉन्टेक्स्ट हो सकता है.

अगले चरण

अब आपने ऑडियो ग्लास और डिसप्ले ग्लास के लिए पहली गतिविधि बना ली है. इसकी सुविधाओं को बढ़ाने के अन्य तरीके जानें: