From b12bf287ec49e296ae0c4a44c524ec706d4adc55 Mon Sep 17 00:00:00 2001 From: thiago Date: Mon, 5 Aug 2024 03:07:53 -0300 Subject: [PATCH 1/9] fix: ensure activityLabel returns null if not explicitly set Modified the activityLabel method to check if the label is explicitly set for the Activity. If not, it will return null instead of the application label. Added activityName to return activityName class Updated onActivityStarted to use activityName as a fallback if activityLabel is null. --- ...HogActivityLifecycleCallbackIntegration.kt | 11 +++++-- .../android/internal/PostHogAndroidUtils.kt | 31 +++++++++++++++++-- 2 files changed, 38 insertions(+), 4 deletions(-) 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..43cf833f 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 @@ -44,12 +44,19 @@ internal class PostHogActivityLifecycleCallbackIntegration( override fun onActivityStarted(activity: Activity) { if (config.captureScreenViews) { val activityLabel = activity.activityLabel(config) - if (!activityLabel.isNullOrEmpty()) { - PostHog.screen(activityLabel) + val screenName = if (!activityLabel.isNullOrEmpty()) { + activityLabel + } else { + activity.activityName(config) + } + + if (!screenName.isNullOrEmpty()) { + PostHog.screen(screenName) } } } + override fun onActivityResumed(activity: Activity) { } 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..9ab3d062 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 @@ -125,14 +125,41 @@ internal fun Context.telephonyManager(): TelephonyManager? { @Suppress("DEPRECATION") internal fun Activity.activityLabel(config: PostHogAndroidConfig): String? { return try { - val info = packageManager.getActivityInfo(componentName, GET_META_DATA) - info.loadLabel(packageManager).toString() + val packageManager = packageManager + val componentName = componentName + val activityInfo = packageManager.getActivityInfo(componentName, GET_META_DATA) + val applicationInfo = applicationInfo + + val activityLabel = + activityInfo.nonLocalizedLabel?.toString() ?: activityInfo.loadLabel(packageManager) + .toString() + val applicationLabel = + applicationInfo.nonLocalizedLabel?.toString() ?: applicationInfo.loadLabel( + packageManager + ).toString() + + if (activityLabel.isNotEmpty() && activityLabel != applicationLabel) { + activityLabel + } else { + null + } } catch (e: Throwable) { config.logger.log("Error getting the Activity's label: $e.") null } } +@Suppress("DEPRECATION") +internal fun Activity.activityName(config: PostHogAndroidConfig): String? { + return try { + val info = packageManager.getActivityInfo(componentName, GET_META_DATA) + info.name.substringAfterLast('.') + } catch (e: Throwable) { + config.logger.log("Error getting the Activity's name: $e.") + null + } +} + internal fun isMainThread(mainHandler: MainHandler): Boolean { return Thread.currentThread().id == mainHandler.mainLooper.thread.id } From fa036a75c5c2112182dbe71a6af5be5550f61d5c Mon Sep 17 00:00:00 2001 From: thiago Date: Wed, 7 Aug 2024 11:48:20 -0300 Subject: [PATCH 2/9] refactor: unify activity label and name retrieval into a single method - Combined activityLabel and activityName methods into a single method activityLabelOrName. - The new method retrieves the activity label if it differs from the application label. - If the labels are identical or the activity label is empty, it falls back to the activity's class name. --- .../android/internal/PostHogAndroidUtils.kt | 30 ++++--------------- 1 file changed, 5 insertions(+), 25 deletions(-) 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 9ab3d062..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,39 +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 packageManager = packageManager - val componentName = componentName val activityInfo = packageManager.getActivityInfo(componentName, GET_META_DATA) - val applicationInfo = applicationInfo - - val activityLabel = - activityInfo.nonLocalizedLabel?.toString() ?: activityInfo.loadLabel(packageManager) - .toString() - val applicationLabel = - applicationInfo.nonLocalizedLabel?.toString() ?: applicationInfo.loadLabel( - packageManager - ).toString() + val activityLabel = activityInfo.loadLabel(packageManager).toString() + val applicationLabel = applicationInfo.loadLabel(packageManager).toString() if (activityLabel.isNotEmpty() && activityLabel != applicationLabel) { activityLabel } else { - null + activityInfo.name.substringAfterLast('.') } } catch (e: Throwable) { - config.logger.log("Error getting the Activity's label: $e.") - null - } -} - -@Suppress("DEPRECATION") -internal fun Activity.activityName(config: PostHogAndroidConfig): String? { - return try { - val info = packageManager.getActivityInfo(componentName, GET_META_DATA) - info.name.substringAfterLast('.') - } catch (e: Throwable) { - config.logger.log("Error getting the Activity's name: $e.") + config.logger.log("Error getting the Activity's label or name: $e.") null } } From f8f0cdbb5b66d7bcbcb120d0dd5d613d690dc900 Mon Sep 17 00:00:00 2001 From: thiago Date: Wed, 7 Aug 2024 11:50:06 -0300 Subject: [PATCH 3/9] feat: update onActivityStarted to use the unified activityLabelOrName method - Replaced the separate calls to activityLabel and activityName with a single call to activityLabelOrName. --- ...tHogActivityLifecycleCallbackIntegration.kt | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) 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 43cf833f..36b4aad2 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 @@ -3,6 +3,7 @@ package com.posthog.android.internal import android.app.Activity import android.app.Application import android.app.Application.ActivityLifecycleCallbacks +import android.content.pm.PackageManager.GET_META_DATA import android.os.Bundle import com.posthog.PostHog import com.posthog.PostHogIntegration @@ -41,20 +42,15 @@ internal class PostHogActivityLifecycleCallbackIntegration( } } - override fun onActivityStarted(activity: Activity) { - if (config.captureScreenViews) { - val activityLabel = activity.activityLabel(config) - val screenName = if (!activityLabel.isNullOrEmpty()) { - activityLabel - } else { - activity.activityName(config) - } + override fun onActivityStarted(activity: Activity) { + if (config.captureScreenViews) { + val screenName = activity.activityLabelOrName(config) - if (!screenName.isNullOrEmpty()) { - PostHog.screen(screenName) + if (!screenName.isNullOrEmpty()) { + PostHog.screen(screenName) + } } } - } override fun onActivityResumed(activity: Activity) { From e1434eaa03b097c599c71782380fb6d8f1c3ebb9 Mon Sep 17 00:00:00 2001 From: thiago Date: Wed, 7 Aug 2024 11:52:19 -0300 Subject: [PATCH 4/9] refactor: update mockScreenTitle to include activity name and application label - Added parameters for activity name and application label to the mockScreenTitle function. --- .../src/test/java/com/posthog/android/Utils.kt | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) 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..f17168dc 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,32 @@ 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 } From 9a20d653d7f5f9fc8de7a068416fb33aca182865 Mon Sep 17 00:00:00 2001 From: thiago Date: Wed, 7 Aug 2024 11:53:16 -0300 Subject: [PATCH 5/9] test: enhance activity lifecycle tests to verify label and name behavior - Updated tests in PostHogActivityLifecycleCallbackIntegrationTest to verify activity label and application label handling. - Added scenarios to ensure the correct behavior when labels are the same or empty. --- ...ctivityLifecycleCallbackIntegrationTest.kt | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) 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..3a3bfff4 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,17 @@ 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 +153,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) } } From 2018ad8e92956e5068f61c1799eeeedb748e00fe Mon Sep 17 00:00:00 2001 From: thiago Date: Wed, 7 Aug 2024 11:57:50 -0300 Subject: [PATCH 6/9] fix: remove unnecessary import --- .../internal/PostHogActivityLifecycleCallbackIntegration.kt | 1 - 1 file changed, 1 deletion(-) 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 36b4aad2..8bf49074 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 @@ -3,7 +3,6 @@ package com.posthog.android.internal import android.app.Activity import android.app.Application import android.app.Application.ActivityLifecycleCallbacks -import android.content.pm.PackageManager.GET_META_DATA import android.os.Bundle import com.posthog.PostHog import com.posthog.PostHogIntegration From 2f4ef5a9a639d1349d0b90d1c9434daeabc9d76e Mon Sep 17 00:00:00 2001 From: thiago Date: Wed, 7 Aug 2024 12:40:16 -0300 Subject: [PATCH 7/9] style: fix indentation in onActivityStarted method --- .../PostHogActivityLifecycleCallbackIntegration.kt | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) 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 8bf49074..41ef6c37 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 @@ -41,15 +41,15 @@ internal class PostHogActivityLifecycleCallbackIntegration( } } - override fun onActivityStarted(activity: Activity) { - if (config.captureScreenViews) { - val screenName = activity.activityLabelOrName(config) + override fun onActivityStarted(activity: Activity) { + if (config.captureScreenViews) { + val screenName = activity.activityLabelOrName(config) - if (!screenName.isNullOrEmpty()) { - PostHog.screen(screenName) - } + if (!screenName.isNullOrEmpty()) { + PostHog.screen(screenName) } } + } override fun onActivityResumed(activity: Activity) { From 75b6f8d88d0db5e0b8f6d5ab42b5297c39f6fd74 Mon Sep 17 00:00:00 2001 From: thiago Date: Wed, 7 Aug 2024 12:48:32 -0300 Subject: [PATCH 8/9] fix: ensure activity name is used when activity label is not defined (#153) --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) 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 From 5f74fa182e712adc12986aea70870df793c9469a Mon Sep 17 00:00:00 2001 From: thiago Date: Thu, 8 Aug 2024 09:37:42 -0300 Subject: [PATCH 9/9] style: fix format --- .../PostHogActivityLifecycleCallbackIntegration.kt | 1 - .../src/test/java/com/posthog/android/Utils.kt | 9 +++++---- ...stHogActivityLifecycleCallbackIntegrationTest.kt | 13 +++++++------ 3 files changed, 12 insertions(+), 11 deletions(-) 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 41ef6c37..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 @@ -51,7 +51,6 @@ internal class PostHogActivityLifecycleCallbackIntegration( } } - override fun onActivityResumed(activity: Activity) { } 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 f17168dc..253d167e 100644 --- a/posthog-android/src/test/java/com/posthog/android/Utils.kt +++ b/posthog-android/src/test/java/com/posthog/android/Utils.kt @@ -41,13 +41,14 @@ public fun mockScreenTitle( throws: Boolean, title: String, activityName: String, - applicationLabel: String + applicationLabel: String, ): Activity { val activity = mock() val pm = mock() - val ac = mock().apply { - name = activityName - } + val ac = + mock().apply { + name = activityName + } val appInfo = mock() whenever(ac.loadLabel(any())).thenReturn(title) 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 3a3bfff4..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 @@ -129,12 +129,13 @@ internal class PostHogActivityLifecycleCallbackIntegrationTest { @Test fun `onActivityStarted returns activityInfo name if labels are the same`() { - val fake = executeCaptureScreenViewsTest( - captureScreenViews = true, - title = "AppLabel", - activityName = "com.example.MyActivity", - applicationLabel = "AppLabel" - ) + val fake = + executeCaptureScreenViewsTest( + captureScreenViews = true, + title = "AppLabel", + activityName = "com.example.MyActivity", + applicationLabel = "AppLabel", + ) assertEquals("MyActivity", fake.screenTitle) }