commit
049750dd51
@ -0,0 +1,6 @@
|
||||
# https://editorconfig.org/
|
||||
# This configuration is used by ktlint when spotless invokes it
|
||||
|
||||
[*.{kt,kts}]
|
||||
ij_kotlin_allow_trailing_comma=true
|
||||
ij_kotlin_allow_trailing_comma_on_call_site=true
|
@ -0,0 +1,38 @@
|
||||
name: Android CI with GMD
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
pull_request:
|
||||
|
||||
jobs:
|
||||
|
||||
android-ci:
|
||||
runs-on: macos-12
|
||||
strategy:
|
||||
matrix:
|
||||
device-config: [ "pixel4api30aospatd", "pixelcapi30aospatd" ]
|
||||
|
||||
steps:
|
||||
- uses: actions/setup-java@v3
|
||||
with:
|
||||
distribution: 'zulu'
|
||||
java-version: '11'
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Setup Android SDK
|
||||
uses: android-actions/setup-android@v2
|
||||
|
||||
- name: Run instrumented tests with GMD
|
||||
run: ./gradlew cleanManagedDevices --unused-only &&
|
||||
./gradlew ${{ matrix.device-config }}DemoDebugAndroidTest -Dorg.gradle.workers.max=1
|
||||
-Pandroid.testoptions.manageddevices.emulator.gpu="swiftshader_indirect" -Pandroid.experimental.testOptions.managedDevices.emulator.showKernelLogging=true
|
||||
|
||||
- name: Upload test reports
|
||||
if: success() || failure()
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: test-reports
|
||||
path: |
|
||||
'**/*/build/reports/androidTests/'
|
@ -0,0 +1,2 @@
|
||||
# This file can be used to trigger an internal build by changing the number below
|
||||
3
|
@ -0,0 +1,125 @@
|
||||
{
|
||||
"project_info": {
|
||||
"project_number": "YourProjectId",
|
||||
"project_id": "abc",
|
||||
"storage_bucket": "abc"
|
||||
},
|
||||
"client": [
|
||||
{
|
||||
"client_info": {
|
||||
"mobilesdk_app_id": "Your:App:Id",
|
||||
"android_client_info": {
|
||||
"package_name": "com.google.samples.apps.nowinandroid"
|
||||
}
|
||||
},
|
||||
"oauth_client": [],
|
||||
"api_key": [
|
||||
{
|
||||
"current_key": "APlaceholderAPIKeyWith-ThirtyNineCharsX"
|
||||
}
|
||||
],
|
||||
"services": {
|
||||
"appinvite_service": {
|
||||
"other_platform_oauth_client": []
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"client_info": {
|
||||
"mobilesdk_app_id": "Your:App:Id",
|
||||
"android_client_info": {
|
||||
"package_name": "com.google.samples.apps.nowinandroid.demo.debug"
|
||||
}
|
||||
},
|
||||
"oauth_client": [],
|
||||
"api_key": [
|
||||
{
|
||||
"current_key": "APlaceholderAPIKeyWith-ThirtyNineCharsX"
|
||||
}
|
||||
],
|
||||
"services": {
|
||||
"appinvite_service": {
|
||||
"other_platform_oauth_client": []
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"client_info": {
|
||||
"mobilesdk_app_id": "Your:App:Id",
|
||||
"android_client_info": {
|
||||
"package_name": "com.google.samples.apps.nowinandroid.demo.benchmark"
|
||||
}
|
||||
},
|
||||
"oauth_client": [],
|
||||
"api_key": [
|
||||
{
|
||||
"current_key": "APlaceholderAPIKeyWith-ThirtyNineCharsX"
|
||||
}
|
||||
],
|
||||
"services": {
|
||||
"appinvite_service": {
|
||||
"other_platform_oauth_client": []
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"client_info": {
|
||||
"mobilesdk_app_id": "Your:App:Id",
|
||||
"android_client_info": {
|
||||
"package_name": "com.google.samples.apps.nowinandroid.benchmark"
|
||||
}
|
||||
},
|
||||
"oauth_client": [],
|
||||
"api_key": [
|
||||
{
|
||||
"current_key": "APlaceholderAPIKeyWith-ThirtyNineCharsX"
|
||||
}
|
||||
],
|
||||
"services": {
|
||||
"appinvite_service": {
|
||||
"other_platform_oauth_client": []
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"client_info": {
|
||||
"mobilesdk_app_id": "Your:App:Id",
|
||||
"android_client_info": {
|
||||
"package_name": "com.google.samples.apps.nowinandroid.debug"
|
||||
}
|
||||
},
|
||||
"oauth_client": [],
|
||||
"api_key": [
|
||||
{
|
||||
"current_key": "APlaceholderAPIKeyWith-ThirtyNineCharsX"
|
||||
}
|
||||
],
|
||||
"services": {
|
||||
"appinvite_service": {
|
||||
"other_platform_oauth_client": []
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"client_info": {
|
||||
"mobilesdk_app_id": "Your:App:Id",
|
||||
"android_client_info": {
|
||||
"package_name": "com.google.samples.apps.nowinandroid.demo"
|
||||
}
|
||||
},
|
||||
"oauth_client": [],
|
||||
"api_key": [
|
||||
{
|
||||
"current_key": "APlaceholderAPIKeyWith-ThirtyNineCharsX"
|
||||
}
|
||||
],
|
||||
"services": {
|
||||
"appinvite_service": {
|
||||
"other_platform_oauth_client": []
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
|
||||
"configuration_version": "1"
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,26 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright 2023 The Android Open Source Project
|
||||
|
||||
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.
|
||||
-->
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools">
|
||||
<application>
|
||||
<!-- Enable Firebase analytics for `prod` builds -->
|
||||
<meta-data
|
||||
tools:replace="android:value"
|
||||
android:name="firebase_analytics_collection_deactivated"
|
||||
android:value="false" />
|
||||
</application>
|
||||
</manifest>
|
@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Copyright 2022 The Android Open Source Project
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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.
|
||||
*/
|
||||
|
||||
import com.android.build.api.variant.ApplicationAndroidComponentsExtension
|
||||
import com.google.firebase.crashlytics.buildtools.gradle.CrashlyticsExtension
|
||||
import org.gradle.api.Plugin
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.api.artifacts.VersionCatalogsExtension
|
||||
import org.gradle.kotlin.dsl.configure
|
||||
import org.gradle.kotlin.dsl.dependencies
|
||||
import org.gradle.kotlin.dsl.getByType
|
||||
|
||||
class AndroidApplicationFirebaseConventionPlugin : Plugin<Project> {
|
||||
override fun apply(target: Project) {
|
||||
with(target) {
|
||||
with(pluginManager) {
|
||||
apply("com.google.gms.google-services")
|
||||
apply("com.google.firebase.firebase-perf")
|
||||
apply("com.google.firebase.crashlytics")
|
||||
}
|
||||
|
||||
val libs = extensions.getByType<VersionCatalogsExtension>().named("libs")
|
||||
dependencies {
|
||||
val bom = libs.findLibrary("firebase-bom").get()
|
||||
add("implementation", platform(bom))
|
||||
"implementation"(libs.findLibrary("firebase.analytics").get())
|
||||
"implementation"(libs.findLibrary("firebase.performance").get())
|
||||
"implementation"(libs.findLibrary("firebase.crashlytics").get())
|
||||
}
|
||||
|
||||
extensions.configure<ApplicationAndroidComponentsExtension> {
|
||||
finalizeDsl {
|
||||
it.buildTypes.forEach { buildType ->
|
||||
// Disable the Crashlytics mapping file upload. This feature should only be
|
||||
// enabled if a Firebase backend is available and configured in
|
||||
// google-services.json.
|
||||
buildType.configure<CrashlyticsExtension> {
|
||||
mappingFileUploadEnabled = false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,63 @@
|
||||
/*
|
||||
* Copyright 2022 The Android Open Source Project
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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.
|
||||
*/
|
||||
|
||||
import com.google.devtools.ksp.gradle.KspExtension
|
||||
import org.gradle.api.Plugin
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.api.artifacts.VersionCatalogsExtension
|
||||
import org.gradle.api.tasks.InputDirectory
|
||||
import org.gradle.api.tasks.PathSensitive
|
||||
import org.gradle.api.tasks.PathSensitivity
|
||||
import org.gradle.kotlin.dsl.configure
|
||||
import org.gradle.kotlin.dsl.dependencies
|
||||
import org.gradle.kotlin.dsl.getByType
|
||||
import org.gradle.process.CommandLineArgumentProvider
|
||||
import java.io.File
|
||||
|
||||
class AndroidRoomConventionPlugin : Plugin<Project> {
|
||||
|
||||
override fun apply(target: Project) {
|
||||
with(target) {
|
||||
pluginManager.apply("com.google.devtools.ksp")
|
||||
|
||||
extensions.configure<KspExtension> {
|
||||
// The schemas directory contains a schema file for each version of the Room database.
|
||||
// This is required to enable Room auto migrations.
|
||||
// See https://developer.android.com/reference/kotlin/androidx/room/AutoMigration.
|
||||
arg(RoomSchemaArgProvider(File(projectDir, "schemas")))
|
||||
}
|
||||
|
||||
val libs = extensions.getByType<VersionCatalogsExtension>().named("libs")
|
||||
dependencies {
|
||||
add("implementation", libs.findLibrary("room.runtime").get())
|
||||
add("implementation", libs.findLibrary("room.ktx").get())
|
||||
add("ksp", libs.findLibrary("room.compiler").get())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* https://issuetracker.google.com/issues/132245929
|
||||
* [Export schemas](https://developer.android.com/training/data-storage/room/migrating-db-versions#export-schemas)
|
||||
*/
|
||||
class RoomSchemaArgProvider(
|
||||
@get:InputDirectory
|
||||
@get:PathSensitive(PathSensitivity.RELATIVE)
|
||||
val schemaDir: File,
|
||||
) : CommandLineArgumentProvider {
|
||||
override fun asArguments() = listOf("room.schemaLocation=${schemaDir.path}")
|
||||
}
|
||||
}
|
@ -0,0 +1,63 @@
|
||||
/*
|
||||
* Copyright 2023 The Android Open Source Project
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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.samples.apps.nowinandroid
|
||||
|
||||
import com.android.build.api.dsl.CommonExtension
|
||||
import com.android.build.api.dsl.ManagedVirtualDevice
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.kotlin.dsl.invoke
|
||||
import java.util.Locale
|
||||
|
||||
/**
|
||||
* Configure project for Gradle managed devices
|
||||
*/
|
||||
internal fun configureGradleManagedDevices(
|
||||
commonExtension: CommonExtension<*, *, *, *>,
|
||||
) {
|
||||
val deviceConfigs = listOf(
|
||||
DeviceConfig("Pixel 4", 30, "aosp-atd"),
|
||||
DeviceConfig("Pixel 6", 31, "aosp"),
|
||||
DeviceConfig("Pixel C", 30, "aosp-atd"),
|
||||
)
|
||||
|
||||
commonExtension.testOptions {
|
||||
managedDevices {
|
||||
devices {
|
||||
deviceConfigs.forEach { deviceConfig ->
|
||||
maybeCreate(deviceConfig.taskName, ManagedVirtualDevice::class.java).apply {
|
||||
device = deviceConfig.device
|
||||
apiLevel = deviceConfig.apiLevel
|
||||
systemImageSource = deviceConfig.systemImageSource
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private data class DeviceConfig(
|
||||
val device: String,
|
||||
val apiLevel: Int,
|
||||
val systemImageSource: String,
|
||||
) {
|
||||
val taskName = buildString {
|
||||
append(device.toLowerCase(Locale.ROOT).replace(" ", ""))
|
||||
append("api")
|
||||
append(apiLevel.toString())
|
||||
append(systemImageSource.replace("-", ""))
|
||||
}
|
||||
}
|
@ -0,0 +1 @@
|
||||
/build
|
@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright 2023 The Android Open Source Project
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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.
|
||||
*/
|
||||
plugins {
|
||||
id("nowinandroid.android.library")
|
||||
id("nowinandroid.android.library.compose")
|
||||
id("nowinandroid.android.hilt")
|
||||
}
|
||||
|
||||
android {
|
||||
namespace = "com.google.samples.apps.nowinandroid.core.analytics"
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation(libs.kotlinx.coroutines.android)
|
||||
implementation(libs.androidx.compose.runtime)
|
||||
implementation(libs.androidx.core.ktx)
|
||||
|
||||
implementation(platform(libs.firebase.bom))
|
||||
implementation(libs.firebase.analytics)
|
||||
}
|
@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Copyright 2023 The Android Open Source Project
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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.samples.apps.nowinandroid.core.analytics
|
||||
|
||||
import dagger.Binds
|
||||
import dagger.Module
|
||||
import dagger.hilt.InstallIn
|
||||
import dagger.hilt.components.SingletonComponent
|
||||
|
||||
@Module
|
||||
@InstallIn(SingletonComponent::class)
|
||||
abstract class AnalyticsModule {
|
||||
@Binds
|
||||
abstract fun bindsAnalyticsHelper(analyticsHelperImpl: StubAnalyticsHelper): AnalyticsHelper
|
||||
}
|
@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Copyright 2023 The Android Open Source Project
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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.samples.apps.nowinandroid.core.analytics
|
||||
|
||||
/**
|
||||
* Represents an analytics event.
|
||||
*
|
||||
* @param type - the event type. Wherever possible use one of the standard
|
||||
* event `Types`, however, if there is no suitable event type already defined, a custom event can be
|
||||
* defined as long as it is configured in your backend analytics system (for example, by creating a
|
||||
* Firebase Analytics custom event).
|
||||
*
|
||||
* @param extras - list of parameters which supply additional context to the event. See `Param`.
|
||||
*/
|
||||
data class AnalyticsEvent(
|
||||
val type: String,
|
||||
val extras: List<Param> = emptyList(),
|
||||
) {
|
||||
// Standard analytics types.
|
||||
class Types {
|
||||
companion object {
|
||||
const val SCREEN_VIEW = "screen_view" // (extras: SCREEN_NAME)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A key-value pair used to supply extra context to an analytics event.
|
||||
*
|
||||
* @param key - the parameter key. Wherever possible use one of the standard `ParamKeys`,
|
||||
* however, if no suitable key is available you can define your own as long as it is configured
|
||||
* in your backend analytics system (for example, by creating a Firebase Analytics custom
|
||||
* parameter).
|
||||
*
|
||||
* @param value - the parameter value.
|
||||
*/
|
||||
data class Param(val key: String, val value: String)
|
||||
|
||||
// Standard parameter keys.
|
||||
class ParamKeys {
|
||||
companion object {
|
||||
const val SCREEN_NAME = "screen_name"
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,24 @@
|
||||
/*
|
||||
* Copyright 2023 The Android Open Source Project
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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.samples.apps.nowinandroid.core.analytics
|
||||
|
||||
/**
|
||||
* Implementation of AnalyticsHelper which does nothing. Useful for tests and previews.
|
||||
*/
|
||||
class NoOpAnalyticsHelper : AnalyticsHelper {
|
||||
override fun logEvent(event: AnalyticsEvent) = Unit
|
||||
}
|
@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright 2023 The Android Open Source Project
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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.samples.apps.nowinandroid.core.analytics
|
||||
|
||||
import android.util.Log
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
||||
private const val TAG = "StubAnalyticsHelper"
|
||||
|
||||
/**
|
||||
* An implementation of AnalyticsHelper just writes the events to logcat. Used in builds where no
|
||||
* analytics events should be sent to a backend.
|
||||
*/
|
||||
@Singleton
|
||||
class StubAnalyticsHelper @Inject constructor() : AnalyticsHelper {
|
||||
override fun logEvent(event: AnalyticsEvent) {
|
||||
Log.d(TAG, "Received analytics event: $event")
|
||||
}
|
||||
}
|
@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Copyright 2023 The Android Open Source Project
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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.samples.apps.nowinandroid.core.analytics
|
||||
|
||||
import androidx.compose.runtime.staticCompositionLocalOf
|
||||
|
||||
/**
|
||||
* Global key used to obtain access to the AnalyticsHelper through a CompositionLocal.
|
||||
*/
|
||||
val LocalAnalyticsHelper = staticCompositionLocalOf<AnalyticsHelper> {
|
||||
// Provide a default AnalyticsHelper which does nothing. This is so that tests and previews
|
||||
// do not have to provide one. For real app builds provide a different implementation.
|
||||
NoOpAnalyticsHelper()
|
||||
}
|
@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright 2023 The Android Open Source Project
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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.samples.apps.nowinandroid.core.analytics
|
||||
|
||||
import com.google.firebase.analytics.FirebaseAnalytics
|
||||
import com.google.firebase.analytics.ktx.analytics
|
||||
import com.google.firebase.ktx.Firebase
|
||||
import dagger.Binds
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import dagger.hilt.InstallIn
|
||||
import dagger.hilt.components.SingletonComponent
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Module
|
||||
@InstallIn(SingletonComponent::class)
|
||||
abstract class AnalyticsModule {
|
||||
@Binds
|
||||
abstract fun bindsAnalyticsHelper(analyticsHelperImpl: FirebaseAnalyticsHelper): AnalyticsHelper
|
||||
|
||||
companion object {
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideFirebaseAnalytics(): FirebaseAnalytics { return Firebase.analytics }
|
||||
}
|
||||
}
|
@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright 2023 The Android Open Source Project
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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.samples.apps.nowinandroid.core.analytics
|
||||
|
||||
import com.google.firebase.analytics.FirebaseAnalytics
|
||||
import com.google.firebase.analytics.ktx.logEvent
|
||||
import javax.inject.Inject
|
||||
|
||||
/**
|
||||
* Implementation of `AnalyticsHelper` which logs events to a Firebase backend.
|
||||
*/
|
||||
class FirebaseAnalyticsHelper @Inject constructor(
|
||||
private val firebaseAnalytics: FirebaseAnalytics,
|
||||
) : AnalyticsHelper {
|
||||
|
||||
override fun logEvent(event: AnalyticsEvent) {
|
||||
firebaseAnalytics.logEvent(event.type) {
|
||||
for (extra in event.extras) {
|
||||
// Truncate parameter keys and values according to firebase maximum length values.
|
||||
param(
|
||||
key = extra.key.take(40),
|
||||
value = extra.value.take(100),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,84 @@
|
||||
/*
|
||||
* Copyright 2023 The Android Open Source Project
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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.samples.apps.nowinandroid.core.data.repository
|
||||
|
||||
import com.google.samples.apps.nowinandroid.core.analytics.AnalyticsEvent
|
||||
import com.google.samples.apps.nowinandroid.core.analytics.AnalyticsEvent.Param
|
||||
import com.google.samples.apps.nowinandroid.core.analytics.AnalyticsHelper
|
||||
|
||||
fun AnalyticsHelper.logNewsResourceBookmarkToggled(newsResourceId: String, isBookmarked: Boolean) {
|
||||
val eventType = if (isBookmarked) "news_resource_saved" else "news_resource_unsaved"
|
||||
val paramKey = if (isBookmarked) "saved_news_resource_id" else "unsaved_news_resource_id"
|
||||
logEvent(
|
||||
AnalyticsEvent(
|
||||
type = eventType,
|
||||
extras = listOf(
|
||||
Param(key = paramKey, value = newsResourceId),
|
||||
),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
fun AnalyticsHelper.logTopicFollowToggled(followedTopicId: String, isFollowed: Boolean) {
|
||||
val eventType = if (isFollowed) "topic_followed" else "topic_unfollowed"
|
||||
val paramKey = if (isFollowed) "followed_topic_id" else "unfollowed_topic_id"
|
||||
logEvent(
|
||||
AnalyticsEvent(
|
||||
type = eventType,
|
||||
extras = listOf(
|
||||
Param(key = paramKey, value = followedTopicId),
|
||||
),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
fun AnalyticsHelper.logThemeChanged(themeName: String) =
|
||||
logEvent(
|
||||
AnalyticsEvent(
|
||||
type = "theme_changed",
|
||||
extras = listOf(
|
||||
Param(key = "theme_name", value = themeName),
|
||||
),
|
||||
),
|
||||
)
|
||||
|
||||
fun AnalyticsHelper.logDarkThemeConfigChanged(darkThemeConfigName: String) =
|
||||
logEvent(
|
||||
AnalyticsEvent(
|
||||
type = "dark_theme_config_changed",
|
||||
extras = listOf(
|
||||
Param(key = "dark_theme_config", value = darkThemeConfigName),
|
||||
),
|
||||
),
|
||||
)
|
||||
|
||||
fun AnalyticsHelper.logDynamicColorPreferenceChanged(useDynamicColor: Boolean) =
|
||||
logEvent(
|
||||
AnalyticsEvent(
|
||||
type = "dynamic_color_preference_changed",
|
||||
extras = listOf(
|
||||
Param(key = "dynamic_color_preference", value = useDynamicColor.toString()),
|
||||
),
|
||||
),
|
||||
)
|
||||
|
||||
fun AnalyticsHelper.logOnboardingStateChanged(shouldHideOnboarding: Boolean) {
|
||||
val eventType = if (shouldHideOnboarding) "onboarding_complete" else "onboarding_reset"
|
||||
logEvent(
|
||||
AnalyticsEvent(type = eventType),
|
||||
)
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue