Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 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
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# Changelog

## Unreleased

### Fixes

- Fix do not initialize SDK for Jetpack Compose Preview builds ([#4324](https://github.com/getsentry/sentry-java/pull/4324))

## 8.7.0

### Features
Expand Down
1 change: 1 addition & 0 deletions sentry-android-core/api/sentry-android-core.api
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,7 @@ public final class io/sentry/android/core/BuildInfoProvider {
}

public final class io/sentry/android/core/ContextUtils {
public static fun appIsLibraryForComposePreview (Landroid/content/Context;)Z
public static fun getApplicationContext (Landroid/content/Context;)Landroid/content/Context;
public static fun isForegroundImportance ()Z
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import android.annotation.SuppressLint;
import android.app.ActivityManager;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
Expand All @@ -27,6 +28,7 @@
import java.io.IOException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
Expand Down Expand Up @@ -285,6 +287,36 @@ public static boolean isForegroundImportance() {
return isForegroundImportance.getValue();
}

/**
* Determines if the app is a packaged android library for running Compose Preview Mode
*
* @param context the context
* @return true, if the app is actually a library running as an app for Compose Preview Mode
*/
@ApiStatus.Internal
public static boolean appIsLibraryForComposePreview(final @NotNull Context context) {
// Jetpack Compose Preview (aka "Run Preview on Device")
// uses the androidTest flavor for android library modules,
// so let's fail-fast by checking this first
if (context.getPackageName().endsWith(".test")) {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this will cover the majority of customers already, great find 💯

try {
final @NotNull ActivityManager activityManager =
(ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
final @NotNull List<ActivityManager.AppTask> appTasks = activityManager.getAppTasks();
for (final ActivityManager.AppTask task : appTasks) {
final @Nullable ComponentName component = task.getTaskInfo().baseIntent.getComponent();
if (component != null
&& component.getClassName().equals("androidx.compose.ui.tooling.PreviewActivity")) {
return true;
}
}
} catch (Throwable t) {
// ignored
}
}
return false;
}

/**
* Get the device's current kernel version, as a string. Attempts to read /proc/version, and falls
* back to the 'os.version' System Property.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,9 @@ public boolean onCreate() {
logger.log(SentryLevel.FATAL, "App. Context from ContentProvider is null");
return false;
}
if (ManifestMetadataReader.isAutoInit(context, logger)) {

if (ManifestMetadataReader.isAutoInit(context, logger)
&& !ContextUtils.appIsLibraryForComposePreview(context)) {
Comment thread
romtsn marked this conversation as resolved.
SentryAndroid.init(context, logger);
SentryIntegrationPackageStorage.getInstance().addIntegration("AutoInit");
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@ import android.app.ActivityManager
import android.app.ActivityManager.MemoryInfo
import android.app.ActivityManager.RunningAppProcessInfo
import android.content.BroadcastReceiver
import android.content.ComponentName
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.content.pm.ApplicationInfo
import android.content.pm.PackageInfo
Expand Down Expand Up @@ -270,4 +272,35 @@ class ContextUtilsTest {
val appContext = ContextUtils.getApplicationContext(contextMock)
assertSame(appContextMock, appContext)
}

@Test
fun `appIsLibraryForComposePreview is correctly determined`() {
fun getMockContext(
packageName: String,
activityClassName: String
): Context {
val context = mock<Context>()
val activityManager = mock<ActivityManager>()
whenever(context.packageName).thenReturn(packageName)
whenever(context.getSystemService(eq(Context.ACTIVITY_SERVICE))).thenReturn(
activityManager
)
val taskInfo = ActivityManager.RecentTaskInfo()
taskInfo.baseIntent = Intent().setComponent(
ComponentName(
"com.example.library",
activityClassName
)
)
val appTask = mock<ActivityManager.AppTask>()
whenever(appTask.taskInfo).thenReturn(taskInfo)
whenever(activityManager.appTasks).thenReturn(listOf(appTask))

return context
}

assertTrue(ContextUtils.appIsLibraryForComposePreview(getMockContext("com.example.library.test", "androidx.compose.ui.tooling.PreviewActivity")))
assertFalse(ContextUtils.appIsLibraryForComposePreview(getMockContext("com.example.library.test", "com.example.HomeActivity")))
assertFalse(ContextUtils.appIsLibraryForComposePreview(getMockContext("com.example.library", "androidx.compose.ui.tooling.PreviewActivity")))
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,14 @@ import androidx.test.ext.junit.runners.AndroidJUnit4
import io.sentry.Sentry
import io.sentry.test.callMethod
import org.junit.runner.RunWith
import org.mockito.Mockito
import org.mockito.kotlin.any
import kotlin.test.BeforeTest
import kotlin.test.Test
import kotlin.test.assertFailsWith
import kotlin.test.assertFalse
import kotlin.test.assertTrue
import kotlin.use

@RunWith(AndroidJUnit4::class)
class SentryInitProviderTest {
Expand Down Expand Up @@ -153,6 +156,24 @@ class SentryInitProviderTest {
assertFalse(sentryOptions.isEnableNdk)
}

@Test
fun `skips init in compose preview mode`() {
val providerInfo = ProviderInfo()

assertFalse(Sentry.isEnabled())
providerInfo.authority = AUTHORITY

val metaData = Bundle()
metaData.putString(ManifestMetadataReader.DSN, "https://key@sentry.io/123")
val mockContext = ContextUtilsTestHelper.mockMetaData(metaData = metaData)

Mockito.mockStatic(ContextUtils::class.java).use { contextUtils ->
contextUtils.`when`<Boolean> { ContextUtils.appIsLibraryForComposePreview(any()) }.thenReturn(true)
sentryInitProvider.attachInfo(mockContext, providerInfo)
}
assertFalse(Sentry.isEnabled())
}

companion object {
private const val AUTHORITY = "io.sentry.sample.SentryInitProvider"
}
Expand Down
Loading