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
2 changes: 2 additions & 0 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ buildscript {
plugins {
id("splunk.spotless-conventions")
alias(libs.plugins.publishPlugin)
alias(libs.plugins.jetbrainsKotlinAndroid) apply false
alias(libs.plugins.compose) apply false
}

allprojects {
Expand Down
20 changes: 19 additions & 1 deletion gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,11 @@ opentelemetry-android = "0.4.0-alpha"
mockito = "5.12.0"
junit = "5.10.2"
spotless = "6.25.0"
kotlin = "2.0.0"
lifecycle-runtime-ktx = "2.8.1"
activity-compose = "1.9.0"
compose-bom = "2023.08.00"
navigationCompose = "2.7.7"

[libraries]
opentelemetry-instrumentation-bom = { module = "io.opentelemetry.instrumentation:opentelemetry-instrumentation-bom", version.ref = "opentelemetry-inst" }
Expand Down Expand Up @@ -53,11 +58,24 @@ android-plugin = "com.android.tools.build:gradle:8.5.0"
errorprone-plugin = "net.ltgt.gradle:gradle-errorprone-plugin:4.0.0"
nullaway-plugin = "net.ltgt.gradle:gradle-nullaway-plugin:2.0.0"
spotless-plugin = { module = "com.diffplug.spotless:spotless-plugin-gradle", version.ref = "spotless" }
androidx-lifecycle-runtime-ktx = { group = "androidx.lifecycle", name = "lifecycle-runtime-ktx", version.ref = "lifecycle-runtime-ktx" }
androidx-activity-compose = { group = "androidx.activity", name = "activity-compose", version.ref = "activity-compose" }
androidx-compose-bom = { group = "androidx.compose", name = "compose-bom", version.ref = "compose-bom" }
androidx-ui = { group = "androidx.compose.ui", name = "ui" }
androidx-ui-graphics = { group = "androidx.compose.ui", name = "ui-graphics" }
androidx-ui-tooling = { group = "androidx.compose.ui", name = "ui-tooling" }
androidx-ui-tooling-preview = { group = "androidx.compose.ui", name = "ui-tooling-preview" }
androidx-ui-test-manifest = { group = "androidx.compose.ui", name = "ui-test-manifest" }
androidx-ui-test-junit4 = { group = "androidx.compose.ui", name = "ui-test-junit4" }
androidx-material3 = { group = "androidx.compose.material3", name = "material3" }
androidx-navigation-compose = { group = "androidx.navigation", name = "navigation-compose", version.ref = "navigationCompose" }

[bundles]
mocking = ["mockito-core", "mockito-junit-jupiter"]
junit = ["junit-jupiter-api", "junit-jupiter-engine", "junit-vintage-engine"]

[plugins]
spotless = { id = "com.diffplug.spotless", version.ref = "spotless" }
publishPlugin = { id = "io.github.gradle-nexus.publish-plugin", version = "2.0.0" }
publishPlugin = { id = "io.github.gradle-nexus.publish-plugin", version = "2.0.0" }
jetbrainsKotlinAndroid = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" }
compose = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" }
30 changes: 30 additions & 0 deletions sample-app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ import java.util.Properties

plugins {
id("com.android.application")
alias(libs.plugins.jetbrainsKotlinAndroid)
alias(libs.plugins.compose)
}

val localProperties = Properties()
Expand All @@ -22,12 +24,16 @@ android {
versionName = "1.0"

testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
vectorDrawables {
useSupportLibrary = true
}
}

buildFeatures {
dataBinding = true
viewBinding = true
buildConfig = true
compose = true
}

buildTypes {
Expand All @@ -50,13 +56,35 @@ android {
sourceCompatibility(JavaVersion.VERSION_1_8)
targetCompatibility(JavaVersion.VERSION_1_8)
}
kotlinOptions {
jvmTarget = "1.8"
}
packaging {
resources {
excludes += "/META-INF/{AL2.0,LGPL2.1}"
}
}
}

composeCompiler {
enableStrongSkippingMode = true
}

dependencies {
api(platform(libs.opentelemetry.instrumentation.bom))

implementation(project(":splunk-otel-android"))
implementation(project(":splunk-otel-android-volley"))
implementation(libs.androidx.lifecycle.runtime.ktx)
implementation(libs.androidx.activity.compose)
implementation(platform(libs.androidx.compose.bom))
implementation(libs.androidx.ui)
implementation(libs.androidx.ui.graphics)
implementation(libs.androidx.ui.tooling.preview)
implementation(libs.androidx.material3)
implementation(libs.androidx.navigation.compose)
androidTestImplementation(platform(libs.androidx.compose.bom))
androidTestImplementation(libs.androidx.ui.test.junit4)

coreLibraryDesugaring(libs.desugarJdkLibs)

Expand All @@ -71,4 +99,6 @@ dependencies {
testImplementation(libs.bundles.junit)
androidTestImplementation(libs.androidx.test.core)
androidTestImplementation(libs.androidx.junit)
debugImplementation(libs.androidx.ui.tooling)
debugImplementation(libs.androidx.ui.test.manifest)
}
18 changes: 11 additions & 7 deletions sample-app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -1,34 +1,38 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">

<uses-permission android:name="android.permission.READ_PHONE_STATE" />

<!-- for location tracking -->
<uses-permission android:name="android.permission.READ_PHONE_STATE" /> <!-- for location tracking -->
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />

<application
android:name=".SampleApplication"
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:name="com.splunk.android.sample.SampleApplication"
android:theme="@style/Theme.SplunkRUMSampleApp">
<activity
android:name=".JetpackComposeActivity"
android:exported="false"
android:label="@string/title_activity_jetpack_compose"
android:theme="@style/Theme.SplunkRUMSampleApp" />
<activity
android:name=".MainActivity"
android:theme="@style/Theme.SplunkRUMSampleApp.NoActionBar"
android:exported="true">
android:exported="true"
android:theme="@style/Theme.SplunkRUMSampleApp.NoActionBar">
<intent-filter>
<action android:name="android.intent.action.MAIN" />

<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>

<service
android:name=".SplunkBackgroundService"
android:exported="false"
android:process=":my_service_process"/>
android:process=":my_service_process" />
</application>

</manifest>
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import static io.opentelemetry.api.common.AttributeKey.longKey;

import android.annotation.SuppressLint;
import android.content.Intent;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
Expand Down Expand Up @@ -80,6 +81,12 @@ public void onViewCreated(@NonNull View view, Bundle savedInstanceState) {
NavHostFragment.findNavController(FirstFragment.this)
.navigate(R.id.action_FirstFragment_to_SecondFragment));

binding.buttonJcompose.setOnClickListener(
v -> {
startActivity(
new Intent(this.getView().getContext(), JetpackComposeActivity.class));
});

binding.crash.setOnClickListener(v -> multiThreadCrashing());

binding.httpMe.setOnClickListener(
Expand Down Expand Up @@ -180,18 +187,6 @@ public LiveData<String> getSessionId() {
return sessionId;
}

@Override
public void onDestroyView() {
super.onDestroyView();
binding = null;
}

@Override
public void onResume() {
super.onResume();
sessionId.postValue(splunkRum.getRumSessionId());
}

@SuppressLint("AllowAllHostnameVerifier")
private Call.Factory buildOkHttpClient(SplunkRum splunkRum) {
// grab the default executor service that okhttp uses, and wrap it with one that will
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
package com.splunk.android.sample

import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.activity.enableEdgeToEdge
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.Button
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.ui.Modifier
import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable
import androidx.navigation.compose.currentBackStackEntryAsState
import androidx.navigation.compose.rememberNavController
import com.splunk.rum.SplunkRum

class JetpackComposeActivity : ComponentActivity() {
private var lastRoute: String? = null

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
enableEdgeToEdge()
setContent {
val navController = rememberNavController()
val currentBackEntry by navController.currentBackStackEntryAsState()
val currentRoute = currentBackEntry?.destination?.route

LaunchedEffect(currentRoute) {
if (currentRoute != null) {
lastRoute = currentRoute
SplunkRum.getInstance().experimentalSetScreenName(currentRoute)
}
}

Scaffold(modifier = Modifier.fillMaxSize()) { innerPadding ->
Column(
modifier = Modifier.padding(innerPadding)
) {
NavHost(navController = navController, startDestination = "view-a") {
composable("view-a") { ViewA(onNavigation = { path -> navController.navigate(path) }) }
composable("view-b") { ViewB(onNavigation = { path -> navController.navigate(path) }) }
}
}
}
}
}

override fun onDestroy() {
super.onDestroy()

// doubled to clear both the last view and the previous last view
SplunkRum.getInstance().experimentalSetScreenName(null)
SplunkRum.getInstance().experimentalSetScreenName(null)
}

override fun onResume() {
super.onResume()
if (lastRoute != null) {
SplunkRum.getInstance().experimentalSetScreenName(lastRoute, "Resumed")
}
}
}

@Composable
fun ViewA(onNavigation: (String) -> Unit) {
Column {
Text("View A")
Button(onClick = { onNavigation("view-b")}) {
Text("Go to B")
}
}
}

@Composable
fun ViewB(onNavigation: (String) -> Unit) {
Column {
Text("View B")
Button(onClick = { onNavigation("view-a")}) {
Text("Go to A")
}
}
}
6 changes: 6 additions & 0 deletions sample-app/src/main/res/layout/fragment_first.xml
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,12 @@
android:layout_height="wrap_content"
android:text="@string/next" />

<Button
android:id="@+id/button_jcompose"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/jcompose" />

<Button
android:id="@+id/crash"
android:layout_width="wrap_content"
Expand Down
2 changes: 2 additions & 0 deletions sample-app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
<string name="second_fragment_label">Second Fragment</string>
<string name="next">Next</string>
<string name="previous">Previous</string>
<string name="jcompose">Jetpack Compose Example</string>

<string name="hello_first_fragment">Hello first fragment</string>
<string name="hello_second_fragment">Hello second fragment. Arg: %1$s</string>
Expand Down Expand Up @@ -35,4 +36,5 @@
<string name="draw_speed_normally">Draw Normally</string>
<string name="draw_speed_slowly">Draw Slowly</string>
<string name="send_email">send email</string>
<string name="title_activity_jetpack_compose">JetpackComposeActivity</string>
</resources>
2 changes: 1 addition & 1 deletion sample-app/src/main/res/values/themes.xml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
<item name="colorSecondaryVariant">@color/teal_700</item>
<item name="colorOnSecondary">@color/black</item>
<!-- Status bar color. -->
<item name="android:statusBarColor" >?attr/colorPrimaryVariant</item>
<item name="android:statusBarColor">?attr/colorPrimaryVariant</item>
<!-- Customize your theme here. -->
</style>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ class NoOpSplunkRum extends SplunkRum {
// passing null values here is fine, they'll never get used anyway
@SuppressWarnings("NullAway")
private NoOpSplunkRum() {
super(OpenTelemetryRum.noop(), null);
super(OpenTelemetryRum.noop(), null, null);
}

@Override
Expand Down Expand Up @@ -79,4 +79,14 @@ public void integrateWithBrowserRum(WebView webView) {
void flushSpans() {
// no-op
}

@Override
public void experimentalSetScreenName(String screenName) {
// no-op
}

@Override
public void experimentalSetScreenName(String screenName, String spanType) {
// no-op
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ SplunkRum initialize(Looper mainLooper) {
config.disableNetworkChangeMonitoring();
}

config.disableScreenAttributes();
OpenTelemetryRumBuilder otelRumBuilder = OpenTelemetryRum.builder(application, config);

otelRumBuilder.mergeResource(createSplunkResource());
Expand Down Expand Up @@ -193,6 +194,12 @@ SplunkRum initialize(Looper mainLooper) {
installCrashReporter(otelRumBuilder);
}

SettableScreenAttributesAppender screenAttributesAppender =
new SettableScreenAttributesAppender(visibleScreenTracker);
otelRumBuilder.addTracerProviderCustomizer(
(tracerProviderBuilder, app) ->
tracerProviderBuilder.addSpanProcessor(screenAttributesAppender));

// Lifecycle events instrumentation are always installed.
installLifecycleInstrumentations(otelRumBuilder, visibleScreenTracker);

Expand All @@ -204,7 +211,7 @@ SplunkRum initialize(Looper mainLooper) {
builder.getConfigFlags(),
openTelemetryRum.getOpenTelemetry().getTracer(RUM_TRACER_NAME));

return new SplunkRum(openTelemetryRum, globalAttributeSupplier);
return new SplunkRum(openTelemetryRum, globalAttributeSupplier, screenAttributesAppender);
}

@NonNull
Expand Down
Loading