diff --git a/features/dd-sdk-android-session-replay/src/main/kotlin/com/datadog/android/sessionreplay/internal/recorder/wrappers/CanvasWrapper.kt b/features/dd-sdk-android-session-replay/src/main/kotlin/com/datadog/android/sessionreplay/internal/recorder/wrappers/CanvasWrapper.kt index f9118aef64..6f2f5a0e05 100644 --- a/features/dd-sdk-android-session-replay/src/main/kotlin/com/datadog/android/sessionreplay/internal/recorder/wrappers/CanvasWrapper.kt +++ b/features/dd-sdk-android-session-replay/src/main/kotlin/com/datadog/android/sessionreplay/internal/recorder/wrappers/CanvasWrapper.kt @@ -13,8 +13,18 @@ import com.datadog.android.api.InternalLogger internal class CanvasWrapper( private val logger: InternalLogger = InternalLogger.UNBOUND ) { + internal fun createCanvas(bitmap: Bitmap): Canvas? { - @Suppress("SwallowedException", "TooGenericExceptionCaught") + if (bitmap.isRecycled || !bitmap.isMutable) { + logger.log( + level = InternalLogger.Level.ERROR, + target = InternalLogger.Target.MAINTAINER, + { INVALID_BITMAP } + ) + return null + } + + @Suppress("TooGenericExceptionCaught") return try { Canvas(bitmap) } catch (e: IllegalStateException) { @@ -38,6 +48,7 @@ internal class CanvasWrapper( } private companion object { + private const val INVALID_BITMAP = "Cannot create canvas: bitmap is either already recycled or immutable" private const val FAILED_TO_CREATE_CANVAS = "Failed to create canvas" } } diff --git a/features/dd-sdk-android-session-replay/src/test/kotlin/com/datadog/android/sessionreplay/internal/recorder/wrappers/CanvasWrapperTest.kt b/features/dd-sdk-android-session-replay/src/test/kotlin/com/datadog/android/sessionreplay/internal/recorder/wrappers/CanvasWrapperTest.kt new file mode 100644 index 0000000000..658c4ae890 --- /dev/null +++ b/features/dd-sdk-android-session-replay/src/test/kotlin/com/datadog/android/sessionreplay/internal/recorder/wrappers/CanvasWrapperTest.kt @@ -0,0 +1,71 @@ +/* + * Unless explicitly stated otherwise all files in this repository are licensed under the Apache License Version 2.0. + * This product includes software developed at Datadog (https://www.datadoghq.com/). + * Copyright 2016-Present Datadog, Inc. + */ + +package com.datadog.android.sessionreplay.internal.recorder.wrappers + +import android.graphics.Bitmap +import com.datadog.android.api.InternalLogger +import com.datadog.android.sessionreplay.forge.ForgeConfigurator +import fr.xgouchet.elmyr.junit5.ForgeConfiguration +import fr.xgouchet.elmyr.junit5.ForgeExtension +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.ExtendWith +import org.junit.jupiter.api.extension.Extensions +import org.mockito.Mock +import org.mockito.junit.jupiter.MockitoExtension +import org.mockito.junit.jupiter.MockitoSettings +import org.mockito.kotlin.doReturn +import org.mockito.kotlin.whenever +import org.mockito.quality.Strictness + +@Extensions( + ExtendWith(MockitoExtension::class), + ExtendWith(ForgeExtension::class) +) +@MockitoSettings(strictness = Strictness.LENIENT) +@ForgeConfiguration(ForgeConfigurator::class) +internal class CanvasWrapperTest { + + lateinit var testedWrapper: CanvasWrapper + + @Mock + lateinit var mockLogger: InternalLogger + + @Mock + lateinit var mockBitmap: Bitmap + + @BeforeEach + fun `set up`() { + testedWrapper = CanvasWrapper(mockLogger) + } + + @Test + fun `M return null W createCanvas() {recycled bitmap}`() { + // Given + whenever(mockBitmap.isRecycled) doReturn true + + // When + val canvas = testedWrapper.createCanvas(mockBitmap) + + // Then + assertThat(canvas).isNull() + } + + @Test + fun `M return null W createCanvas() {immutable bitmap}`() { + // Given + whenever(mockBitmap.isRecycled) doReturn false + whenever(mockBitmap.isMutable) doReturn false + + // When + val canvas = testedWrapper.createCanvas(mockBitmap) + + // Then + assertThat(canvas).isNull() + } +}