Skip to content

Commit a90bd80

Browse files
authored
Hook User Interaction integration into running Activity in case of deferred SDK init (7.x.x) (#4387)
* Hook User Interaction integration into running Activity in case of deferred SDK init * Update Changelog
1 parent 98fe7b0 commit a90bd80

File tree

12 files changed

+207
-291
lines changed

12 files changed

+207
-291
lines changed

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
# Changelog
22

3+
## Unreleased
4+
5+
### Features
6+
7+
- Hook User Interaction integration into running Activity in case of deferred SDK init ([#4387](https://github.com/getsentry/sentry-java/pull/4387))
8+
39
## 7.22.5
410

511
### Fixes

sentry-android-core/api/sentry-android-core.api

Lines changed: 4 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -168,24 +168,12 @@ public final class io/sentry/android/core/ContextUtils {
168168

169169
public class io/sentry/android/core/CurrentActivityHolder {
170170
public fun clearActivity ()V
171+
public fun clearActivity (Landroid/app/Activity;)V
171172
public fun getActivity ()Landroid/app/Activity;
172173
public static fun getInstance ()Lio/sentry/android/core/CurrentActivityHolder;
173174
public fun setActivity (Landroid/app/Activity;)V
174175
}
175176

176-
public final class io/sentry/android/core/CurrentActivityIntegration : android/app/Application$ActivityLifecycleCallbacks, io/sentry/Integration, java/io/Closeable {
177-
public fun <init> (Landroid/app/Application;)V
178-
public fun close ()V
179-
public fun onActivityCreated (Landroid/app/Activity;Landroid/os/Bundle;)V
180-
public fun onActivityDestroyed (Landroid/app/Activity;)V
181-
public fun onActivityPaused (Landroid/app/Activity;)V
182-
public fun onActivityResumed (Landroid/app/Activity;)V
183-
public fun onActivitySaveInstanceState (Landroid/app/Activity;Landroid/os/Bundle;)V
184-
public fun onActivityStarted (Landroid/app/Activity;)V
185-
public fun onActivityStopped (Landroid/app/Activity;)V
186-
public fun register (Lio/sentry/IHub;Lio/sentry/SentryOptions;)V
187-
}
188-
189177
public final class io/sentry/android/core/DeviceInfoUtil {
190178
public fun <init> (Landroid/content/Context;Lio/sentry/android/core/SentryAndroidOptions;)V
191179
public fun collectDeviceInformation (ZZ)Lio/sentry/protocol/Device;
@@ -449,7 +437,10 @@ public class io/sentry/android/core/performance/AppStartMetrics : io/sentry/andr
449437
public fun isAppLaunchedInForeground ()Z
450438
public fun onActivityCreated (Landroid/app/Activity;Landroid/os/Bundle;)V
451439
public fun onActivityDestroyed (Landroid/app/Activity;)V
440+
public fun onActivityPaused (Landroid/app/Activity;)V
441+
public fun onActivityResumed (Landroid/app/Activity;)V
452442
public fun onActivityStarted (Landroid/app/Activity;)V
443+
public fun onActivityStopped (Landroid/app/Activity;)V
453444
public fun onAppStartSpansSent ()V
454445
public static fun onApplicationCreate (Landroid/app/Application;)V
455446
public static fun onApplicationPostCreate (Landroid/app/Application;)V

sentry-android-core/src/main/java/io/sentry/android/core/AndroidOptionsInitializer.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -281,7 +281,6 @@ static void installDefaultIntegrations(
281281
new ActivityLifecycleIntegration(
282282
(Application) context, buildInfoProvider, activityFramesTracker));
283283
options.addIntegration(new ActivityBreadcrumbsIntegration((Application) context));
284-
options.addIntegration(new CurrentActivityIntegration((Application) context));
285284
options.addIntegration(new UserInteractionIntegration((Application) context, loadClass));
286285
if (isFragmentAvailable) {
287286
options.addIntegration(new FragmentLifecycleIntegration((Application) context, true, true));

sentry-android-core/src/main/java/io/sentry/android/core/CurrentActivityHolder.java

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,10 @@
11
package io.sentry.android.core;
22

33
import android.app.Activity;
4-
import androidx.annotation.NonNull;
5-
import androidx.annotation.Nullable;
64
import java.lang.ref.WeakReference;
75
import org.jetbrains.annotations.ApiStatus;
86
import org.jetbrains.annotations.NotNull;
7+
import org.jetbrains.annotations.Nullable;
98

109
@ApiStatus.Internal
1110
public class CurrentActivityHolder {
@@ -16,7 +15,7 @@ private CurrentActivityHolder() {}
1615

1716
private @Nullable WeakReference<Activity> currentActivity;
1817

19-
public static @NonNull CurrentActivityHolder getInstance() {
18+
public static @NotNull CurrentActivityHolder getInstance() {
2019
return instance;
2120
}
2221

@@ -27,7 +26,7 @@ private CurrentActivityHolder() {}
2726
return null;
2827
}
2928

30-
public void setActivity(final @NonNull Activity activity) {
29+
public void setActivity(final @NotNull Activity activity) {
3130
if (currentActivity != null && currentActivity.get() == activity) {
3231
return;
3332
}
@@ -38,4 +37,11 @@ public void setActivity(final @NonNull Activity activity) {
3837
public void clearActivity() {
3938
currentActivity = null;
4039
}
40+
41+
public void clearActivity(final @NotNull Activity activity) {
42+
if (currentActivity != null && currentActivity.get() != activity) {
43+
return;
44+
}
45+
currentActivity = null;
46+
}
4147
}

sentry-android-core/src/main/java/io/sentry/android/core/CurrentActivityIntegration.java

Lines changed: 0 additions & 80 deletions
This file was deleted.

sentry-android-core/src/main/java/io/sentry/android/core/UserInteractionIntegration.java

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66
import android.app.Application;
77
import android.os.Bundle;
88
import android.view.Window;
9+
import androidx.lifecycle.Lifecycle;
10+
import androidx.lifecycle.LifecycleOwner;
911
import io.sentry.IHub;
1012
import io.sentry.Integration;
1113
import io.sentry.SentryLevel;
@@ -27,12 +29,15 @@ public final class UserInteractionIntegration
2729
private @Nullable SentryAndroidOptions options;
2830

2931
private final boolean isAndroidXAvailable;
32+
private final boolean isAndroidxLifecycleAvailable;
3033

3134
public UserInteractionIntegration(
3235
final @NotNull Application application, final @NotNull LoadClass classLoader) {
3336
this.application = Objects.requireNonNull(application, "Application is required");
3437
isAndroidXAvailable =
3538
classLoader.isClassAvailable("androidx.core.view.GestureDetectorCompat", options);
39+
isAndroidxLifecycleAvailable =
40+
classLoader.isClassAvailable("androidx.lifecycle.Lifecycle", options);
3641
}
3742

3843
private void startTracking(final @NotNull Activity activity) {
@@ -127,6 +132,17 @@ public void register(@NotNull IHub hub, @NotNull SentryOptions options) {
127132
application.registerActivityLifecycleCallbacks(this);
128133
this.options.getLogger().log(SentryLevel.DEBUG, "UserInteractionIntegration installed.");
129134
addIntegrationToSdkVersion("UserInteraction");
135+
136+
// In case of a deferred init, we hook into any resumed activity
137+
if (isAndroidxLifecycleAvailable) {
138+
final @Nullable Activity activity = CurrentActivityHolder.getInstance().getActivity();
139+
if (activity instanceof LifecycleOwner) {
140+
if (((LifecycleOwner) activity).getLifecycle().getCurrentState()
141+
== Lifecycle.State.RESUMED) {
142+
startTracking(activity);
143+
}
144+
}
145+
}
130146
} else {
131147
options
132148
.getLogger()

sentry-android-core/src/main/java/io/sentry/android/core/performance/AppStartMetrics.java

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
import io.sentry.TracesSamplingDecision;
1616
import io.sentry.android.core.BuildInfoProvider;
1717
import io.sentry.android.core.ContextUtils;
18+
import io.sentry.android.core.CurrentActivityHolder;
1819
import io.sentry.android.core.SentryAndroidOptions;
1920
import io.sentry.android.core.internal.util.FirstDrawDoneListener;
2021
import java.util.ArrayList;
@@ -39,7 +40,6 @@
3940
*/
4041
@ApiStatus.Internal
4142
public class AppStartMetrics extends ActivityLifecycleCallbacksAdapter {
42-
4343
public enum AppStartType {
4444
UNKNOWN,
4545
COLD,
@@ -304,10 +304,12 @@ private void checkCreateTimeOnMain() {
304304

305305
@Override
306306
public void onActivityCreated(@NonNull Activity activity, @Nullable Bundle savedInstanceState) {
307-
final long nowUptimeMs = SystemClock.uptimeMillis();
307+
CurrentActivityHolder.getInstance().setActivity(activity);
308308

309309
// the first activity determines the app start type
310310
if (activeActivitiesCounter.incrementAndGet() == 1 && !firstDrawDone.get()) {
311+
final long nowUptimeMs = SystemClock.uptimeMillis();
312+
311313
// If the app (process) was launched more than 1 minute ago, it's likely wrong
312314
final long durationSinceAppStartMillis = nowUptimeMs - appStartSpan.getStartUptimeMs();
313315
if (!appLaunchedInForeground || durationSinceAppStartMillis > TimeUnit.MINUTES.toMillis(1)) {
@@ -329,6 +331,8 @@ public void onActivityCreated(@NonNull Activity activity, @Nullable Bundle saved
329331

330332
@Override
331333
public void onActivityStarted(@NonNull Activity activity) {
334+
CurrentActivityHolder.getInstance().setActivity(activity);
335+
332336
if (firstDrawDone.get()) {
333337
return;
334338
}
@@ -340,8 +344,25 @@ public void onActivityStarted(@NonNull Activity activity) {
340344
}
341345
}
342346

347+
@Override
348+
public void onActivityResumed(@NonNull Activity activity) {
349+
CurrentActivityHolder.getInstance().setActivity(activity);
350+
}
351+
352+
@Override
353+
public void onActivityPaused(@NonNull Activity activity) {
354+
CurrentActivityHolder.getInstance().clearActivity(activity);
355+
}
356+
357+
@Override
358+
public void onActivityStopped(@NonNull Activity activity) {
359+
CurrentActivityHolder.getInstance().clearActivity(activity);
360+
}
361+
343362
@Override
344363
public void onActivityDestroyed(@NonNull Activity activity) {
364+
CurrentActivityHolder.getInstance().clearActivity(activity);
365+
345366
final int remainingActivities = activeActivitiesCounter.decrementAndGet();
346367
// if the app is moving into background
347368
// as the next Activity is considered like a new app start

sentry-android-core/src/test/java/io/sentry/android/core/AndroidOptionsInitializerTest.kt

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -517,15 +517,6 @@ class AndroidOptionsInitializerTest {
517517
assertTrue { fixture.sentryOptions.envelopeDiskCache is AndroidEnvelopeCache }
518518
}
519519

520-
@Test
521-
fun `CurrentActivityIntegration is added by default`() {
522-
fixture.initSut(useRealContext = true)
523-
524-
val actual =
525-
fixture.sentryOptions.integrations.firstOrNull { it is CurrentActivityIntegration }
526-
assertNotNull(actual)
527-
}
528-
529520
@Test
530521
fun `When Activity Frames Tracking is enabled, the Activity Frames Tracker should be available`() {
531522
fixture.initSut(

0 commit comments

Comments
 (0)