From ed26d4b016e09f7437d4a98a9edbcb14a732eb65 Mon Sep 17 00:00:00 2001 From: Fadi George Date: Tue, 7 Apr 2026 10:21:11 -0700 Subject: [PATCH 1/4] chore: downgrade Kotlin from 2.2.0 to 1.9.25 --- OneSignalSDK/build.gradle | 2 +- .../onesignal/debug/internal/crash/OtelIntegrationTest.kt | 2 +- OneSignalSDK/onesignal/otel/build.gradle | 2 +- examples/demo/app/build.gradle.kts | 8 +++++--- examples/demo/build.gradle.kts | 2 +- 5 files changed, 9 insertions(+), 7 deletions(-) diff --git a/OneSignalSDK/build.gradle b/OneSignalSDK/build.gradle index c02338492..c70a36b00 100644 --- a/OneSignalSDK/build.gradle +++ b/OneSignalSDK/build.gradle @@ -14,7 +14,7 @@ buildscript { huaweiAgconnectVersion = '1.9.1.304' huaweiHMSPushVersion = '6.3.0.304' huaweiHMSLocationVersion = '4.0.0.300' - kotlinVersion = '2.2.0' + kotlinVersion = '1.9.25' dokkaVersion = '1.9.10' coroutinesVersion = '1.7.3' kotestVersion = '5.8.0' diff --git a/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/debug/internal/crash/OtelIntegrationTest.kt b/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/debug/internal/crash/OtelIntegrationTest.kt index f7cf09c7d..8eceeedcf 100644 --- a/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/debug/internal/crash/OtelIntegrationTest.kt +++ b/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/debug/internal/crash/OtelIntegrationTest.kt @@ -76,7 +76,7 @@ class OtelIntegrationTest : FunSpec({ put(identityModel) } - sharedPreferences.edit() + sharedPreferences!!.edit() .putString(PreferenceOneSignalKeys.MODEL_STORE_PREFIX + configNameSpace, configArray.toString()) .putString(PreferenceOneSignalKeys.MODEL_STORE_PREFIX + identityNameSpace, identityArray.toString()) .putString(PreferenceOneSignalKeys.PREFS_OS_INSTALL_ID, "test-install-id") diff --git a/OneSignalSDK/onesignal/otel/build.gradle b/OneSignalSDK/onesignal/otel/build.gradle index 15e093c7c..fcf55b2aa 100644 --- a/OneSignalSDK/onesignal/otel/build.gradle +++ b/OneSignalSDK/onesignal/otel/build.gradle @@ -36,7 +36,7 @@ android { kotlinOptions { jvmTarget = '1.8' - freeCompilerArgs += ['-module-name', namespace] + freeCompilerArgs += ['-module-name', namespace, '-Xskip-metadata-version-check'] } } diff --git a/examples/demo/app/build.gradle.kts b/examples/demo/app/build.gradle.kts index 91b2bdbdb..814d1204a 100644 --- a/examples/demo/app/build.gradle.kts +++ b/examples/demo/app/build.gradle.kts @@ -1,11 +1,9 @@ plugins { id("com.android.application") id("kotlin-android") - id("org.jetbrains.kotlin.plugin.compose") version "2.2.0" } -// Keep IDE sync stable even if root extra properties are unavailable. -val kotlinVersion: String = rootProject.findProperty("kotlinVersion") as? String ?: "2.2.0" +val kotlinVersion: String = rootProject.findProperty("kotlinVersion") as? String ?: "1.9.25" // Apply GMS or Huawei plugin based on build variant // Check at configuration time, not when task graph is ready @@ -37,6 +35,10 @@ android { compose = true } + composeOptions { + kotlinCompilerExtensionVersion = "1.5.15" + } + flavorDimensions += "default" productFlavors { diff --git a/examples/demo/build.gradle.kts b/examples/demo/build.gradle.kts index 351f435c2..159ff201c 100644 --- a/examples/demo/build.gradle.kts +++ b/examples/demo/build.gradle.kts @@ -1,7 +1,7 @@ // Top-level build file where you can add configuration options common to all sub-projects/modules. buildscript { - val kotlinVersion by extra("2.2.0") + val kotlinVersion by extra("1.9.25") repositories { google() mavenCentral() From b7cd7356c8c02c9fe765d550aab4aa3ed39c2209 Mon Sep 17 00:00:00 2001 From: Fadi George Date: Tue, 7 Apr 2026 10:32:59 -0700 Subject: [PATCH 2/4] docs: rename Activity to Screen in examples --- examples/build.md | 10 +++++----- examples/demo/GettingStarted.md | 2 +- examples/demo/app/src/main/AndroidManifest.xml | 2 +- .../java/com/onesignal/sdktest/ui/main/MainScreen.kt | 4 ++-- .../sdktest/ui/secondary/SecondaryActivity.kt | 4 ++-- examples/demo/app/src/main/res/values/strings.xml | 6 +++--- 6 files changed, 14 insertions(+), 14 deletions(-) diff --git a/examples/build.md b/examples/build.md index 8cf3617dd..b3d7ca60d 100644 --- a/examples/build.md +++ b/examples/build.md @@ -154,7 +154,7 @@ In MainViewModel.kt, implement observers: 11. **Triggers Section** (Add/Add Multiple/Remove Selected/Clear All - IN MEMORY ONLY) 12. **Track Event Section** (Track Event with JSON validation) 13. **Location Section** (Location Shared toggle, Prompt Location button) -14. **Next Activity Button** +14. **Next Screen Button** ### Prompt 2.1 - App Section @@ -374,12 +374,12 @@ Location Section: - PROMPT LOCATION button ``` -### Prompt 2.14 - Secondary Activity +### Prompt 2.14 - Secondary Screen ``` -Secondary Activity (launched by "Next Activity" button at bottom of main screen): -- Activity title: "Secondary Activity" -- Page content: centered text "Secondary Activity" using headlineMedium style +Secondary Screen (launched by "Next Screen" button at bottom of main screen): +- Screen title: "Secondary Screen" +- Page content: centered text "Secondary Screen" using headlineMedium style - Simple screen, no additional functionality needed ``` diff --git a/examples/demo/GettingStarted.md b/examples/demo/GettingStarted.md index 8d9f37a8a..56d4129db 100644 --- a/examples/demo/GettingStarted.md +++ b/examples/demo/GettingStarted.md @@ -145,7 +145,7 @@ Send a named **event** with optional JSON properties for advanced analytics. ### Location Toggle **location sharing** on or off and **prompt** for location permission. -### Secondary Activity +### Secondary Screen Navigate to a second screen with buttons to **simulate a crash** (`RuntimeException`) and **simulate an ANR** (10-second main-thread block) — useful for testing crash and ANR reporting. ### Log Viewer diff --git a/examples/demo/app/src/main/AndroidManifest.xml b/examples/demo/app/src/main/AndroidManifest.xml index 9d72e7e0e..450e5cae0 100644 --- a/examples/demo/app/src/main/AndroidManifest.xml +++ b/examples/demo/app/src/main/AndroidManifest.xml @@ -62,7 +62,7 @@ - + diff --git a/examples/demo/app/src/main/java/com/onesignal/sdktest/ui/main/MainScreen.kt b/examples/demo/app/src/main/java/com/onesignal/sdktest/ui/main/MainScreen.kt index a9c02609b..82dfc0118 100644 --- a/examples/demo/app/src/main/java/com/onesignal/sdktest/ui/main/MainScreen.kt +++ b/examples/demo/app/src/main/java/com/onesignal/sdktest/ui/main/MainScreen.kt @@ -263,9 +263,9 @@ fun MainScreen(viewModel: MainViewModel) { Spacer(modifier = Modifier.height(8.dp)) - // === NEXT ACTIVITY BUTTON === + // === NEXT SCREEN BUTTON === PrimaryButton( - text = "NEXT ACTIVITY", + text = "NEXT SCREEN", onClick = { context.startActivity(Intent(context, SecondaryActivity::class.java)) } diff --git a/examples/demo/app/src/main/java/com/onesignal/sdktest/ui/secondary/SecondaryActivity.kt b/examples/demo/app/src/main/java/com/onesignal/sdktest/ui/secondary/SecondaryActivity.kt index 0655dc843..451cea39e 100644 --- a/examples/demo/app/src/main/java/com/onesignal/sdktest/ui/secondary/SecondaryActivity.kt +++ b/examples/demo/app/src/main/java/com/onesignal/sdktest/ui/secondary/SecondaryActivity.kt @@ -42,7 +42,7 @@ class SecondaryActivity : ComponentActivity() { Scaffold( topBar = { CenterAlignedTopAppBar( - title = { Text("Secondary Activity", color = Color.White) }, + title = { Text("Secondary Screen", color = Color.White) }, navigationIcon = { IconButton(onClick = { finish() }) { Icon( @@ -67,7 +67,7 @@ class SecondaryActivity : ComponentActivity() { verticalArrangement = Arrangement.Center ) { Text( - text = "Secondary Activity", + text = "Secondary Screen", style = MaterialTheme.typography.headlineMedium ) diff --git a/examples/demo/app/src/main/res/values/strings.xml b/examples/demo/app/src/main/res/values/strings.xml index f230d4b29..c0e19fe3b 100644 --- a/examples/demo/app/src/main/res/values/strings.xml +++ b/examples/demo/app/src/main/res/values/strings.xml @@ -105,9 +105,9 @@ Send In-App Message - - NEXT ACTIVITY - Secondary Activity + + NEXT SCREEN + Secondary Screen External User Id From 89e5d68d7ae1b25d92f1ec3fad9e920aaea96437 Mon Sep 17 00:00:00 2001 From: Fadi George Date: Tue, 7 Apr 2026 10:52:23 -0700 Subject: [PATCH 3/4] refactor(test): remove nullable context variables in OtelIntegrationTest --- .../internal/crash/OtelIntegrationTest.kt | 207 +++++++++--------- 1 file changed, 101 insertions(+), 106 deletions(-) diff --git a/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/debug/internal/crash/OtelIntegrationTest.kt b/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/debug/internal/crash/OtelIntegrationTest.kt index 8eceeedcf..ad6827b33 100644 --- a/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/debug/internal/crash/OtelIntegrationTest.kt +++ b/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/debug/internal/crash/OtelIntegrationTest.kt @@ -35,133 +35,128 @@ private infix fun T.shouldBeOneOf(expected: List) { @RobolectricTest @Config(sdk = [Build.VERSION_CODES.O]) -class OtelIntegrationTest : FunSpec({ - var appContext: Context? = null - var sharedPreferences: SharedPreferences? = null - - beforeAny { - if (appContext == null) { - appContext = ApplicationProvider.getApplicationContext() - sharedPreferences = appContext!!.getSharedPreferences(PreferenceStores.ONESIGNAL, Context.MODE_PRIVATE) +class OtelIntegrationTest : FunSpec() { + private lateinit var appContext: Context + private lateinit var sharedPreferences: SharedPreferences + + init { + beforeAny { + if (!::appContext.isInitialized) { + appContext = ApplicationProvider.getApplicationContext() + sharedPreferences = appContext.getSharedPreferences(PreferenceStores.ONESIGNAL, Context.MODE_PRIVATE) + } } - } - beforeEach { - // Ensure sharedPreferences is initialized - if (sharedPreferences == null) { - appContext = ApplicationProvider.getApplicationContext() - sharedPreferences = appContext!!.getSharedPreferences(PreferenceStores.ONESIGNAL, Context.MODE_PRIVATE) - } - // Clear and set up SharedPreferences with test data - sharedPreferences!!.edit().clear().commit() - - // Set up ConfigModelStore data - val configModel = JSONObject().apply { - put(ConfigModel::appId.name, "test-app-id") - put(ConfigModel::pushSubscriptionId.name, "test-subscription-id") - val remoteLoggingParams = JSONObject().apply { - put("logLevel", "ERROR") + beforeEach { + if (!::sharedPreferences.isInitialized) { + appContext = ApplicationProvider.getApplicationContext() + sharedPreferences = appContext.getSharedPreferences(PreferenceStores.ONESIGNAL, Context.MODE_PRIVATE) + } + sharedPreferences.edit().clear().commit() + + val configModel = JSONObject().apply { + put(ConfigModel::appId.name, "test-app-id") + put(ConfigModel::pushSubscriptionId.name, "test-subscription-id") + val remoteLoggingParams = JSONObject().apply { + put("logLevel", "ERROR") + } + put(ConfigModel::remoteLoggingParams.name, remoteLoggingParams) + } + val configArray = JSONArray().apply { + put(configModel) } - put(ConfigModel::remoteLoggingParams.name, remoteLoggingParams) - } - val configArray = JSONArray().apply { - put(configModel) - } - // Set up IdentityModelStore data - val identityModel = JSONObject().apply { - put(IdentityConstants.ONESIGNAL_ID, "test-onesignal-id") - } - val identityArray = JSONArray().apply { - put(identityModel) - } + val identityModel = JSONObject().apply { + put(IdentityConstants.ONESIGNAL_ID, "test-onesignal-id") + } + val identityArray = JSONArray().apply { + put(identityModel) + } - sharedPreferences!!.edit() - .putString(PreferenceOneSignalKeys.MODEL_STORE_PREFIX + configNameSpace, configArray.toString()) - .putString(PreferenceOneSignalKeys.MODEL_STORE_PREFIX + identityNameSpace, identityArray.toString()) - .putString(PreferenceOneSignalKeys.PREFS_OS_INSTALL_ID, "test-install-id") - .commit() - } + sharedPreferences.edit() + .putString(PreferenceOneSignalKeys.MODEL_STORE_PREFIX + configNameSpace, configArray.toString()) + .putString(PreferenceOneSignalKeys.MODEL_STORE_PREFIX + identityNameSpace, identityArray.toString()) + .putString(PreferenceOneSignalKeys.PREFS_OS_INSTALL_ID, "test-install-id") + .commit() + } - afterEach { - sharedPreferences!!.edit().clear().commit() - } + afterEach { + sharedPreferences.edit().clear().commit() + } - test("AndroidOtelPlatformProvider should provide correct Android values") { - val provider = createAndroidOtelPlatformProvider(appContext!!) + test("AndroidOtelPlatformProvider should provide correct Android values") { + val provider = createAndroidOtelPlatformProvider(appContext) - provider.shouldBeInstanceOf() - provider.sdkBase shouldBe "android" - provider.appPackageId shouldBe appContext!!.packageName // Use actual package name from context - provider.osName shouldBe "Android" - provider.deviceManufacturer shouldBe Build.MANUFACTURER - provider.deviceModel shouldBe Build.MODEL - provider.osVersion shouldBe Build.VERSION.RELEASE - provider.osBuildId shouldBe Build.ID + provider.shouldBeInstanceOf() + provider.sdkBase shouldBe "android" + provider.appPackageId shouldBe appContext.packageName + provider.osName shouldBe "Android" + provider.deviceManufacturer shouldBe Build.MANUFACTURER + provider.deviceModel shouldBe Build.MODEL + provider.osVersion shouldBe Build.VERSION.RELEASE + provider.osBuildId shouldBe Build.ID - runBlocking { - provider.getInstallId() shouldNotBe null + runBlocking { + provider.getInstallId() shouldNotBe null + } } - } - test("AndroidOtelPlatformProvider should provide per-event values") { - val provider = createAndroidOtelPlatformProvider(appContext!!) + test("AndroidOtelPlatformProvider should provide per-event values") { + val provider = createAndroidOtelPlatformProvider(appContext) - provider.appId shouldBe "test-app-id" - provider.onesignalId shouldBe "test-onesignal-id" - provider.pushSubscriptionId shouldBe "test-subscription-id" - provider.appState shouldBeOneOf listOf("foreground", "background", "unknown") - (provider.processUptime > 0) shouldBe true - provider.currentThreadName shouldBe Thread.currentThread().name - } + provider.appId shouldBe "test-app-id" + provider.onesignalId shouldBe "test-onesignal-id" + provider.pushSubscriptionId shouldBe "test-subscription-id" + provider.appState shouldBeOneOf listOf("foreground", "background", "unknown") + (provider.processUptime > 0) shouldBe true + provider.currentThreadName shouldBe Thread.currentThread().name + } - test("AndroidOtelLogger should delegate to Logging") { - val logger = AndroidOtelLogger() + test("AndroidOtelLogger should delegate to Logging") { + val logger = AndroidOtelLogger() - logger.shouldBeInstanceOf() - // Should not throw - logger.debug("test") - logger.info("test") - logger.warn("test") - logger.error("test") - } + logger.shouldBeInstanceOf() + logger.debug("test") + logger.info("test") + logger.warn("test") + logger.error("test") + } - test("OtelFactory should create crash handler with Android provider") { - val provider = createAndroidOtelPlatformProvider(appContext!!) - val logger = AndroidOtelLogger() + test("OtelFactory should create crash handler with Android provider") { + val provider = createAndroidOtelPlatformProvider(appContext) + val logger = AndroidOtelLogger() - val handler = OtelFactory.createCrashHandler(provider, logger) + val handler = OtelFactory.createCrashHandler(provider, logger) - handler shouldNotBe null - handler.shouldBeInstanceOf() - handler.initialize() // Should not throw - } + handler shouldNotBe null + handler.shouldBeInstanceOf() + handler.initialize() + } - test("OneSignalCrashHandlerFactory should create working crash handler") { - // Note: OneSignalCrashHandlerFactory may need to be updated to use the new approach - // For now, we'll test the direct creation - val provider = createAndroidOtelPlatformProvider(appContext!!) - val logger = AndroidOtelLogger() - val handler = OtelFactory.createCrashHandler(provider, logger) + test("OneSignalCrashHandlerFactory should create working crash handler") { + val provider = createAndroidOtelPlatformProvider(appContext) + val logger = AndroidOtelLogger() + val handler = OtelFactory.createCrashHandler(provider, logger) - handler shouldNotBe null - handler.shouldBeInstanceOf() - handler.initialize() // Should not throw - } + handler shouldNotBe null + handler.shouldBeInstanceOf() + handler.initialize() + } - test("AndroidOtelPlatformProvider should provide crash storage path") { - val provider = createAndroidOtelPlatformProvider(appContext!!) + test("AndroidOtelPlatformProvider should provide crash storage path") { + val provider = createAndroidOtelPlatformProvider(appContext) - provider.crashStoragePath.contains("onesignal") shouldBe true - provider.crashStoragePath.contains("otel") shouldBe true - provider.crashStoragePath.contains("crashes") shouldBe true - provider.minFileAgeForReadMillis shouldBe 5000L - } + provider.crashStoragePath.contains("onesignal") shouldBe true + provider.crashStoragePath.contains("otel") shouldBe true + provider.crashStoragePath.contains("crashes") shouldBe true + provider.minFileAgeForReadMillis shouldBe 5000L + } - test("AndroidOtelPlatformProvider should handle remote logging config") { - val provider = createAndroidOtelPlatformProvider(appContext!!) + test("AndroidOtelPlatformProvider should handle remote logging config") { + val provider = createAndroidOtelPlatformProvider(appContext) - provider.remoteLogLevel shouldBe "ERROR" - provider.appIdForHeaders shouldBe "test-app-id" + provider.remoteLogLevel shouldBe "ERROR" + provider.appIdForHeaders shouldBe "test-app-id" + } } -}) +} From acc13b33dbb5c0e661f3d12be20f49dcd678f227 Mon Sep 17 00:00:00 2001 From: Fadi George Date: Tue, 7 Apr 2026 10:53:16 -0700 Subject: [PATCH 4/4] docs: bump Compose compiler to 1.5.15 --- examples/build.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/build.md b/examples/build.md index b3d7ca60d..7d2d3043f 100644 --- a/examples/build.md +++ b/examples/build.md @@ -650,7 +650,7 @@ Enable Jetpack Compose in the project: build.gradle.kts (app): - buildFeatures { compose = true } -- composeOptions { kotlinCompilerExtensionVersion = "1.5.10" } +- composeOptions { kotlinCompilerExtensionVersion = "1.5.15" } Dependencies (via BOM): - composeBom = "2024.02.00"