ViewModellanguagepack directory. Open the project in Android Studio. Before building, replace the APPLICATION_ID placeholder in MainActivity.kt with your app’s registered Horizon application ID from the Meta Horizon developer dashboard. Build and deploy the sample to your Quest device using the standard Android deployment workflow.| File | What it demonstrates | Key concepts |
|---|---|---|
MainActivity.kt | Activity entry point with SDK connection and Compose UI rendering | HorizonServiceConnection.connect(), lifecycle scope integration |
LanguagePackViewModel.kt | Business logic for service verification and UI state management | LanguagePack instantiation, StateFlow-based reactive state, coroutine-based initialization |
LanguagePackViewModelTest.kt | Unit tests for UI state data class behavior | Data class default values and copy() behavior verification |
gradle/libs.versions.toml | Centralized dependency versions for SDK artifacts | Version catalog management |
app/build.gradle.kts | Module configuration with Compose and Platform SDK dependencies | SDK artifact declaration |
LanguagePack service initialized successfully.” in a styled card. If initialization fails, the error details appear in a separate error card. The UI uses Material 3 cards with a loading indicator while the check is in progress.HorizonServiceConnection.connect() in the Activity’s onCreate() method, before rendering the Compose UI:HorizonServiceConnection.connect(
APPLICATION_ID, applicationContext, lifecycleScope
)
MainActivity.kt for the complete implementation.ViewModel creates a Language Pack instance using the no-argument constructor. This establishes the service reference for localization queries:private val languagePack = LanguagePack()
LanguagePackViewModel.kt for the verification logic.LanguagePackUiState with three properties: isLoading, resultMessage, and errorMessage. The ViewModel exposes this state as a StateFlow, triggering recomposition when state changes:data class LanguagePackUiState(
val isLoading: Boolean = false,
val resultMessage: String? = null,
val errorMessage: String? = null,
)
ViewModel’s lifecycle scope. Error handling uses a try-catch block that populates the error message property on failure:viewModelScope.launch(Dispatchers.IO) {
try { /* check logic */ }
catch (e: Exception) { /* update error state */ }
}
LanguagePackViewModel to call Language Pack API methods that retrieve available locales or download language resources after initialization succeeds.LanguagePackViewModel to demonstrate coordinated initialization patterns.