mirror of
https://github.com/google-ai-edge/gallery.git
synced 2025-07-17 11:46:39 -04:00
[gallery] add Analytics events: app_open, capability_select, generate_action, resource_link_click
PiperOrigin-RevId: 781122232
This commit is contained in:
parent
b960b28ea9
commit
3559cf6e43
7 changed files with 93 additions and 16 deletions
|
@ -0,0 +1,36 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2025 Google LLC
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.google.ai.edge.gallery
|
||||||
|
|
||||||
|
import android.util.Log
|
||||||
|
import com.google.firebase.analytics.FirebaseAnalytics
|
||||||
|
import com.google.firebase.analytics.ktx.analytics
|
||||||
|
import com.google.firebase.ktx.Firebase
|
||||||
|
|
||||||
|
private var hasLoggedAnalyticsWarning = false
|
||||||
|
|
||||||
|
val firebaseAnalytics: FirebaseAnalytics?
|
||||||
|
get() =
|
||||||
|
runCatching { Firebase.analytics }
|
||||||
|
.onFailure { exception ->
|
||||||
|
// Firebase.analytics can throw an exception if goolgle-services is not set up, e.g.,
|
||||||
|
// missing google-services.json.
|
||||||
|
if (!hasLoggedAnalyticsWarning) {
|
||||||
|
Log.w("AGAnalyticsFirebase", "Firebase Analytics is not available", exception)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.getOrNull()
|
|
@ -18,7 +18,6 @@ package com.google.ai.edge.gallery
|
||||||
|
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.util.Log
|
|
||||||
import android.view.WindowManager
|
import android.view.WindowManager
|
||||||
import androidx.activity.ComponentActivity
|
import androidx.activity.ComponentActivity
|
||||||
import androidx.activity.compose.setContent
|
import androidx.activity.compose.setContent
|
||||||
|
@ -26,31 +25,20 @@ import androidx.activity.enableEdgeToEdge
|
||||||
import androidx.compose.foundation.layout.fillMaxSize
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
import androidx.compose.material3.Surface
|
import androidx.compose.material3.Surface
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.core.os.bundleOf
|
||||||
import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen
|
import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen
|
||||||
import com.google.ai.edge.gallery.ui.theme.GalleryTheme
|
import com.google.ai.edge.gallery.ui.theme.GalleryTheme
|
||||||
import com.google.firebase.analytics.FirebaseAnalytics
|
import com.google.firebase.analytics.FirebaseAnalytics
|
||||||
import com.google.firebase.analytics.ktx.analytics
|
|
||||||
import com.google.firebase.ktx.Firebase
|
|
||||||
import dagger.hilt.android.AndroidEntryPoint
|
import dagger.hilt.android.AndroidEntryPoint
|
||||||
|
|
||||||
@AndroidEntryPoint
|
@AndroidEntryPoint
|
||||||
class MainActivity : ComponentActivity() {
|
class MainActivity : ComponentActivity() {
|
||||||
|
|
||||||
private var firebaseAnalytics: FirebaseAnalytics? = null
|
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
firebaseAnalytics =
|
super.onCreate(savedInstanceState)
|
||||||
runCatching { Firebase.analytics }
|
|
||||||
.onFailure { exception ->
|
|
||||||
// Firebase.analytics can throw an exception if goolgle-services is not set up, e.g.,
|
|
||||||
// missing google-services.json.
|
|
||||||
Log.w(TAG, "Firebase Analytics is not available", exception)
|
|
||||||
}
|
|
||||||
.getOrNull()
|
|
||||||
|
|
||||||
installSplashScreen()
|
installSplashScreen()
|
||||||
|
|
||||||
super.onCreate(savedInstanceState)
|
|
||||||
enableEdgeToEdge()
|
enableEdgeToEdge()
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
|
||||||
// Fix for three-button nav not properly going edge-to-edge.
|
// Fix for three-button nav not properly going edge-to-edge.
|
||||||
|
@ -62,6 +50,19 @@ class MainActivity : ComponentActivity() {
|
||||||
window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
|
window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun onResume() {
|
||||||
|
super.onResume()
|
||||||
|
|
||||||
|
firebaseAnalytics?.logEvent(
|
||||||
|
FirebaseAnalytics.Event.APP_OPEN,
|
||||||
|
bundleOf(
|
||||||
|
"app_version" to BuildConfig.VERSION_NAME,
|
||||||
|
"os_version" to Build.VERSION.SDK_INT.toString(),
|
||||||
|
"device_model" to Build.MODEL,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private const val TAG = "AGMainActivity"
|
private const val TAG = "AGMainActivity"
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,6 +34,8 @@ import androidx.compose.ui.text.SpanStyle
|
||||||
import androidx.compose.ui.text.style.TextAlign
|
import androidx.compose.ui.text.style.TextAlign
|
||||||
import androidx.compose.ui.text.style.TextDecoration
|
import androidx.compose.ui.text.style.TextDecoration
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
|
import androidx.core.os.bundleOf
|
||||||
|
import com.google.ai.edge.gallery.firebaseAnalytics
|
||||||
import com.google.ai.edge.gallery.ui.theme.customColors
|
import com.google.ai.edge.gallery.ui.theme.customColors
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
|
@ -62,7 +64,11 @@ fun ClickableLink(url: String, linkText: String, icon: ImageVector) {
|
||||||
text = annotatedText,
|
text = annotatedText,
|
||||||
textAlign = TextAlign.Center,
|
textAlign = TextAlign.Center,
|
||||||
style = MaterialTheme.typography.bodyLarge,
|
style = MaterialTheme.typography.bodyLarge,
|
||||||
modifier = Modifier.padding(start = 6.dp).clickable { uriHandler.openUri(url) },
|
modifier =
|
||||||
|
Modifier.padding(start = 6.dp).clickable {
|
||||||
|
uriHandler.openUri(url)
|
||||||
|
firebaseAnalytics?.logEvent("resource_link_click", bundleOf("link_destination" to url))
|
||||||
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -88,6 +88,7 @@ import androidx.compose.ui.graphics.Brush
|
||||||
import androidx.compose.ui.input.nestedscroll.nestedScroll
|
import androidx.compose.ui.input.nestedscroll.nestedScroll
|
||||||
import androidx.compose.ui.platform.LocalContext
|
import androidx.compose.ui.platform.LocalContext
|
||||||
import androidx.compose.ui.platform.LocalDensity
|
import androidx.compose.ui.platform.LocalDensity
|
||||||
|
import androidx.compose.ui.platform.LocalUriHandler
|
||||||
import androidx.compose.ui.platform.LocalWindowInfo
|
import androidx.compose.ui.platform.LocalWindowInfo
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
import androidx.compose.ui.text.LinkAnnotation
|
import androidx.compose.ui.text.LinkAnnotation
|
||||||
|
@ -100,11 +101,13 @@ import androidx.compose.ui.text.style.TextDecoration
|
||||||
import androidx.compose.ui.text.withLink
|
import androidx.compose.ui.text.withLink
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.compose.ui.unit.sp
|
import androidx.compose.ui.unit.sp
|
||||||
|
import androidx.core.os.bundleOf
|
||||||
import com.google.ai.edge.gallery.GalleryTopAppBar
|
import com.google.ai.edge.gallery.GalleryTopAppBar
|
||||||
import com.google.ai.edge.gallery.R
|
import com.google.ai.edge.gallery.R
|
||||||
import com.google.ai.edge.gallery.data.AppBarAction
|
import com.google.ai.edge.gallery.data.AppBarAction
|
||||||
import com.google.ai.edge.gallery.data.AppBarActionType
|
import com.google.ai.edge.gallery.data.AppBarActionType
|
||||||
import com.google.ai.edge.gallery.data.Task
|
import com.google.ai.edge.gallery.data.Task
|
||||||
|
import com.google.ai.edge.gallery.firebaseAnalytics
|
||||||
import com.google.ai.edge.gallery.proto.ImportedModel
|
import com.google.ai.edge.gallery.proto.ImportedModel
|
||||||
import com.google.ai.edge.gallery.ui.common.TaskIcon
|
import com.google.ai.edge.gallery.ui.common.TaskIcon
|
||||||
import com.google.ai.edge.gallery.ui.common.getTaskBgColor
|
import com.google.ai.edge.gallery.ui.common.getTaskBgColor
|
||||||
|
@ -334,17 +337,24 @@ private fun TaskList(
|
||||||
val screenHeightDp = remember { with(density) { windowInfo.containerSize.height.toDp() } }
|
val screenHeightDp = remember { with(density) { windowInfo.containerSize.height.toDp() } }
|
||||||
val sizeFraction = remember { ((screenWidthDp - 360.dp) / (410.dp - 360.dp)).coerceIn(0f, 1f) }
|
val sizeFraction = remember { ((screenWidthDp - 360.dp) / (410.dp - 360.dp)).coerceIn(0f, 1f) }
|
||||||
val linkColor = MaterialTheme.customColors.linkColor
|
val linkColor = MaterialTheme.customColors.linkColor
|
||||||
|
val url = "https://huggingface.co/litert-community"
|
||||||
|
val uriHandler = LocalUriHandler.current
|
||||||
|
|
||||||
val introText = buildAnnotatedString {
|
val introText = buildAnnotatedString {
|
||||||
append("Welcome to Google AI Edge Gallery! Explore a world of amazing on-device models from ")
|
append("Welcome to Google AI Edge Gallery! Explore a world of amazing on-device models from ")
|
||||||
|
// TODO: Consolidate the link clicking logic into ui/common/ClickableLink.kt.
|
||||||
withLink(
|
withLink(
|
||||||
link =
|
link =
|
||||||
LinkAnnotation.Url(
|
LinkAnnotation.Url(
|
||||||
url = "https://huggingface.co/litert-community", // Replace with the actual URL
|
url = url,
|
||||||
styles =
|
styles =
|
||||||
TextLinkStyles(
|
TextLinkStyles(
|
||||||
style = SpanStyle(color = linkColor, textDecoration = TextDecoration.Underline)
|
style = SpanStyle(color = linkColor, textDecoration = TextDecoration.Underline)
|
||||||
),
|
),
|
||||||
|
linkInteractionListener = { _ ->
|
||||||
|
firebaseAnalytics?.logEvent("resource_link_click", bundleOf("link_destination" to url))
|
||||||
|
uriHandler.openUri(url)
|
||||||
|
},
|
||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
append("LiteRT community")
|
append("LiteRT community")
|
||||||
|
|
|
@ -20,6 +20,8 @@ import android.graphics.Bitmap
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.platform.LocalContext
|
import androidx.compose.ui.platform.LocalContext
|
||||||
|
import androidx.core.os.bundleOf
|
||||||
|
import com.google.ai.edge.gallery.firebaseAnalytics
|
||||||
import com.google.ai.edge.gallery.ui.common.chat.ChatMessageAudioClip
|
import com.google.ai.edge.gallery.ui.common.chat.ChatMessageAudioClip
|
||||||
import com.google.ai.edge.gallery.ui.common.chat.ChatMessageImage
|
import com.google.ai.edge.gallery.ui.common.chat.ChatMessageImage
|
||||||
import com.google.ai.edge.gallery.ui.common.chat.ChatMessageText
|
import com.google.ai.edge.gallery.ui.common.chat.ChatMessageText
|
||||||
|
@ -132,6 +134,11 @@ fun ChatViewWrapper(
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
firebaseAnalytics?.logEvent(
|
||||||
|
"generate_action",
|
||||||
|
bundleOf("capability_name" to viewModel.task.type.toString(), "model_id" to model.name),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onRunAgainClicked = { model, message ->
|
onRunAgainClicked = { model, message ->
|
||||||
|
|
|
@ -43,8 +43,10 @@ import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.draw.alpha
|
import androidx.compose.ui.draw.alpha
|
||||||
import androidx.compose.ui.platform.LocalContext
|
import androidx.compose.ui.platform.LocalContext
|
||||||
import androidx.compose.ui.platform.LocalLayoutDirection
|
import androidx.compose.ui.platform.LocalLayoutDirection
|
||||||
|
import androidx.core.os.bundleOf
|
||||||
import com.google.ai.edge.gallery.data.ModelDownloadStatusType
|
import com.google.ai.edge.gallery.data.ModelDownloadStatusType
|
||||||
import com.google.ai.edge.gallery.data.TASK_LLM_PROMPT_LAB
|
import com.google.ai.edge.gallery.data.TASK_LLM_PROMPT_LAB
|
||||||
|
import com.google.ai.edge.gallery.firebaseAnalytics
|
||||||
import com.google.ai.edge.gallery.ui.common.ErrorDialog
|
import com.google.ai.edge.gallery.ui.common.ErrorDialog
|
||||||
import com.google.ai.edge.gallery.ui.common.ModelPageAppBar
|
import com.google.ai.edge.gallery.ui.common.ModelPageAppBar
|
||||||
import com.google.ai.edge.gallery.ui.common.chat.ModelDownloadStatusInfoPanel
|
import com.google.ai.edge.gallery.ui.common.chat.ModelDownloadStatusInfoPanel
|
||||||
|
@ -167,6 +169,14 @@ fun LlmSingleTurnScreen(
|
||||||
modelManagerViewModel = modelManagerViewModel,
|
modelManagerViewModel = modelManagerViewModel,
|
||||||
onSend = { fullPrompt ->
|
onSend = { fullPrompt ->
|
||||||
viewModel.generateResponse(model = selectedModel, input = fullPrompt)
|
viewModel.generateResponse(model = selectedModel, input = fullPrompt)
|
||||||
|
|
||||||
|
firebaseAnalytics?.logEvent(
|
||||||
|
"generate_action",
|
||||||
|
bundleOf(
|
||||||
|
"capability_name" to task.type.toString(),
|
||||||
|
"model_id" to selectedModel.name,
|
||||||
|
),
|
||||||
|
)
|
||||||
},
|
},
|
||||||
onStopButtonClicked = { model -> viewModel.stopResponse(model = model) },
|
onStopButtonClicked = { model -> viewModel.stopResponse(model = model) },
|
||||||
modifier = Modifier.fillMaxSize(),
|
modifier = Modifier.fillMaxSize(),
|
||||||
|
|
|
@ -36,6 +36,7 @@ import androidx.compose.runtime.setValue
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.unit.IntOffset
|
import androidx.compose.ui.unit.IntOffset
|
||||||
import androidx.compose.ui.zIndex
|
import androidx.compose.ui.zIndex
|
||||||
|
import androidx.core.os.bundleOf
|
||||||
import androidx.hilt.navigation.compose.hiltViewModel
|
import androidx.hilt.navigation.compose.hiltViewModel
|
||||||
import androidx.lifecycle.Lifecycle
|
import androidx.lifecycle.Lifecycle
|
||||||
import androidx.lifecycle.LifecycleEventObserver
|
import androidx.lifecycle.LifecycleEventObserver
|
||||||
|
@ -54,6 +55,7 @@ import com.google.ai.edge.gallery.data.TASK_LLM_PROMPT_LAB
|
||||||
import com.google.ai.edge.gallery.data.Task
|
import com.google.ai.edge.gallery.data.Task
|
||||||
import com.google.ai.edge.gallery.data.TaskType
|
import com.google.ai.edge.gallery.data.TaskType
|
||||||
import com.google.ai.edge.gallery.data.getModelByName
|
import com.google.ai.edge.gallery.data.getModelByName
|
||||||
|
import com.google.ai.edge.gallery.firebaseAnalytics
|
||||||
import com.google.ai.edge.gallery.ui.home.HomeScreen
|
import com.google.ai.edge.gallery.ui.home.HomeScreen
|
||||||
import com.google.ai.edge.gallery.ui.llmchat.LlmAskAudioDestination
|
import com.google.ai.edge.gallery.ui.llmchat.LlmAskAudioDestination
|
||||||
import com.google.ai.edge.gallery.ui.llmchat.LlmAskAudioScreen
|
import com.google.ai.edge.gallery.ui.llmchat.LlmAskAudioScreen
|
||||||
|
@ -144,6 +146,11 @@ fun GalleryNavHost(
|
||||||
navigateToTaskScreen = { task ->
|
navigateToTaskScreen = { task ->
|
||||||
pickedTask = task
|
pickedTask = task
|
||||||
showModelManager = true
|
showModelManager = true
|
||||||
|
|
||||||
|
firebaseAnalytics?.logEvent(
|
||||||
|
"capability_select",
|
||||||
|
bundleOf("capability_name" to task.type.toString()),
|
||||||
|
)
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue