Membuat aktivitas pertama untuk kacamata audio dan kacamata tampilan

Perangkat XR yang kompatibel
Panduan ini membantu Anda membangun pengalaman untuk jenis perangkat XR ini.
Kacamata Audio &
Layar

Pengalaman augmented untuk kacamata audio dan kacamata layar dibangun di Android Activity framework API yang ada dan mencakup konsep tambahan untuk mendukung aspek unik dari kacamata ini. Tidak seperti headset XR yang menjalankan APK lengkap di perangkat, kacamata audio dan kacamata layar menggunakan aktivitas khusus yang berjalan dalam aplikasi yang ada di ponsel Anda. Aktivitas ini diproyeksikan dari perangkat host ke kacamata.

Untuk membuat pengalaman aplikasi Anda untuk kacamata audio dan kacamata layar, Anda memperluas aplikasi ponsel yang ada dengan membuat Activityyang diproyeksikan baru. Aktivitas ini berfungsi sebagai titik entri peluncuran utama untuk aplikasi Anda di kacamata. Pendekatan ini menyederhanakan pengembangan karena Anda dapat berbagi dan menggunakan kembali logika bisnis antara pengalaman ponsel dan kacamata.

Kompatibilitas versi

Periksa persyaratan kompatibilitas Android SDK untuk Jetpack XR SDK.

Dependensi

Tambahkan dependensi library berikut untuk kacamata audio dan kacamata layar:

Groovy

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

Mendeklarasikan aktivitas di manifes aplikasi

Sama seperti jenis aktivitas lainnya, Anda perlu mendeklarasikan aktivitas di file manifes aplikasi agar sistem dapat melihat dan menjalankannya.

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

Poin-poin penting tentang kode

  • Menentukan xr_projected untuk atribut android:requiredDisplayCategory untuk memberi tahu sistem bahwa aktivitas ini harus menggunakan konteks yang diproyeksikan untuk mengakses hardware dari perangkat yang terhubung.

Membuat aktivitas

Selanjutnya, Anda akan membuat aktivitas kecil yang dapat menampilkan sesuatu di kacamata AI setiap kali layar diaktifkan.

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

Poin-poin penting tentang kode

Mengimplementasikan composable

Aktivitas yang Anda buat mereferensikan fungsi composable HomeScreen yang perlu Anda implementasikan. Kode berikut menggunakan Jetpack Compose Glimmer untuk menentukan composable yang dapat menampilkan beberapa teks di layar kacamata:

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

Poin-poin penting tentang kode

  • Seperti yang Anda tentukan dalam aktivitas sebelumnya, fungsi HomeScreen mencakup konten composable yang dilihat pengguna saat layar kacamata aktif.
  • Komponen Text Jetpack Compose Glimmer menampilkan teks "Hello, AI Glasses!" ke layar kacamata.
  • Jetpack Compose Glimmer Button menutup aktivitas dengan memanggil finish() melalui onClose dalam aktivitas yang diproyeksikan.

Memeriksa apakah kacamata audio atau kacamata layar terhubung

Untuk menentukan apakah kacamata audio atau kacamata layar pengguna terhubung ke ponselnya sebelum meluncurkan aktivitas Anda, gunakan metode ProjectedContext.isProjectedDeviceConnected. Metode ini menampilkan Flow<Boolean> yang dapat diamati aplikasi Anda untuk mendapatkan update real-time tentang status koneksi.

Memulai aktivitas

Setelah membuat aktivitas dasar, Anda dapat meluncurkannya ke kacamata. Untuk mengakses hardware kacamata, aplikasi Anda harus memulai aktivitas dengan opsi tertentu yang memberi tahu sistem untuk menggunakan konteks yang diproyeksikan, seperti ditunjukkan dalam kode berikut:

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

Metode createProjectedActivityOptions di ProjectedContext menghasilkan opsi yang diperlukan untuk memulai aktivitas Anda dalam konteks yang diproyeksikan. Parameter context dapat berupa konteks dari ponsel atau perangkat kacamata.

Langkah berikutnya

Setelah membuat aktivitas pertama untuk kacamata audio dan kacamata layar, jelajahi cara lain untuk memperluas fungsinya: