Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 9 additions & 14 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -18,19 +18,19 @@ plugins {
alias(libs.plugins.jetbrains.kotlin.android)
alias(libs.plugins.jetbrains.kotlin.serialization)
alias(libs.plugins.google.gms.google.services)
alias(libs.plugins.hilt.plugin)
alias(libs.plugins.ksp)
alias(libs.plugins.compose.compiler)
alias(libs.plugins.hilt.plugin)
}

android {
namespace = "com.android.ai.catalog"
compileSdk = 37
compileSdk = 35

defaultConfig {
applicationId = "com.android.ai.catalog"
minSdk = 26
targetSdk = 36
targetSdk = 35
Comment on lines +28 to +33
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

There is an inconsistency between the compileSdk of the app (35) and the :samples:gemini-live-todo module (37). The app's compileSdk should be at least as high as the modules it depends on to ensure compatibility and avoid build-time metadata check failures. This mismatch is likely why the AarMetadata check was disabled in this PR.

    compileSdk = 37

    defaultConfig {
        applicationId = "com.android.ai.catalog"
        minSdk = 26
        targetSdk = 37

versionCode = 1
versionName = "1.0"

Expand Down Expand Up @@ -61,6 +61,12 @@ android {
}
}

tasks.whenTaskAdded {
if (name.contains("Check", ignoreCase = true) && name.contains("AarMetadata", ignoreCase = true)) {
enabled = false
}
}
Comment on lines +64 to +68
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

This tasks.whenTaskAdded block is redundant because android.aarMetadataCheck.enabled=false has already been added to gradle.properties. Furthermore, disabling this check is a workaround for the SDK version mismatch between the app and its modules. It is recommended to resolve the underlying issue by aligning the compileSdk versions instead.


dependencies {

implementation(libs.androidx.core.ktx)
Expand All @@ -81,18 +87,7 @@ dependencies {
ksp(libs.hilt.compiler)

implementation(project(":ui-component"))
implementation(project(":samples:gemini-multimodal"))
implementation(project(":samples:gemini-chatbot"))
implementation(project(":samples:genai-summarization"))
implementation(project(":samples:genai-image-description"))
implementation(project(":samples:genai-writing-assistance"))
implementation(project(":samples:nanobanana"))
implementation(project(":samples:magic-selfie"))
implementation(project(":samples:gemini-video-summarization"))
implementation(project(":samples:gemini-live-todo"))
implementation(project(":samples:gemini-video-metadata-creation"))
implementation(project(":samples:gemini-image-chat"))
implementation(project(":samples:gemini-hybrid"))

testImplementation(libs.junit)
androidTestImplementation(libs.androidx.junit)
Expand Down
5 changes: 5 additions & 0 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,11 @@
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="androidx.xr.projected.CATEGORY_PROJECTED"/>
<category android:name="android.intent.category.XR_PROJECTED_LAUNCHER"/>
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.XR_PROJECTED_LAUNCHER"/>
</intent-filter>
Comment on lines 43 to 51
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The second <intent-filter> is redundant. A single filter can contain multiple categories, and an intent matches if the filter contains all categories specified in the intent. The first filter (lines 43-47) already includes both androidx.xr.projected.CATEGORY_PROJECTED and android.intent.category.XR_PROJECTED_LAUNCHER, making the second one unnecessary.

Suggested change
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="androidx.xr.projected.CATEGORY_PROJECTED"/>
<category android:name="android.intent.category.XR_PROJECTED_LAUNCHER"/>
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.XR_PROJECTED_LAUNCHER"/>
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="androidx.xr.projected.CATEGORY_PROJECTED"/>
<category android:name="android.intent.category.XR_PROJECTED_LAUNCHER"/>
</intent-filter>

</activity>
</application>
Expand Down
110 changes: 0 additions & 110 deletions app/src/main/java/com/android/ai/catalog/domain/SampleCatalog.kt
Original file line number Diff line number Diff line change
Expand Up @@ -22,123 +22,13 @@ import androidx.annotation.StringRes
import androidx.compose.runtime.Composable
import androidx.compose.ui.graphics.Color
import com.android.ai.catalog.R
import com.android.ai.samples.geminichatbot.GeminiChatbotScreen
import com.android.ai.samples.geminiimagechat.GeminiImageChatScreen
import com.android.ai.samples.geminilivetodo.ui.TodoScreen
import com.android.ai.samples.geminimultimodal.ui.GeminiMultimodalScreen
import com.android.ai.samples.geminivideometadatacreation.ui.VideoMetadataCreationScreen
import com.android.ai.samples.geminivideosummary.ui.VideoSummarizationScreen
import com.android.ai.samples.genai_image_description.GenAIImageDescriptionScreen
import com.android.ai.samples.genai_summarization.GenAISummarizationScreen
import com.android.ai.samples.genai_writing_assistance.GenAIWritingAssistanceScreen
import com.android.ai.samples.geminihybrid.GeminiHybridScreen
import com.android.ai.samples.nanobanana.ui.NanobananaScreen
import com.android.ai.samples.magicselfie.ui.MagicSelfieScreen
import com.android.ai.theme.extendedColorScheme
import com.google.firebase.ai.type.PublicPreviewAPI

@OptIn(PublicPreviewAPI::class)
@RequiresPermission(Manifest.permission.RECORD_AUDIO)
val sampleCatalog = listOf(
SampleCatalogItem(
title = R.string.gemini_hybrid_sample_list_title,
description = R.string.gemini_hybrid_sample_list_description,
route = "GeminiHybridScreen",
sampleEntryScreen = { GeminiHybridScreen() },
tags = listOf(SampleTags.GEMINI_NANO, SampleTags.GEMINI_FLASH, SampleTags.ML_KIT, SampleTags.FIREBASE),
needsFirebase = true,
keyArt = R.drawable.img_keyart_text,
isFeatured = true,
),
SampleCatalogItem(
title = R.string.gemini_image_chat_list_title,
description = R.string.gemini_image_chat_list_description,
route = "GeminiImageChatScreen",
sampleEntryScreen = { GeminiImageChatScreen() },
tags = listOf(SampleTags.GEMINI_FLASH, SampleTags.FIREBASE),
keyArt = R.drawable.img_keyart_chatbot,
needsFirebase = true,
isFeatured = true,
),
SampleCatalogItem(
title = R.string.gemini_multimodal_sample_list_title,
description = R.string.gemini_multimodal_sample_list_description,
route = "GeminiMultimodalScreen",
sampleEntryScreen = { GeminiMultimodalScreen() },
tags = listOf(SampleTags.GEMINI_FLASH, SampleTags.FIREBASE),
needsFirebase = true,
isFeatured = false,
keyArt = R.drawable.img_keyart_multimodal,
),
SampleCatalogItem(
title = R.string.gemini_chatbot_sample_title,
description = R.string.gemini_chatbot_sample_description,
route = "GeminiChitchatScreen",
sampleEntryScreen = { GeminiChatbotScreen() },
tags = listOf(SampleTags.GEMINI_FLASH, SampleTags.FIREBASE),
needsFirebase = true,
keyArt = R.drawable.img_keyart_chatbot,
),
SampleCatalogItem(
title = R.string.genai_summarization_sample_list_title,
description = R.string.genai_summarization_sample_list_description,
route = "GenAISummarizationScreen",
sampleEntryScreen = { GenAISummarizationScreen() },
tags = listOf(SampleTags.GEMINI_NANO, SampleTags.ML_KIT),
keyArt = R.drawable.img_keyart_summary,
),
SampleCatalogItem(
title = R.string.genai_image_description_sample_list_title,
description = R.string.genai_image_description_sample_list_description,
route = "GenAIImageDescriptionScreen",
sampleEntryScreen = { GenAIImageDescriptionScreen() },
tags = listOf(SampleTags.GEMINI_NANO, SampleTags.ML_KIT),
keyArt = R.drawable.img_keyart_img_desc,
),
SampleCatalogItem(
title = R.string.genai_writing_assistance_sample_list_title,
description = R.string.genai_writing_assistance_sample_list_description,
route = "GenAIWritingAssistanceScreen",
sampleEntryScreen = { GenAIWritingAssistanceScreen() },
tags = listOf(SampleTags.GEMINI_NANO, SampleTags.ML_KIT),
keyArt = R.drawable.img_keyart_text,
),
SampleCatalogItem(
title = R.string.nanobanana_sample_list_title,
description = R.string.nanobanana_sample_list_description,
route = "NanobananaImageGenerationScreen",
sampleEntryScreen = { NanobananaScreen() },
tags = listOf(SampleTags.GEMINI_FLASH, SampleTags.FIREBASE),
needsFirebase = true,
keyArt = R.drawable.img_keyart_imagen,
),
SampleCatalogItem(
title = R.string.magic_selfie_sample_list_title,
description = R.string.magic_selfie_sample_list_description,
route = "MagicSelfieScreen",
sampleEntryScreen = { MagicSelfieScreen() },
tags = listOf(SampleTags.GEMINI_FLASH, SampleTags.FIREBASE),
needsFirebase = true,
keyArt = R.drawable.img_keyart_magic_selfie,
),
SampleCatalogItem(
title = R.string.gemini_video_summarization_sample_list_title,
description = R.string.gemini_video_summarization_sample_list_description,
route = "VideoSummarizationScreen",
sampleEntryScreen = { VideoSummarizationScreen() },
tags = listOf(SampleTags.GEMINI_FLASH, SampleTags.FIREBASE, SampleTags.MEDIA3),
keyArt = R.drawable.img_keyart_video_summary,
needsFirebase = true,
),
SampleCatalogItem(
title = R.string.gemini_video_metadata_creation_sample_list_title,
description = R.string.gemini_video_metadata_creation_sample_list_description,
route = "VideoMetadataCreationScreen",
sampleEntryScreen = { VideoMetadataCreationScreen() },
tags = listOf(SampleTags.GEMINI_FLASH, SampleTags.FIREBASE, SampleTags.MEDIA3),
needsFirebase = true,
keyArt = R.drawable.img_keyart_video_summary,
),
SampleCatalogItem(
title = R.string.gemini_live_todo_list_title,
description = R.string.gemini_live_todo_list_description,
Expand Down
7 changes: 7 additions & 0 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,13 @@ plugins {

subprojects {
apply(plugin = "com.diffplug.spotless")

tasks.withType<org.jetbrains.kotlin.gradle.tasks.KotlinCompile>().configureEach {
kotlinOptions {
jvmTarget = "17"
}
}

configure<com.diffplug.gradle.spotless.SpotlessExtension> {
kotlin {
target("**/*.kt")
Expand Down
3 changes: 1 addition & 2 deletions gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -32,5 +32,4 @@ android.uniquePackageNames=false
android.dependency.useConstraints=true
android.r8.strictFullModeForKeepRules=false
android.r8.optimizedResourceShrinking=false
android.builtInKotlin=false
android.newDsl=false
android.aarMetadataCheck.enabled=false
10 changes: 6 additions & 4 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
[versions]
agp = "9.2.0"
agp = "8.9.1"
coilCompose = "3.1.0"
firebaseAiOndevice = "16.0.0-beta01"
firebaseBom = "34.11.0"
lifecycleRuntimeCompose = "2.9.1"
mlkitGenAi = "1.0.0-beta1"
kotlin = "2.2.10"
kotlin = "2.1.0"
coreKtx = "1.15.0"
junit = "4.13.2"
junitVersion = "1.2.1"
Expand All @@ -14,7 +14,7 @@ kotlinxCoroutinesGuava = "1.10.2"
kotlinxSerializationJson = "1.6.2"
lifecycleRuntimeKtx = "2.8.7"
activityCompose = "1.10.1"
composeBom = "2025.06.01"
composeBom = "2026.03.01"
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The composeBom version 2026.03.01 appears to be a typo, as the year 2026 is in the future. This will likely cause dependency resolution failures. Please verify and correct it to a valid version (e.g., 2025.02.00 or the intended 2025 release).

navigationCompose = "2.9.0"
navigationRuntimeKtx = "2.9.0"
appcompat = "1.7.0"
Expand All @@ -36,7 +36,7 @@ uiTextGoogleFonts = "1.8.1"
exifinterface = "1.4.1"
material3WindowSizeClass = "1.3.2"
richtext = "1.0.0-alpha02"
glimmer = "1.0.0-alpha12"
glimmer = "1.0.0-alpha11"
projected = "1.0.0-alpha07"

[libraries]
Expand All @@ -51,6 +51,7 @@ genai-image-description = { module = "com.google.mlkit:genai-image-description",
genai-proofreading = { module = "com.google.mlkit:genai-proofreading", version.ref = "mlkitGenAi" }
genai-rewrite = { module = "com.google.mlkit:genai-rewriting", version.ref = "mlkitGenAi" }
genai-summarization = { module = "com.google.mlkit:genai-summarization", version.ref = "mlkitGenAi" }
mlkit-segmentation = { module = "com.google.android.gms:play-services-mlkit-subject-segmentation", version.ref = "mlkitSegmentation" }
junit = { group = "junit", name = "junit", version.ref = "junit" }
androidx-junit = { group = "androidx.test.ext", name = "junit", version.ref = "junitVersion" }
androidx-espresso-core = { group = "androidx.test.espresso", name = "espresso-core", version.ref = "espressoCore" }
Expand Down Expand Up @@ -88,6 +89,7 @@ ui-tooling = { group = "androidx.compose.ui", name = "ui-tooling", version.ref =
androidx-lifecycle-viewmodel-android = { group = "androidx.lifecycle", name = "lifecycle-viewmodel-android", version.ref = "lifecycleViewmodelAndroid" }
androidx-exifinterface = { group = "androidx.exifinterface", name = "exifinterface", version.ref = "exifinterface" }
androidx-xr-glimmer = { group = "androidx.xr.glimmer", name = "glimmer", version.ref = "glimmer" }
androidx-xr-glimmer-google-fonts = { group = "androidx.xr.glimmer", name = "glimmer-google-fonts", version.ref = "glimmer" }
androidx-xr-projected = { group = "androidx.xr.projected", name = "projected", version.ref = "projected" }

[plugins]
Expand Down
3 changes: 2 additions & 1 deletion samples/gemini-live-todo/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ plugins {

android {
namespace = "com.android.ai.samples.geminilivetodo"
compileSdk = 36
compileSdk = 37

defaultConfig {
minSdk = 24
Expand Down Expand Up @@ -52,6 +52,7 @@ android {

dependencies {
implementation(libs.androidx.xr.glimmer)
implementation(libs.androidx.xr.glimmer.google.fonts)
implementation(libs.androidx.xr.projected)
implementation("com.google.firebase:firebase-ai:17.5.0")
implementation(libs.androidx.core.ktx)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,12 @@ import androidx.compose.ui.tooling.preview.Preview
import androidx.core.content.ContextCompat
import androidx.lifecycle.lifecycleScope
import androidx.xr.glimmer.GlimmerTheme
import androidx.xr.glimmer.googlefonts.createGoogleSansFlexTypography
import com.android.ai.samples.geminilivetodo.ui.AudioExperience
import com.android.ai.samples.geminilivetodo.ui.GlimmerTodoScreen
import com.android.ai.samples.geminilivetodo.ui.TodoScreenViewModel
import androidx.compose.ui.ComposeUiFlags
import androidx.compose.ui.ExperimentalComposeUiApi
import androidx.xr.projected.ProjectedDeviceController
import androidx.xr.projected.ProjectedDeviceController.Capability
import androidx.xr.projected.ProjectedDisplayController
Expand Down Expand Up @@ -57,9 +60,10 @@ class GlassesActivity : ComponentActivity() {
setupContent()
}

@OptIn(ExperimentalProjectedApi::class)
@OptIn(ExperimentalComposeUiApi::class, ExperimentalProjectedApi::class)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
ComposeUiFlags.isInitialFocusOnFocusableAvailable = true

viewModel.initializeGeminiLive(this)

Expand Down Expand Up @@ -97,16 +101,20 @@ class GlassesActivity : ComponentActivity() {
}
}

@OptIn(ExperimentalProjectedApi::class)
private fun setupContent() {
setContent {
GlimmerTheme {
RootScreen(
isGranted = isPermissionsGranted,
isDisplayCapable = isDisplayCapable,
areVisualsOn = areVisualsOn,
viewModel = viewModel
)
}
GlimmerTheme(
typography = createGoogleSansFlexTypography(),
content = {
RootScreen(
isGranted = isPermissionsGranted,
isDisplayCapable = isDisplayCapable,
areVisualsOn = areVisualsOn,
viewModel = viewModel
)
}
)
}
}

Expand All @@ -121,6 +129,13 @@ class GlassesActivity : ComponentActivity() {
)
)
}

override fun onStop() {
super.onStop()
// Release high-drain resources (camera, mic, sensors)
// to prevent battery drain
viewModel.stopLiveSession()
}
}


Expand Down Expand Up @@ -150,12 +165,15 @@ fun RootScreen(
@Preview(showBackground = true)
@Composable
fun PreviewRootScreen() {
GlimmerTheme {
RootScreen(
isGranted = false,
isDisplayCapable = true,
areVisualsOn = true,
viewModel = TodoScreenViewModel(com.android.ai.samples.geminilivetodo.data.TodoRepository())
)
}
}
GlimmerTheme(
typography = createGoogleSansFlexTypography(),
content = {
RootScreen(
isGranted = false,
isDisplayCapable = true,
areVisualsOn = true,
viewModel = TodoScreenViewModel(com.android.ai.samples.geminilivetodo.data.TodoRepository())
)
}
)
}
Loading