Skip to content

Commit

Permalink
Merge c67d132 into f55020d
Browse files Browse the repository at this point in the history
  • Loading branch information
markushi authored Jan 3, 2023
2 parents f55020d + c67d132 commit 4a4964e
Show file tree
Hide file tree
Showing 35 changed files with 1,514 additions and 185 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# Changelog

## Unreleased

### Features

- Add Android View Hierarchy support ([#2440](https://github.com/getsentry/sentry-java/pull/2440))

## 6.11.0

### Features
Expand Down
33 changes: 23 additions & 10 deletions sentry-android-core/api/sentry-android-core.api
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,19 @@ public class io/sentry/android/core/CurrentActivityHolder {
public fun setActivity (Landroid/app/Activity;)V
}

public final class io/sentry/android/core/CurrentActivityIntegration : android/app/Application$ActivityLifecycleCallbacks, io/sentry/Integration, java/io/Closeable {
public fun <init> (Landroid/app/Application;)V
public fun close ()V
public fun onActivityCreated (Landroid/app/Activity;Landroid/os/Bundle;)V
public fun onActivityDestroyed (Landroid/app/Activity;)V
public fun onActivityPaused (Landroid/app/Activity;)V
public fun onActivityResumed (Landroid/app/Activity;)V
public fun onActivitySaveInstanceState (Landroid/app/Activity;Landroid/os/Bundle;)V
public fun onActivityStarted (Landroid/app/Activity;)V
public fun onActivityStopped (Landroid/app/Activity;)V
public fun register (Lio/sentry/IHub;Lio/sentry/SentryOptions;)V
}

public abstract class io/sentry/android/core/EnvelopeFileObserverIntegration : io/sentry/Integration, java/io/Closeable {
public fun <init> ()V
public fun close ()V
Expand Down Expand Up @@ -121,16 +134,8 @@ public final class io/sentry/android/core/PhoneStateBreadcrumbsIntegration : io/
public fun register (Lio/sentry/IHub;Lio/sentry/SentryOptions;)V
}

public final class io/sentry/android/core/ScreenshotEventProcessor : android/app/Application$ActivityLifecycleCallbacks, io/sentry/EventProcessor, java/io/Closeable {
public fun <init> (Landroid/app/Application;Lio/sentry/android/core/SentryAndroidOptions;Lio/sentry/android/core/BuildInfoProvider;)V
public fun close ()V
public fun onActivityCreated (Landroid/app/Activity;Landroid/os/Bundle;)V
public fun onActivityDestroyed (Landroid/app/Activity;)V
public fun onActivityPaused (Landroid/app/Activity;)V
public fun onActivityResumed (Landroid/app/Activity;)V
public fun onActivitySaveInstanceState (Landroid/app/Activity;Landroid/os/Bundle;)V
public fun onActivityStarted (Landroid/app/Activity;)V
public fun onActivityStopped (Landroid/app/Activity;)V
public final class io/sentry/android/core/ScreenshotEventProcessor : io/sentry/EventProcessor {
public fun <init> (Lio/sentry/android/core/SentryAndroidOptions;Lio/sentry/android/core/BuildInfoProvider;)V
public fun process (Lio/sentry/SentryEvent;Lio/sentry/Hint;)Lio/sentry/SentryEvent;
}

Expand All @@ -152,6 +157,7 @@ public final class io/sentry/android/core/SentryAndroidOptions : io/sentry/Sentr
public fun isAnrEnabled ()Z
public fun isAnrReportInDebug ()Z
public fun isAttachScreenshot ()Z
public fun isAttachViewHierarchy ()Z
public fun isCollectAdditionalContext ()Z
public fun isEnableActivityLifecycleBreadcrumbs ()Z
public fun isEnableActivityLifecycleTracingAutoFinish ()Z
Expand All @@ -164,6 +170,7 @@ public final class io/sentry/android/core/SentryAndroidOptions : io/sentry/Sentr
public fun setAnrReportInDebug (Z)V
public fun setAnrTimeoutIntervalMillis (J)V
public fun setAttachScreenshot (Z)V
public fun setAttachViewHierarchy (Z)V
public fun setCollectAdditionalContext (Z)V
public fun setDebugImagesLoader (Lio/sentry/android/core/IDebugImagesLoader;)V
public fun setEnableActivityLifecycleBreadcrumbs (Z)V
Expand Down Expand Up @@ -235,6 +242,12 @@ public final class io/sentry/android/core/UserInteractionIntegration : android/a
public fun register (Lio/sentry/IHub;Lio/sentry/SentryOptions;)V
}

public final class io/sentry/android/core/ViewHierarchyEventProcessor : io/sentry/EventProcessor {
public fun <init> (Lio/sentry/android/core/SentryAndroidOptions;)V
public fun process (Lio/sentry/SentryEvent;Lio/sentry/Hint;)Lio/sentry/SentryEvent;
public static fun snapshotViewHierarchy (Landroid/view/View;)Lio/sentry/protocol/ViewHierarchy;
}

public final class io/sentry/android/core/cache/AndroidEnvelopeCache : io/sentry/cache/EnvelopeCache {
public fun <init> (Lio/sentry/android/core/SentryAndroidOptions;)V
public fun getDirectory ()Ljava/io/File;
Expand Down
1 change: 1 addition & 0 deletions sentry-android-core/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@ dependencies {
testImplementation(projects.sentryAndroidTimber)
testImplementation(projects.sentryComposeHelper)
testImplementation(projects.sentryAndroidNdk)
testRuntimeOnly(Config.Libs.composeUi)
testRuntimeOnly(Config.Libs.timber)
testRuntimeOnly(Config.Libs.fragment)
}
Original file line number Diff line number Diff line change
Expand Up @@ -209,19 +209,21 @@ private static void installDefaultIntegrations(
options.addIntegration(
new ActivityLifecycleIntegration(
(Application) context, buildInfoProvider, activityFramesTracker));
options.addIntegration(new CurrentActivityIntegration((Application) context));
options.addIntegration(new UserInteractionIntegration((Application) context, loadClass));
if (isFragmentAvailable) {
options.addIntegration(new FragmentLifecycleIntegration((Application) context, true, true));
}
options.addEventProcessor(
new ScreenshotEventProcessor((Application) context, options, buildInfoProvider));
options.addEventProcessor(new ScreenshotEventProcessor(options, buildInfoProvider));
} else {
options
.getLogger()
.log(
SentryLevel.WARNING,
"ActivityLifecycle, FragmentLifecycle and UserInteraction Integrations need an Application class to be installed.");
}
options.addEventProcessor(new ViewHierarchyEventProcessor(options));

if (isTimberAvailable) {
options.addIntegration(new SentryTimberIntegration());
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
package io.sentry.android.core;

import android.app.Activity;
import android.app.Application;
import android.os.Bundle;
import androidx.annotation.NonNull;
import io.sentry.IHub;
import io.sentry.Integration;
import io.sentry.SentryOptions;
import io.sentry.util.Objects;
import java.io.Closeable;
import java.io.IOException;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

@ApiStatus.Internal
public final class CurrentActivityIntegration
implements Integration, Closeable, Application.ActivityLifecycleCallbacks {

private final @NotNull Application application;

public CurrentActivityIntegration(final @NotNull Application application) {
this.application = Objects.requireNonNull(application, "Application is required");
}

@Override
public void register(@NotNull IHub hub, @NotNull SentryOptions options) {
application.registerActivityLifecycleCallbacks(this);
}

@Override
public void onActivityCreated(@NonNull Activity activity, @Nullable Bundle savedInstanceState) {
setCurrentActivity(activity);
}

@Override
public void onActivityStarted(@NonNull Activity activity) {
setCurrentActivity(activity);
}

@Override
public void onActivityResumed(@NonNull Activity activity) {
setCurrentActivity(activity);
}

@Override
public void onActivityPaused(@NonNull Activity activity) {
cleanCurrentActivity(activity);
}

@Override
public void onActivityStopped(@NonNull Activity activity) {
cleanCurrentActivity(activity);
}

@Override
public void onActivitySaveInstanceState(@NonNull Activity activity, @NonNull Bundle outState) {}

@Override
public void onActivityDestroyed(@NonNull Activity activity) {
cleanCurrentActivity(activity);
}

@Override
public void close() throws IOException {
application.unregisterActivityLifecycleCallbacks(this);
CurrentActivityHolder.getInstance().clearActivity();
}

private void cleanCurrentActivity(final @NotNull Activity activity) {
if (CurrentActivityHolder.getInstance().getActivity() == activity) {
CurrentActivityHolder.getInstance().clearActivity();
}
}

private void setCurrentActivity(final @NotNull Activity activity) {
CurrentActivityHolder.getInstance().setActivity(activity);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ final class ManifestMetadataReader {
static final String IDLE_TIMEOUT = "io.sentry.traces.idle-timeout";

static final String ATTACH_SCREENSHOT = "io.sentry.attach-screenshot";
static final String ATTACH_VIEW_HIERARCHY = "io.sentry.attach-view-hierarchy";
static final String CLIENT_REPORTS_ENABLE = "io.sentry.send-client-reports";
static final String COLLECT_ADDITIONAL_CONTEXT = "io.sentry.additional-context";

Expand Down Expand Up @@ -220,6 +221,9 @@ static void applyMetadata(
options.setAttachScreenshot(
readBool(metadata, logger, ATTACH_SCREENSHOT, options.isAttachScreenshot()));

options.setAttachViewHierarchy(
readBool(metadata, logger, ATTACH_VIEW_HIERARCHY, options.isAttachViewHierarchy()));

options.setSendClientReports(
readBool(metadata, logger, CLIENT_REPORTS_ENABLE, options.isSendClientReports()));

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,66 +4,46 @@
import static io.sentry.android.core.internal.util.ScreenshotUtils.takeScreenshot;

import android.app.Activity;
import android.app.Application;
import android.os.Bundle;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import io.sentry.Attachment;
import io.sentry.EventProcessor;
import io.sentry.Hint;
import io.sentry.SentryEvent;
import io.sentry.SentryLevel;
import io.sentry.util.HintUtils;
import io.sentry.util.Objects;
import java.io.Closeable;
import java.io.IOException;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

/**
* ScreenshotEventProcessor responsible for taking a screenshot of the screen when an error is
* captured.
*/
@ApiStatus.Internal
public final class ScreenshotEventProcessor
implements EventProcessor, Application.ActivityLifecycleCallbacks, Closeable {
public final class ScreenshotEventProcessor implements EventProcessor {

private final @NotNull Application application;
private final @NotNull SentryAndroidOptions options;
private final @NotNull BuildInfoProvider buildInfoProvider;
private boolean lifecycleCallbackInstalled = true;

public ScreenshotEventProcessor(
final @NotNull Application application,
final @NotNull SentryAndroidOptions options,
final @NotNull BuildInfoProvider buildInfoProvider) {
this.application = Objects.requireNonNull(application, "Application is required");
this.options = Objects.requireNonNull(options, "SentryAndroidOptions is required");
this.buildInfoProvider =
Objects.requireNonNull(buildInfoProvider, "BuildInfoProvider is required");

application.registerActivityLifecycleCallbacks(this);
}

@SuppressWarnings("NullAway")
@Override
public @NotNull SentryEvent process(final @NotNull SentryEvent event, @NotNull Hint hint) {
if (!lifecycleCallbackInstalled || !event.isErrored()) {
public @NotNull SentryEvent process(final @NotNull SentryEvent event, final @NotNull Hint hint) {
if (!event.isErrored()) {
return event;
}
if (!options.isAttachScreenshot()) {
application.unregisterActivityLifecycleCallbacks(this);
lifecycleCallbackInstalled = false;

this.options
.getLogger()
.log(
SentryLevel.DEBUG,
"attachScreenshot is disabled, ScreenshotEventProcessor isn't installed.");
this.options.getLogger().log(SentryLevel.DEBUG, "attachScreenshot is disabled.");

return event;
}
final Activity activity = CurrentActivityHolder.getInstance().getActivity();
final @Nullable Activity activity = CurrentActivityHolder.getInstance().getActivity();
if (activity == null || HintUtils.isFromHybridSdk(hint)) {
return event;
}
Expand All @@ -77,55 +57,4 @@ public ScreenshotEventProcessor(
hint.set(ANDROID_ACTIVITY, activity);
return event;
}

@Override
public void onActivityCreated(@NonNull Activity activity, @Nullable Bundle savedInstanceState) {
CurrentActivityHolder.getInstance().setActivity(activity);
}

@Override
public void onActivityStarted(@NonNull Activity activity) {
setCurrentActivity(activity);
}

@Override
public void onActivityResumed(@NonNull Activity activity) {
setCurrentActivity(activity);
}

@Override
public void onActivityPaused(@NonNull Activity activity) {
cleanCurrentActivity(activity);
}

@Override
public void onActivityStopped(@NonNull Activity activity) {
cleanCurrentActivity(activity);
}

@Override
public void onActivitySaveInstanceState(@NonNull Activity activity, @NonNull Bundle outState) {}

@Override
public void onActivityDestroyed(@NonNull Activity activity) {
cleanCurrentActivity(activity);
}

@Override
public void close() throws IOException {
if (options.isAttachScreenshot()) {
application.unregisterActivityLifecycleCallbacks(this);
CurrentActivityHolder.getInstance().clearActivity();
}
}

private void cleanCurrentActivity(@NonNull Activity activity) {
if (CurrentActivityHolder.getInstance().getActivity() == activity) {
CurrentActivityHolder.getInstance().clearActivity();
}
}

private void setCurrentActivity(@NonNull Activity activity) {
CurrentActivityHolder.getInstance().setActivity(activity);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,9 @@ public final class SentryAndroidOptions extends SentryOptions {
/** Enables or disables the attach screenshot feature when an error happened. */
private boolean attachScreenshot;

/** Enables or disables the attach view hierarchy feature when an error happened. */
private boolean attachViewHierarchy;

/**
* Enables or disables collecting of device information which requires Inter-Process Communication
* (IPC)
Expand Down Expand Up @@ -329,6 +332,14 @@ public void setAttachScreenshot(boolean attachScreenshot) {
this.attachScreenshot = attachScreenshot;
}

public boolean isAttachViewHierarchy() {
return attachViewHierarchy;
}

public void setAttachViewHierarchy(boolean attachViewHierarchy) {
this.attachViewHierarchy = attachViewHierarchy;
}

public boolean isCollectAdditionalContext() {
return collectAdditionalContext;
}
Expand Down
Loading

0 comments on commit 4a4964e

Please sign in to comment.