From fc20d26ee9aa7cb1d5dfd91916a3b41237a8fe30 Mon Sep 17 00:00:00 2001 From: Krystof Woldrich Date: Mon, 14 Nov 2022 16:04:19 +0100 Subject: [PATCH 01/10] Fix do not add screenshots if should not apply scope data, make setCurrentActivity public --- .../android/core/ScreenshotEventProcessor.java | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/sentry-android-core/src/main/java/io/sentry/android/core/ScreenshotEventProcessor.java b/sentry-android-core/src/main/java/io/sentry/android/core/ScreenshotEventProcessor.java index 48e99e7ad34..500b8d78722 100644 --- a/sentry-android-core/src/main/java/io/sentry/android/core/ScreenshotEventProcessor.java +++ b/sentry-android-core/src/main/java/io/sentry/android/core/ScreenshotEventProcessor.java @@ -17,6 +17,7 @@ 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.ByteArrayOutputStream; import java.io.Closeable; @@ -51,10 +52,18 @@ public ScreenshotEventProcessor( application.registerActivityLifecycleCallbacks(this); } + public void setCurrentActivity(@NonNull Activity activity) { + if (currentActivity != null && currentActivity.get() == activity) { + return; + } + currentActivity = new WeakReference<>(activity); + } + @SuppressWarnings("NullAway") @Override public @NotNull SentryEvent process(final @NotNull SentryEvent event, @NotNull Hint hint) { - if (!lifecycleCallbackInstalled) { + if (!lifecycleCallbackInstalled + || !HintUtils.shouldApplyScopeData(hint)) { return event; } if (!options.isAttachScreenshot()) { @@ -167,13 +176,6 @@ private void cleanCurrentActivity(@NonNull Activity activity) { } } - private void setCurrentActivity(@NonNull Activity activity) { - if (currentActivity != null && currentActivity.get() == activity) { - return; - } - currentActivity = new WeakReference<>(activity); - } - @SuppressLint("NewApi") private boolean isActivityValid(@Nullable Activity activity) { if (activity == null) { From d9a2e695d8afa827460a3f88343b4f109576e29e Mon Sep 17 00:00:00 2001 From: Sentry Github Bot Date: Mon, 14 Nov 2022 15:14:33 +0000 Subject: [PATCH 02/10] Format code --- .../java/io/sentry/android/core/ScreenshotEventProcessor.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/sentry-android-core/src/main/java/io/sentry/android/core/ScreenshotEventProcessor.java b/sentry-android-core/src/main/java/io/sentry/android/core/ScreenshotEventProcessor.java index 500b8d78722..a02ede3d5db 100644 --- a/sentry-android-core/src/main/java/io/sentry/android/core/ScreenshotEventProcessor.java +++ b/sentry-android-core/src/main/java/io/sentry/android/core/ScreenshotEventProcessor.java @@ -62,8 +62,7 @@ public void setCurrentActivity(@NonNull Activity activity) { @SuppressWarnings("NullAway") @Override public @NotNull SentryEvent process(final @NotNull SentryEvent event, @NotNull Hint hint) { - if (!lifecycleCallbackInstalled - || !HintUtils.shouldApplyScopeData(hint)) { + if (!lifecycleCallbackInstalled || !HintUtils.shouldApplyScopeData(hint)) { return event; } if (!options.isAttachScreenshot()) { From 6615b75f03a0818db8e35b196ef6d337bb8bf97e Mon Sep 17 00:00:00 2001 From: Krystof Woldrich Date: Mon, 14 Nov 2022 16:04:19 +0100 Subject: [PATCH 03/10] Expose ScreenshotEventProcessor to allow HybridSDKs to use it --- .../core/AndroidOptionsInitializer.java | 2 +- .../core/ScreenshotEventProcessor.java | 138 +++++++++++------- .../src/main/java/io/sentry/OutboxSender.java | 3 + .../main/java/io/sentry/TypeCheckHint.java | 3 + .../main/java/io/sentry/util/HintUtils.java | 21 +++ 5 files changed, 113 insertions(+), 54 deletions(-) diff --git a/sentry-android-core/src/main/java/io/sentry/android/core/AndroidOptionsInitializer.java b/sentry-android-core/src/main/java/io/sentry/android/core/AndroidOptionsInitializer.java index 0ecbbb9067d..111eb09effa 100644 --- a/sentry-android-core/src/main/java/io/sentry/android/core/AndroidOptionsInitializer.java +++ b/sentry-android-core/src/main/java/io/sentry/android/core/AndroidOptionsInitializer.java @@ -210,7 +210,7 @@ private static void installDefaultIntegrations( options.addIntegration(new FragmentLifecycleIntegration((Application) context, true, true)); } options.addEventProcessor( - new ScreenshotEventProcessor((Application) context, options, buildInfoProvider)); + ScreenshotEventProcessor.createInstance((Application) context, options, buildInfoProvider)); } else { options .getLogger() diff --git a/sentry-android-core/src/main/java/io/sentry/android/core/ScreenshotEventProcessor.java b/sentry-android-core/src/main/java/io/sentry/android/core/ScreenshotEventProcessor.java index 48e99e7ad34..84059568d89 100644 --- a/sentry-android-core/src/main/java/io/sentry/android/core/ScreenshotEventProcessor.java +++ b/sentry-android-core/src/main/java/io/sentry/android/core/ScreenshotEventProcessor.java @@ -17,6 +17,7 @@ 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.ByteArrayOutputStream; import java.io.Closeable; @@ -33,6 +34,8 @@ public final class ScreenshotEventProcessor implements EventProcessor, Application.ActivityLifecycleCallbacks, Closeable { + private static @NotNull ScreenshotEventProcessor instance; + private final @NotNull Application application; private final @NotNull SentryAndroidOptions options; private @Nullable WeakReference currentActivity; @@ -51,10 +54,86 @@ public ScreenshotEventProcessor( application.registerActivityLifecycleCallbacks(this); } + public static ScreenshotEventProcessor createInstance( + final @NotNull Application application, + final @NotNull SentryAndroidOptions options, + final @NotNull BuildInfoProvider buildInfoProvider + ) { + ScreenshotEventProcessor.instance = new ScreenshotEventProcessor(application, options, buildInfoProvider); + return ScreenshotEventProcessor.instance; + } + + public static ScreenshotEventProcessor getInstance() { + return ScreenshotEventProcessor.instance; + } + + public void setCurrentActivity(@NonNull Activity activity) { + if (currentActivity != null && currentActivity.get() == activity) { + return; + } + currentActivity = new WeakReference<>(activity); + } + + public byte[] takeScreenshot() { + if (currentActivity == null) { + return null; + } + + final Activity activity = currentActivity.get(); + if (!isActivityValid(activity) + || activity.getWindow() == null + || activity.getWindow().getDecorView() == null + || activity.getWindow().getDecorView().getRootView() == null) { + this.options + .getLogger() + .log(SentryLevel.DEBUG, "Activity isn't valid, not taking screenshot."); + } + + final View view = activity.getWindow().getDecorView().getRootView(); + if (view.getWidth() <= 0 || view.getHeight() <= 0) { + this.options + .getLogger() + .log(SentryLevel.DEBUG, "View's width and height is zeroed, not taking screenshot."); + return null; + } + + try { + // ARGB_8888 -> This configuration is very flexible and offers the best quality + final Bitmap bitmap = + Bitmap.createBitmap(view.getWidth(), view.getHeight(), Bitmap.Config.ARGB_8888); + + final Canvas canvas = new Canvas(bitmap); + view.draw(canvas); + + final ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); + + // 0 meaning compress for small size, 100 meaning compress for max quality. + // Some formats, like PNG which is lossless, will ignore the quality setting. + bitmap.compress(Bitmap.CompressFormat.PNG, 0, byteArrayOutputStream); + + if (byteArrayOutputStream.size() <= 0) { + this.options + .getLogger() + .log(SentryLevel.DEBUG, "Screenshot is 0 bytes, not attaching the image."); + return null; + } + + // screenshot png is around ~100-150 kb + return byteArrayOutputStream.toByteArray(); + } catch (Throwable e) { + this.options.getLogger().log(SentryLevel.ERROR, "Taking screenshot failed.", e); + } + return null; + } + + @SuppressWarnings("NullAway") @Override public @NotNull SentryEvent process(final @NotNull SentryEvent event, @NotNull Hint hint) { - if (!lifecycleCallbackInstalled) { + if (HintUtils.getIsFromHybridSdk(hint) + || !lifecycleCallbackInstalled + || !event.isErrored() + || currentActivity == null) { return event; } if (!options.isAttachScreenshot()) { @@ -70,53 +149,13 @@ public ScreenshotEventProcessor( return event; } - if (event.isErrored() && currentActivity != null) { - final Activity activity = currentActivity.get(); - if (isActivityValid(activity) - && activity.getWindow() != null - && activity.getWindow().getDecorView() != null - && activity.getWindow().getDecorView().getRootView() != null) { - final View view = activity.getWindow().getDecorView().getRootView(); - - if (view.getWidth() > 0 && view.getHeight() > 0) { - try { - // ARGB_8888 -> This configuration is very flexible and offers the best quality - final Bitmap bitmap = - Bitmap.createBitmap(view.getWidth(), view.getHeight(), Bitmap.Config.ARGB_8888); - - final Canvas canvas = new Canvas(bitmap); - view.draw(canvas); - - final ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); - - // 0 meaning compress for small size, 100 meaning compress for max quality. - // Some formats, like PNG which is lossless, will ignore the quality setting. - bitmap.compress(Bitmap.CompressFormat.PNG, 0, byteArrayOutputStream); - - if (byteArrayOutputStream.size() > 0) { - // screenshot png is around ~100-150 kb - hint.setScreenshot(Attachment.fromScreenshot(byteArrayOutputStream.toByteArray())); - hint.set(ANDROID_ACTIVITY, activity); - } else { - this.options - .getLogger() - .log(SentryLevel.DEBUG, "Screenshot is 0 bytes, not attaching the image."); - } - } catch (Throwable e) { - this.options.getLogger().log(SentryLevel.ERROR, "Taking screenshot failed.", e); - } - } else { - this.options - .getLogger() - .log(SentryLevel.DEBUG, "View's width and height is zeroed, not taking screenshot."); - } - } else { - this.options - .getLogger() - .log(SentryLevel.DEBUG, "Activity isn't valid, not taking screenshot."); - } + final byte[] screenshot = takeScreenshot(); + if (screenshot == null) { + return event; } + hint.setScreenshot(Attachment.fromScreenshot(screenshot)); + hint.set(ANDROID_ACTIVITY, currentActivity.get()); return event; } @@ -167,13 +206,6 @@ private void cleanCurrentActivity(@NonNull Activity activity) { } } - private void setCurrentActivity(@NonNull Activity activity) { - if (currentActivity != null && currentActivity.get() == activity) { - return; - } - currentActivity = new WeakReference<>(activity); - } - @SuppressLint("NewApi") private boolean isActivityValid(@Nullable Activity activity) { if (activity == null) { diff --git a/sentry/src/main/java/io/sentry/OutboxSender.java b/sentry/src/main/java/io/sentry/OutboxSender.java index bd2d9483168..fcf21fb1215 100644 --- a/sentry/src/main/java/io/sentry/OutboxSender.java +++ b/sentry/src/main/java/io/sentry/OutboxSender.java @@ -133,6 +133,9 @@ private void processEnvelope(final @NotNull SentryEnvelope envelope, final @NotN if (event == null) { logEnvelopeItemNull(item, currentItem); } else { + if (event.getSdk() != null) { + HintUtils.setIsFromHybridSdk(hint, event.getSdk().getName()); + } if (envelope.getHeader().getEventId() != null && !envelope.getHeader().getEventId().equals(event.getEventId())) { logUnexpectedEventId(envelope, event.getEventId(), currentItem); diff --git a/sentry/src/main/java/io/sentry/TypeCheckHint.java b/sentry/src/main/java/io/sentry/TypeCheckHint.java index 11e465ac51d..5fde39994ab 100644 --- a/sentry/src/main/java/io/sentry/TypeCheckHint.java +++ b/sentry/src/main/java/io/sentry/TypeCheckHint.java @@ -6,6 +6,9 @@ public final class TypeCheckHint { @ApiStatus.Internal public static final String SENTRY_TYPE_CHECK_HINT = "sentry:typeCheckHint"; + @ApiStatus.Internal public static final String SENTRY_IS_FROM_HYBRID_SDK = "sentry:isFromHybridSdk"; + @ApiStatus.Internal public static final String SENTRY_REACT_NATIVE_SDK_NAME = "sentry.javascript.react-native"; + @ApiStatus.Internal public static final String SENTRY_DART_SDK_NAME = "sentry.dart"; /** Used for Synthetic exceptions. */ public static final String SENTRY_SYNTHETIC_EXCEPTION = "syntheticException"; diff --git a/sentry/src/main/java/io/sentry/util/HintUtils.java b/sentry/src/main/java/io/sentry/util/HintUtils.java index 13c6c87d05b..3933e6fece1 100644 --- a/sentry/src/main/java/io/sentry/util/HintUtils.java +++ b/sentry/src/main/java/io/sentry/util/HintUtils.java @@ -1,6 +1,9 @@ package io.sentry.util; import static io.sentry.TypeCheckHint.SENTRY_TYPE_CHECK_HINT; +import static io.sentry.TypeCheckHint.SENTRY_IS_FROM_HYBRID_SDK; +import static io.sentry.TypeCheckHint.SENTRY_REACT_NATIVE_SDK_NAME; +import static io.sentry.TypeCheckHint.SENTRY_DART_SDK_NAME; import io.sentry.Hint; import io.sentry.ILogger; @@ -16,6 +19,24 @@ public final class HintUtils { private HintUtils() {} + @ApiStatus.Internal + public static void setIsFromHybridSdk(Hint hint, String sdkName) { + if (sdkName.startsWith(SENTRY_REACT_NATIVE_SDK_NAME) + || sdkName.startsWith(SENTRY_DART_SDK_NAME)) { + HintUtils.setIsFromHybridSdk(hint, true); + } + } + + @ApiStatus.Internal + public static void setIsFromHybridSdk(Hint hint, boolean isFromHybridSdk) { + hint.set(SENTRY_IS_FROM_HYBRID_SDK, isFromHybridSdk); + } + + @ApiStatus.Internal + public static boolean getIsFromHybridSdk(Hint hint) { + return Boolean.TRUE.equals(hint.getAs(SENTRY_IS_FROM_HYBRID_SDK, Boolean.class)); + } + @ApiStatus.Internal public static Hint createWithTypeCheckHint(Object typeCheckHint) { Hint hint = new Hint(); From d7b8109ff46bac27c6b54cf51c24ed9882f5b8cc Mon Sep 17 00:00:00 2001 From: Krystof Woldrich Date: Tue, 15 Nov 2022 16:10:16 +0100 Subject: [PATCH 04/10] Revert gradle.properties --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index 8ef36ddf9bc..ca951053ec6 100644 --- a/gradle.properties +++ b/gradle.properties @@ -7,7 +7,7 @@ org.gradle.parallel=true android.useAndroidX=true # Release information -versionName=6.8.0 +versionName=6.7.0 # Override the SDK name on native crashes on Android sentryAndroidSdkName=sentry.native.android From 33eb7e21be2836349a3e6368f8e1680bce820191 Mon Sep 17 00:00:00 2001 From: Sentry Github Bot Date: Tue, 15 Nov 2022 15:13:18 +0000 Subject: [PATCH 05/10] Format code --- .../core/AndroidOptionsInitializer.java | 3 ++- .../core/ScreenshotEventProcessor.java | 25 +++++++++---------- .../main/java/io/sentry/TypeCheckHint.java | 9 +++++-- .../main/java/io/sentry/util/HintUtils.java | 4 +-- 4 files changed, 23 insertions(+), 18 deletions(-) diff --git a/sentry-android-core/src/main/java/io/sentry/android/core/AndroidOptionsInitializer.java b/sentry-android-core/src/main/java/io/sentry/android/core/AndroidOptionsInitializer.java index 111eb09effa..7a703b680e4 100644 --- a/sentry-android-core/src/main/java/io/sentry/android/core/AndroidOptionsInitializer.java +++ b/sentry-android-core/src/main/java/io/sentry/android/core/AndroidOptionsInitializer.java @@ -210,7 +210,8 @@ private static void installDefaultIntegrations( options.addIntegration(new FragmentLifecycleIntegration((Application) context, true, true)); } options.addEventProcessor( - ScreenshotEventProcessor.createInstance((Application) context, options, buildInfoProvider)); + ScreenshotEventProcessor.createInstance( + (Application) context, options, buildInfoProvider)); } else { options .getLogger() diff --git a/sentry-android-core/src/main/java/io/sentry/android/core/ScreenshotEventProcessor.java b/sentry-android-core/src/main/java/io/sentry/android/core/ScreenshotEventProcessor.java index 84059568d89..aaba35a1471 100644 --- a/sentry-android-core/src/main/java/io/sentry/android/core/ScreenshotEventProcessor.java +++ b/sentry-android-core/src/main/java/io/sentry/android/core/ScreenshotEventProcessor.java @@ -55,11 +55,11 @@ public ScreenshotEventProcessor( } public static ScreenshotEventProcessor createInstance( - final @NotNull Application application, - final @NotNull SentryAndroidOptions options, - final @NotNull BuildInfoProvider buildInfoProvider - ) { - ScreenshotEventProcessor.instance = new ScreenshotEventProcessor(application, options, buildInfoProvider); + final @NotNull Application application, + final @NotNull SentryAndroidOptions options, + final @NotNull BuildInfoProvider buildInfoProvider) { + ScreenshotEventProcessor.instance = + new ScreenshotEventProcessor(application, options, buildInfoProvider); return ScreenshotEventProcessor.instance; } @@ -85,22 +85,22 @@ public byte[] takeScreenshot() { || activity.getWindow().getDecorView() == null || activity.getWindow().getDecorView().getRootView() == null) { this.options - .getLogger() - .log(SentryLevel.DEBUG, "Activity isn't valid, not taking screenshot."); + .getLogger() + .log(SentryLevel.DEBUG, "Activity isn't valid, not taking screenshot."); } final View view = activity.getWindow().getDecorView().getRootView(); if (view.getWidth() <= 0 || view.getHeight() <= 0) { this.options - .getLogger() - .log(SentryLevel.DEBUG, "View's width and height is zeroed, not taking screenshot."); + .getLogger() + .log(SentryLevel.DEBUG, "View's width and height is zeroed, not taking screenshot."); return null; } try { // ARGB_8888 -> This configuration is very flexible and offers the best quality final Bitmap bitmap = - Bitmap.createBitmap(view.getWidth(), view.getHeight(), Bitmap.Config.ARGB_8888); + Bitmap.createBitmap(view.getWidth(), view.getHeight(), Bitmap.Config.ARGB_8888); final Canvas canvas = new Canvas(bitmap); view.draw(canvas); @@ -113,8 +113,8 @@ public byte[] takeScreenshot() { if (byteArrayOutputStream.size() <= 0) { this.options - .getLogger() - .log(SentryLevel.DEBUG, "Screenshot is 0 bytes, not attaching the image."); + .getLogger() + .log(SentryLevel.DEBUG, "Screenshot is 0 bytes, not attaching the image."); return null; } @@ -126,7 +126,6 @@ public byte[] takeScreenshot() { return null; } - @SuppressWarnings("NullAway") @Override public @NotNull SentryEvent process(final @NotNull SentryEvent event, @NotNull Hint hint) { diff --git a/sentry/src/main/java/io/sentry/TypeCheckHint.java b/sentry/src/main/java/io/sentry/TypeCheckHint.java index 5fde39994ab..7d6daf47815 100644 --- a/sentry/src/main/java/io/sentry/TypeCheckHint.java +++ b/sentry/src/main/java/io/sentry/TypeCheckHint.java @@ -6,8 +6,13 @@ public final class TypeCheckHint { @ApiStatus.Internal public static final String SENTRY_TYPE_CHECK_HINT = "sentry:typeCheckHint"; - @ApiStatus.Internal public static final String SENTRY_IS_FROM_HYBRID_SDK = "sentry:isFromHybridSdk"; - @ApiStatus.Internal public static final String SENTRY_REACT_NATIVE_SDK_NAME = "sentry.javascript.react-native"; + + @ApiStatus.Internal + public static final String SENTRY_IS_FROM_HYBRID_SDK = "sentry:isFromHybridSdk"; + + @ApiStatus.Internal + public static final String SENTRY_REACT_NATIVE_SDK_NAME = "sentry.javascript.react-native"; + @ApiStatus.Internal public static final String SENTRY_DART_SDK_NAME = "sentry.dart"; /** Used for Synthetic exceptions. */ diff --git a/sentry/src/main/java/io/sentry/util/HintUtils.java b/sentry/src/main/java/io/sentry/util/HintUtils.java index 3933e6fece1..45615433781 100644 --- a/sentry/src/main/java/io/sentry/util/HintUtils.java +++ b/sentry/src/main/java/io/sentry/util/HintUtils.java @@ -1,9 +1,9 @@ package io.sentry.util; -import static io.sentry.TypeCheckHint.SENTRY_TYPE_CHECK_HINT; +import static io.sentry.TypeCheckHint.SENTRY_DART_SDK_NAME; import static io.sentry.TypeCheckHint.SENTRY_IS_FROM_HYBRID_SDK; import static io.sentry.TypeCheckHint.SENTRY_REACT_NATIVE_SDK_NAME; -import static io.sentry.TypeCheckHint.SENTRY_DART_SDK_NAME; +import static io.sentry.TypeCheckHint.SENTRY_TYPE_CHECK_HINT; import io.sentry.Hint; import io.sentry.ILogger; From 98459b9e1dfcebe779f41b9dcbb3c239a3f843cf Mon Sep 17 00:00:00 2001 From: Krystof Woldrich Date: Tue, 15 Nov 2022 16:15:30 +0100 Subject: [PATCH 06/10] Return correctly when invalid activity --- .../java/io/sentry/android/core/ScreenshotEventProcessor.java | 1 + 1 file changed, 1 insertion(+) diff --git a/sentry-android-core/src/main/java/io/sentry/android/core/ScreenshotEventProcessor.java b/sentry-android-core/src/main/java/io/sentry/android/core/ScreenshotEventProcessor.java index aaba35a1471..12873d464af 100644 --- a/sentry-android-core/src/main/java/io/sentry/android/core/ScreenshotEventProcessor.java +++ b/sentry-android-core/src/main/java/io/sentry/android/core/ScreenshotEventProcessor.java @@ -87,6 +87,7 @@ public byte[] takeScreenshot() { this.options .getLogger() .log(SentryLevel.DEBUG, "Activity isn't valid, not taking screenshot."); + return null; } final View view = activity.getWindow().getDecorView().getRootView(); From ba663652a323875047130db038b02b2e94761200 Mon Sep 17 00:00:00 2001 From: Krystof Woldrich Date: Tue, 15 Nov 2022 16:29:30 +0100 Subject: [PATCH 07/10] Update api --- sentry-android-core/api/sentry-android-core.api | 4 ++++ sentry/api/sentry.api | 6 ++++++ 2 files changed, 10 insertions(+) diff --git a/sentry-android-core/api/sentry-android-core.api b/sentry-android-core/api/sentry-android-core.api index 4bdcfecd270..16628e6325a 100644 --- a/sentry-android-core/api/sentry-android-core.api +++ b/sentry-android-core/api/sentry-android-core.api @@ -107,6 +107,8 @@ public final class io/sentry/android/core/PhoneStateBreadcrumbsIntegration : io/ public final class io/sentry/android/core/ScreenshotEventProcessor : android/app/Application$ActivityLifecycleCallbacks, io/sentry/EventProcessor, java/io/Closeable { public fun (Landroid/app/Application;Lio/sentry/android/core/SentryAndroidOptions;Lio/sentry/android/core/BuildInfoProvider;)V public fun close ()V + public static fun createInstance (Landroid/app/Application;Lio/sentry/android/core/SentryAndroidOptions;Lio/sentry/android/core/BuildInfoProvider;)Lio/sentry/android/core/ScreenshotEventProcessor; + public static fun getInstance ()Lio/sentry/android/core/ScreenshotEventProcessor; public fun onActivityCreated (Landroid/app/Activity;Landroid/os/Bundle;)V public fun onActivityDestroyed (Landroid/app/Activity;)V public fun onActivityPaused (Landroid/app/Activity;)V @@ -115,6 +117,8 @@ public final class io/sentry/android/core/ScreenshotEventProcessor : android/app public fun onActivityStarted (Landroid/app/Activity;)V public fun onActivityStopped (Landroid/app/Activity;)V public fun process (Lio/sentry/SentryEvent;Lio/sentry/Hint;)Lio/sentry/SentryEvent; + public fun setCurrentActivity (Landroid/app/Activity;)V + public fun takeScreenshot ()[B } public final class io/sentry/android/core/SentryAndroid { diff --git a/sentry/api/sentry.api b/sentry/api/sentry.api index 55af4a3b1d5..993e3a38ff7 100644 --- a/sentry/api/sentry.api +++ b/sentry/api/sentry.api @@ -1897,6 +1897,9 @@ public final class io/sentry/TypeCheckHint { public static final field OKHTTP_RESPONSE Ljava/lang/String; public static final field OPEN_FEIGN_REQUEST Ljava/lang/String; public static final field OPEN_FEIGN_RESPONSE Ljava/lang/String; + public static final field SENTRY_DART_SDK_NAME Ljava/lang/String; + public static final field SENTRY_IS_FROM_HYBRID_SDK Ljava/lang/String; + public static final field SENTRY_REACT_NATIVE_SDK_NAME Ljava/lang/String; public static final field SENTRY_SYNTHETIC_EXCEPTION Ljava/lang/String; public static final field SENTRY_TYPE_CHECK_HINT Ljava/lang/String; public static final field SERVLET_REQUEST Ljava/lang/String; @@ -3301,12 +3304,15 @@ public final class io/sentry/util/FileUtils { public final class io/sentry/util/HintUtils { public static fun createWithTypeCheckHint (Ljava/lang/Object;)Lio/sentry/Hint; + public static fun getIsFromHybridSdk (Lio/sentry/Hint;)Z public static fun getSentrySdkHint (Lio/sentry/Hint;)Ljava/lang/Object; public static fun hasType (Lio/sentry/Hint;Ljava/lang/Class;)Z public static fun runIfDoesNotHaveType (Lio/sentry/Hint;Ljava/lang/Class;Lio/sentry/util/HintUtils$SentryNullableConsumer;)V public static fun runIfHasType (Lio/sentry/Hint;Ljava/lang/Class;Lio/sentry/util/HintUtils$SentryConsumer;)V public static fun runIfHasType (Lio/sentry/Hint;Ljava/lang/Class;Lio/sentry/util/HintUtils$SentryConsumer;Lio/sentry/util/HintUtils$SentryHintFallback;)V public static fun runIfHasTypeLogIfNot (Lio/sentry/Hint;Ljava/lang/Class;Lio/sentry/ILogger;Lio/sentry/util/HintUtils$SentryConsumer;)V + public static fun setIsFromHybridSdk (Lio/sentry/Hint;Ljava/lang/String;)V + public static fun setIsFromHybridSdk (Lio/sentry/Hint;Z)V public static fun setTypeCheckHint (Lio/sentry/Hint;Ljava/lang/Object;)V public static fun shouldApplyScopeData (Lio/sentry/Hint;)Z } From 465bbf3894146169dad9fa126cf59da8aed259c9 Mon Sep 17 00:00:00 2001 From: Krystof Woldrich Date: Wed, 16 Nov 2022 13:47:54 +0100 Subject: [PATCH 08/10] Extract screenshot logic to static method, create activity holder singleton --- .../api/sentry-android-core.api | 14 +- .../core/AndroidOptionsInitializer.java | 4 +- .../android/core/CurrentActivityHolder.java | 42 ++++++ .../core/ScreenshotEventProcessor.java | 130 +++--------------- .../core/internal/util/ActivityUtils.java | 20 +++ .../core/internal/util/ScreenshotUtils.java | 64 +++++++++ .../core/ScreenshotEventProcessorTest.kt | 3 +- .../main/java/io/sentry/util/HintUtils.java | 9 +- 8 files changed, 160 insertions(+), 126 deletions(-) create mode 100644 sentry-android-core/src/main/java/io/sentry/android/core/CurrentActivityHolder.java create mode 100644 sentry-android-core/src/main/java/io/sentry/android/core/internal/util/ActivityUtils.java create mode 100644 sentry-android-core/src/main/java/io/sentry/android/core/internal/util/ScreenshotUtils.java diff --git a/sentry-android-core/api/sentry-android-core.api b/sentry-android-core/api/sentry-android-core.api index 16628e6325a..1690a8a5033 100644 --- a/sentry-android-core/api/sentry-android-core.api +++ b/sentry-android-core/api/sentry-android-core.api @@ -72,6 +72,14 @@ public final class io/sentry/android/core/BuildInfoProvider { public fun isEmulator ()Ljava/lang/Boolean; } +public class io/sentry/android/core/CurrentActivityHolder { + public fun ()V + public fun clearActivity ()V + public fun getActivity ()Landroid/app/Activity; + public static fun getInstance ()Lio/sentry/android/core/CurrentActivityHolder; + public fun setActivity (Landroid/app/Activity;)V +} + public abstract class io/sentry/android/core/EnvelopeFileObserverIntegration : io/sentry/Integration, java/io/Closeable { public fun ()V public fun close ()V @@ -105,10 +113,8 @@ public final class io/sentry/android/core/PhoneStateBreadcrumbsIntegration : io/ } public final class io/sentry/android/core/ScreenshotEventProcessor : android/app/Application$ActivityLifecycleCallbacks, io/sentry/EventProcessor, java/io/Closeable { - public fun (Landroid/app/Application;Lio/sentry/android/core/SentryAndroidOptions;Lio/sentry/android/core/BuildInfoProvider;)V + public fun (Landroid/app/Application;Lio/sentry/android/core/SentryAndroidOptions;)V public fun close ()V - public static fun createInstance (Landroid/app/Application;Lio/sentry/android/core/SentryAndroidOptions;Lio/sentry/android/core/BuildInfoProvider;)Lio/sentry/android/core/ScreenshotEventProcessor; - public static fun getInstance ()Lio/sentry/android/core/ScreenshotEventProcessor; public fun onActivityCreated (Landroid/app/Activity;Landroid/os/Bundle;)V public fun onActivityDestroyed (Landroid/app/Activity;)V public fun onActivityPaused (Landroid/app/Activity;)V @@ -117,8 +123,6 @@ public final class io/sentry/android/core/ScreenshotEventProcessor : android/app public fun onActivityStarted (Landroid/app/Activity;)V public fun onActivityStopped (Landroid/app/Activity;)V public fun process (Lio/sentry/SentryEvent;Lio/sentry/Hint;)Lio/sentry/SentryEvent; - public fun setCurrentActivity (Landroid/app/Activity;)V - public fun takeScreenshot ()[B } public final class io/sentry/android/core/SentryAndroid { diff --git a/sentry-android-core/src/main/java/io/sentry/android/core/AndroidOptionsInitializer.java b/sentry-android-core/src/main/java/io/sentry/android/core/AndroidOptionsInitializer.java index 7a703b680e4..a375653d7d4 100644 --- a/sentry-android-core/src/main/java/io/sentry/android/core/AndroidOptionsInitializer.java +++ b/sentry-android-core/src/main/java/io/sentry/android/core/AndroidOptionsInitializer.java @@ -209,9 +209,7 @@ private static void installDefaultIntegrations( if (isFragmentAvailable) { options.addIntegration(new FragmentLifecycleIntegration((Application) context, true, true)); } - options.addEventProcessor( - ScreenshotEventProcessor.createInstance( - (Application) context, options, buildInfoProvider)); + options.addEventProcessor(new ScreenshotEventProcessor((Application) context, options)); } else { options .getLogger() diff --git a/sentry-android-core/src/main/java/io/sentry/android/core/CurrentActivityHolder.java b/sentry-android-core/src/main/java/io/sentry/android/core/CurrentActivityHolder.java new file mode 100644 index 00000000000..c7b4a918172 --- /dev/null +++ b/sentry-android-core/src/main/java/io/sentry/android/core/CurrentActivityHolder.java @@ -0,0 +1,42 @@ +package io.sentry.android.core; + +import android.app.Activity; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import java.lang.ref.WeakReference; +import org.jetbrains.annotations.ApiStatus; + +@ApiStatus.Internal +public class CurrentActivityHolder { + + private static @Nullable CurrentActivityHolder instance; + + private @Nullable WeakReference currentActivity; + + public static CurrentActivityHolder getInstance() { + if (instance != null) { + return instance; + } + instance = new CurrentActivityHolder(); + return instance; + } + + public @Nullable Activity getActivity() { + if (currentActivity != null) { + return currentActivity.get(); + } + return null; + } + + public void setActivity(@NonNull Activity activity) { + if (currentActivity != null && currentActivity.get() == activity) { + return; + } + + currentActivity = new WeakReference<>(activity); + } + + public void clearActivity() { + currentActivity = null; + } +} diff --git a/sentry-android-core/src/main/java/io/sentry/android/core/ScreenshotEventProcessor.java b/sentry-android-core/src/main/java/io/sentry/android/core/ScreenshotEventProcessor.java index 12873d464af..a5e0ced2000 100644 --- a/sentry-android-core/src/main/java/io/sentry/android/core/ScreenshotEventProcessor.java +++ b/sentry-android-core/src/main/java/io/sentry/android/core/ScreenshotEventProcessor.java @@ -1,15 +1,11 @@ package io.sentry.android.core; import static io.sentry.TypeCheckHint.ANDROID_ACTIVITY; +import static io.sentry.android.core.internal.util.ScreenshotUtils.takeScreenshot; -import android.annotation.SuppressLint; import android.app.Activity; import android.app.Application; -import android.graphics.Bitmap; -import android.graphics.Canvas; -import android.os.Build; import android.os.Bundle; -import android.view.View; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import io.sentry.Attachment; @@ -19,10 +15,8 @@ import io.sentry.SentryLevel; import io.sentry.util.HintUtils; import io.sentry.util.Objects; -import java.io.ByteArrayOutputStream; import java.io.Closeable; import java.io.IOException; -import java.lang.ref.WeakReference; import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; @@ -34,106 +28,25 @@ public final class ScreenshotEventProcessor implements EventProcessor, Application.ActivityLifecycleCallbacks, Closeable { - private static @NotNull ScreenshotEventProcessor instance; - private final @NotNull Application application; private final @NotNull SentryAndroidOptions options; - private @Nullable WeakReference currentActivity; - private final @NotNull BuildInfoProvider buildInfoProvider; + private final @NotNull CurrentActivityHolder currentActivityHolder; private boolean lifecycleCallbackInstalled = true; public ScreenshotEventProcessor( - final @NotNull Application application, - final @NotNull SentryAndroidOptions options, - final @NotNull BuildInfoProvider buildInfoProvider) { + final @NotNull Application application, final @NotNull SentryAndroidOptions options) { this.application = Objects.requireNonNull(application, "Application is required"); this.options = Objects.requireNonNull(options, "SentryAndroidOptions is required"); - this.buildInfoProvider = - Objects.requireNonNull(buildInfoProvider, "BuildInfoProvider is required"); + this.currentActivityHolder = CurrentActivityHolder.getInstance(); application.registerActivityLifecycleCallbacks(this); } - public static ScreenshotEventProcessor createInstance( - final @NotNull Application application, - final @NotNull SentryAndroidOptions options, - final @NotNull BuildInfoProvider buildInfoProvider) { - ScreenshotEventProcessor.instance = - new ScreenshotEventProcessor(application, options, buildInfoProvider); - return ScreenshotEventProcessor.instance; - } - - public static ScreenshotEventProcessor getInstance() { - return ScreenshotEventProcessor.instance; - } - - public void setCurrentActivity(@NonNull Activity activity) { - if (currentActivity != null && currentActivity.get() == activity) { - return; - } - currentActivity = new WeakReference<>(activity); - } - - public byte[] takeScreenshot() { - if (currentActivity == null) { - return null; - } - - final Activity activity = currentActivity.get(); - if (!isActivityValid(activity) - || activity.getWindow() == null - || activity.getWindow().getDecorView() == null - || activity.getWindow().getDecorView().getRootView() == null) { - this.options - .getLogger() - .log(SentryLevel.DEBUG, "Activity isn't valid, not taking screenshot."); - return null; - } - - final View view = activity.getWindow().getDecorView().getRootView(); - if (view.getWidth() <= 0 || view.getHeight() <= 0) { - this.options - .getLogger() - .log(SentryLevel.DEBUG, "View's width and height is zeroed, not taking screenshot."); - return null; - } - - try { - // ARGB_8888 -> This configuration is very flexible and offers the best quality - final Bitmap bitmap = - Bitmap.createBitmap(view.getWidth(), view.getHeight(), Bitmap.Config.ARGB_8888); - - final Canvas canvas = new Canvas(bitmap); - view.draw(canvas); - - final ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); - - // 0 meaning compress for small size, 100 meaning compress for max quality. - // Some formats, like PNG which is lossless, will ignore the quality setting. - bitmap.compress(Bitmap.CompressFormat.PNG, 0, byteArrayOutputStream); - - if (byteArrayOutputStream.size() <= 0) { - this.options - .getLogger() - .log(SentryLevel.DEBUG, "Screenshot is 0 bytes, not attaching the image."); - return null; - } - - // screenshot png is around ~100-150 kb - return byteArrayOutputStream.toByteArray(); - } catch (Throwable e) { - this.options.getLogger().log(SentryLevel.ERROR, "Taking screenshot failed.", e); - } - return null; - } - @SuppressWarnings("NullAway") @Override public @NotNull SentryEvent process(final @NotNull SentryEvent event, @NotNull Hint hint) { - if (HintUtils.getIsFromHybridSdk(hint) - || !lifecycleCallbackInstalled - || !event.isErrored() - || currentActivity == null) { + if (!lifecycleCallbackInstalled + || !event.isErrored()) { return event; } if (!options.isAttachScreenshot()) { @@ -148,20 +61,25 @@ public byte[] takeScreenshot() { return event; } + if (currentActivityHolder.getActivity() == null + || HintUtils.isFromHybridSdk(hint)) { + return event; + } - final byte[] screenshot = takeScreenshot(); + final byte[] screenshot = + takeScreenshot(currentActivityHolder.getActivity(), options.getLogger()); if (screenshot == null) { return event; } hint.setScreenshot(Attachment.fromScreenshot(screenshot)); - hint.set(ANDROID_ACTIVITY, currentActivity.get()); + hint.set(ANDROID_ACTIVITY, currentActivityHolder.getActivity()); return event; } @Override public void onActivityCreated(@NonNull Activity activity, @Nullable Bundle savedInstanceState) { - setCurrentActivity(activity); + currentActivityHolder.setActivity(activity); } @Override @@ -196,25 +114,17 @@ public void onActivityDestroyed(@NonNull Activity activity) { public void close() throws IOException { if (options.isAttachScreenshot()) { application.unregisterActivityLifecycleCallbacks(this); - currentActivity = null; + currentActivityHolder.clearActivity(); } } - private void cleanCurrentActivity(@NonNull Activity activity) { - if (currentActivity != null && currentActivity.get() == activity) { - currentActivity = null; - } + private void setCurrentActivity(@NonNull Activity activity) { + currentActivityHolder.setActivity(activity); } - @SuppressLint("NewApi") - private boolean isActivityValid(@Nullable Activity activity) { - if (activity == null) { - return false; - } - if (buildInfoProvider.getSdkInfoVersion() >= Build.VERSION_CODES.JELLY_BEAN_MR1) { - return !activity.isFinishing() && !activity.isDestroyed(); - } else { - return !activity.isFinishing(); + private void cleanCurrentActivity(@NonNull Activity activity) { + if (currentActivityHolder.getActivity() == activity) { + currentActivityHolder.clearActivity(); } } } diff --git a/sentry-android-core/src/main/java/io/sentry/android/core/internal/util/ActivityUtils.java b/sentry-android-core/src/main/java/io/sentry/android/core/internal/util/ActivityUtils.java new file mode 100644 index 00000000000..3a494eb4149 --- /dev/null +++ b/sentry-android-core/src/main/java/io/sentry/android/core/internal/util/ActivityUtils.java @@ -0,0 +1,20 @@ +package io.sentry.android.core.internal.util; + +import android.app.Activity; +import android.os.Build; +import androidx.annotation.Nullable; +import org.jetbrains.annotations.ApiStatus; + +@ApiStatus.Internal +public class ActivityUtils { + public static boolean isActivityValid(@Nullable Activity activity) { + if (activity == null) { + return false; + } + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { + return !activity.isFinishing() && !activity.isDestroyed(); + } else { + return !activity.isFinishing(); + } + } +} diff --git a/sentry-android-core/src/main/java/io/sentry/android/core/internal/util/ScreenshotUtils.java b/sentry-android-core/src/main/java/io/sentry/android/core/internal/util/ScreenshotUtils.java new file mode 100644 index 00000000000..3c1703c0d2f --- /dev/null +++ b/sentry-android-core/src/main/java/io/sentry/android/core/internal/util/ScreenshotUtils.java @@ -0,0 +1,64 @@ +package io.sentry.android.core.internal.util; + +import static io.sentry.android.core.internal.util.ActivityUtils.isActivityValid; + +import android.app.Activity; +import android.graphics.Bitmap; +import android.graphics.Canvas; +import android.view.View; +import androidx.annotation.Nullable; +import io.sentry.ILogger; +import io.sentry.SentryLevel; +import java.io.ByteArrayOutputStream; +import org.jetbrains.annotations.ApiStatus; +import org.jetbrains.annotations.NotNull; + +@ApiStatus.Internal +public class ScreenshotUtils { + public static @Nullable byte[] takeScreenshot( + final @Nullable Activity activity, final @NotNull ILogger logger) { + if (activity == null) { + return null; + } + + if (!isActivityValid(activity) + || activity.getWindow() == null + || activity.getWindow().getDecorView() == null + || activity.getWindow().getDecorView().getRootView() == null) { + logger.log(SentryLevel.DEBUG, "Activity isn't valid, not taking screenshot."); + return null; + } + + final View view = activity.getWindow().getDecorView().getRootView(); + if (view.getWidth() <= 0 || view.getHeight() <= 0) { + logger.log(SentryLevel.DEBUG, "View's width and height is zeroed, not taking screenshot."); + return null; + } + + try { + // ARGB_8888 -> This configuration is very flexible and offers the best quality + final Bitmap bitmap = + Bitmap.createBitmap(view.getWidth(), view.getHeight(), Bitmap.Config.ARGB_8888); + + final Canvas canvas = new Canvas(bitmap); + view.draw(canvas); + + final ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); + + // 0 meaning compress for small size, 100 meaning compress for max quality. + // Some formats, like PNG which is lossless, will ignore the quality setting. + bitmap.compress(Bitmap.CompressFormat.PNG, 0, byteArrayOutputStream); + + if (byteArrayOutputStream.size() <= 0) { + logger.log(SentryLevel.DEBUG, "Screenshot is 0 bytes, not attaching the image."); + return null; + } + + // screenshot png is around ~100-150 kb + return byteArrayOutputStream.toByteArray(); + } catch (Throwable e) { + logger.log(SentryLevel.ERROR, "Taking screenshot failed.", e); + } + return null; + } +} diff --git a/sentry-android-core/src/test/java/io/sentry/android/core/ScreenshotEventProcessorTest.kt b/sentry-android-core/src/test/java/io/sentry/android/core/ScreenshotEventProcessorTest.kt index 3d81b176bff..c220c73fb20 100644 --- a/sentry-android-core/src/test/java/io/sentry/android/core/ScreenshotEventProcessorTest.kt +++ b/sentry-android-core/src/test/java/io/sentry/android/core/ScreenshotEventProcessorTest.kt @@ -28,7 +28,6 @@ class ScreenshotEventProcessorTest { private class Fixture { val application = mock() - val buildInfo = mock() val activity = mock() val window = mock() val view = mock() @@ -49,7 +48,7 @@ class ScreenshotEventProcessorTest { fun getSut(attachScreenshot: Boolean = false): ScreenshotEventProcessor { options.isAttachScreenshot = attachScreenshot - return ScreenshotEventProcessor(application, options, buildInfo) + return ScreenshotEventProcessor(application, options) } } diff --git a/sentry/src/main/java/io/sentry/util/HintUtils.java b/sentry/src/main/java/io/sentry/util/HintUtils.java index 45615433781..57ba21ea086 100644 --- a/sentry/src/main/java/io/sentry/util/HintUtils.java +++ b/sentry/src/main/java/io/sentry/util/HintUtils.java @@ -19,21 +19,18 @@ public final class HintUtils { private HintUtils() {} - @ApiStatus.Internal - public static void setIsFromHybridSdk(Hint hint, String sdkName) { + public static void setIsFromHybridSdk(@NotNull Hint hint, @NotNull String sdkName) { if (sdkName.startsWith(SENTRY_REACT_NATIVE_SDK_NAME) || sdkName.startsWith(SENTRY_DART_SDK_NAME)) { HintUtils.setIsFromHybridSdk(hint, true); } } - @ApiStatus.Internal - public static void setIsFromHybridSdk(Hint hint, boolean isFromHybridSdk) { + public static void setIsFromHybridSdk(@NotNull Hint hint, boolean isFromHybridSdk) { hint.set(SENTRY_IS_FROM_HYBRID_SDK, isFromHybridSdk); } - @ApiStatus.Internal - public static boolean getIsFromHybridSdk(Hint hint) { + public static boolean isFromHybridSdk(@NotNull Hint hint) { return Boolean.TRUE.equals(hint.getAs(SENTRY_IS_FROM_HYBRID_SDK, Boolean.class)); } From 706dc8e7873676648c375f56a320e49e3f695e56 Mon Sep 17 00:00:00 2001 From: Sentry Github Bot Date: Wed, 16 Nov 2022 12:51:02 +0000 Subject: [PATCH 09/10] Format code --- .../io/sentry/android/core/ScreenshotEventProcessor.java | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/sentry-android-core/src/main/java/io/sentry/android/core/ScreenshotEventProcessor.java b/sentry-android-core/src/main/java/io/sentry/android/core/ScreenshotEventProcessor.java index a5e0ced2000..f14f9e2abe6 100644 --- a/sentry-android-core/src/main/java/io/sentry/android/core/ScreenshotEventProcessor.java +++ b/sentry-android-core/src/main/java/io/sentry/android/core/ScreenshotEventProcessor.java @@ -45,8 +45,7 @@ public ScreenshotEventProcessor( @SuppressWarnings("NullAway") @Override public @NotNull SentryEvent process(final @NotNull SentryEvent event, @NotNull Hint hint) { - if (!lifecycleCallbackInstalled - || !event.isErrored()) { + if (!lifecycleCallbackInstalled || !event.isErrored()) { return event; } if (!options.isAttachScreenshot()) { @@ -61,8 +60,7 @@ public ScreenshotEventProcessor( return event; } - if (currentActivityHolder.getActivity() == null - || HintUtils.isFromHybridSdk(hint)) { + if (currentActivityHolder.getActivity() == null || HintUtils.isFromHybridSdk(hint)) { return event; } From 8c89da757efc3d8a3f2e5ffa24419e59a4b40fa1 Mon Sep 17 00:00:00 2001 From: Krystof Woldrich Date: Wed, 16 Nov 2022 13:53:24 +0100 Subject: [PATCH 10/10] Refactor --- .../io/sentry/android/core/ScreenshotEventProcessor.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sentry-android-core/src/main/java/io/sentry/android/core/ScreenshotEventProcessor.java b/sentry-android-core/src/main/java/io/sentry/android/core/ScreenshotEventProcessor.java index f14f9e2abe6..22582cece2c 100644 --- a/sentry-android-core/src/main/java/io/sentry/android/core/ScreenshotEventProcessor.java +++ b/sentry-android-core/src/main/java/io/sentry/android/core/ScreenshotEventProcessor.java @@ -116,13 +116,13 @@ public void close() throws IOException { } } - private void setCurrentActivity(@NonNull Activity activity) { - currentActivityHolder.setActivity(activity); - } - private void cleanCurrentActivity(@NonNull Activity activity) { if (currentActivityHolder.getActivity() == activity) { currentActivityHolder.clearActivity(); } } + + private void setCurrentActivity(@NonNull Activity activity) { + currentActivityHolder.setActivity(activity); + } }