diff --git a/CHANGELOG.md b/CHANGELOG.md index 7c1bf397..1706bc2e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,6 @@ ## Next +- fix: ensure activity name is used when activity label is not defined ([#153](https://github.com/PostHog/posthog-android/pull/153)) - recording: mask views with `contentDescription` setting and mask `WebView` if any masking is enabled ([#149](https://github.com/PostHog/posthog-android/pull/149)) ## 3.4.2 - 2024-06-28 diff --git a/posthog-android/src/main/java/com/posthog/android/internal/PostHogActivityLifecycleCallbackIntegration.kt b/posthog-android/src/main/java/com/posthog/android/internal/PostHogActivityLifecycleCallbackIntegration.kt index b1ef8f87..9bf75dc0 100644 --- a/posthog-android/src/main/java/com/posthog/android/internal/PostHogActivityLifecycleCallbackIntegration.kt +++ b/posthog-android/src/main/java/com/posthog/android/internal/PostHogActivityLifecycleCallbackIntegration.kt @@ -43,9 +43,10 @@ internal class PostHogActivityLifecycleCallbackIntegration( override fun onActivityStarted(activity: Activity) { if (config.captureScreenViews) { - val activityLabel = activity.activityLabel(config) - if (!activityLabel.isNullOrEmpty()) { - PostHog.screen(activityLabel) + val screenName = activity.activityLabelOrName(config) + + if (!screenName.isNullOrEmpty()) { + PostHog.screen(screenName) } } } diff --git a/posthog-android/src/main/java/com/posthog/android/internal/PostHogAndroidUtils.kt b/posthog-android/src/main/java/com/posthog/android/internal/PostHogAndroidUtils.kt index 37738bcf..909ac2ac 100644 --- a/posthog-android/src/main/java/com/posthog/android/internal/PostHogAndroidUtils.kt +++ b/posthog-android/src/main/java/com/posthog/android/internal/PostHogAndroidUtils.kt @@ -123,12 +123,19 @@ internal fun Context.telephonyManager(): TelephonyManager? { } @Suppress("DEPRECATION") -internal fun Activity.activityLabel(config: PostHogAndroidConfig): String? { +internal fun Activity.activityLabelOrName(config: PostHogAndroidConfig): String? { return try { - val info = packageManager.getActivityInfo(componentName, GET_META_DATA) - info.loadLabel(packageManager).toString() + val activityInfo = packageManager.getActivityInfo(componentName, GET_META_DATA) + val activityLabel = activityInfo.loadLabel(packageManager).toString() + val applicationLabel = applicationInfo.loadLabel(packageManager).toString() + + if (activityLabel.isNotEmpty() && activityLabel != applicationLabel) { + activityLabel + } else { + activityInfo.name.substringAfterLast('.') + } } catch (e: Throwable) { - config.logger.log("Error getting the Activity's label: $e.") + config.logger.log("Error getting the Activity's label or name: $e.") null } } diff --git a/posthog-android/src/test/java/com/posthog/android/Utils.kt b/posthog-android/src/test/java/com/posthog/android/Utils.kt index c5019e19..253d167e 100644 --- a/posthog-android/src/test/java/com/posthog/android/Utils.kt +++ b/posthog-android/src/test/java/com/posthog/android/Utils.kt @@ -40,19 +40,33 @@ public fun mockActivityUri(uri: String): Activity { public fun mockScreenTitle( throws: Boolean, title: String, + activityName: String, + applicationLabel: String, ): Activity { val activity = mock() val pm = mock() - val ac = mock() + val ac = + mock().apply { + name = activityName + } + val appInfo = mock() + whenever(ac.loadLabel(any())).thenReturn(title) + whenever(appInfo.loadLabel(any())).thenReturn(applicationLabel) + if (throws) { whenever(pm.getActivityInfo(any(), any())).thenThrow(PackageManager.NameNotFoundException()) } else { whenever(pm.getActivityInfo(any(), any())).thenReturn(ac) } + + whenever(pm.getApplicationInfo(any(), any())).thenReturn(appInfo) + val component = mock() whenever(activity.componentName).thenReturn(component) whenever(activity.packageManager).thenReturn(pm) + whenever(activity.applicationInfo).thenReturn(appInfo) // Ensure applicationInfo is not null + return activity } diff --git a/posthog-android/src/test/java/com/posthog/android/internal/PostHogActivityLifecycleCallbackIntegrationTest.kt b/posthog-android/src/test/java/com/posthog/android/internal/PostHogActivityLifecycleCallbackIntegrationTest.kt index 070c605c..24b90e7e 100644 --- a/posthog-android/src/test/java/com/posthog/android/internal/PostHogActivityLifecycleCallbackIntegrationTest.kt +++ b/posthog-android/src/test/java/com/posthog/android/internal/PostHogActivityLifecycleCallbackIntegrationTest.kt @@ -107,9 +107,11 @@ internal class PostHogActivityLifecycleCallbackIntegrationTest { captureScreenViews: Boolean = true, throws: Boolean = false, title: String = "Title", + activityName: String = "com.example.MyActivity", + applicationLabel: String = "AppLabel", ): PostHogFake { val sut = getSut(captureScreenViews = captureScreenViews) - val activity = mockScreenTitle(throws, title) + val activity = mockScreenTitle(throws, title, activityName, applicationLabel) val fake = createPostHogFake() @@ -125,6 +127,18 @@ internal class PostHogActivityLifecycleCallbackIntegrationTest { assertEquals("Title", fake.screenTitle) } + @Test + fun `onActivityStarted returns activityInfo name if labels are the same`() { + val fake = + executeCaptureScreenViewsTest( + captureScreenViews = true, + title = "AppLabel", + activityName = "com.example.MyActivity", + applicationLabel = "AppLabel", + ) + assertEquals("MyActivity", fake.screenTitle) + } + @Test fun `onActivityStarted does not capture captureScreenViews if disabled`() { val fake = executeCaptureScreenViewsTest(false) @@ -140,9 +154,9 @@ internal class PostHogActivityLifecycleCallbackIntegrationTest { } @Test - fun `onActivityStarted does not capture if title is empty`() { + fun `onActivityStarted returns activity name if activity label are the empty`() { val fake = executeCaptureScreenViewsTest(title = "") - assertNull(fake.screenTitle) + assertEquals("MyActivity", fake.screenTitle) } }