diff --git a/CHANGELOG.md b/CHANGELOG.md index edeb6b81..5237b124 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,7 @@ ## Next +- no user facing changes + ## 3.9.2 - 2024-11-12 - fix: allow changing person properties after identify ([#205](https://github.com/PostHog/posthog-android/pull/205)) diff --git a/posthog-android/api/posthog-android.api b/posthog-android/api/posthog-android.api index aab34421..3517f6b8 100644 --- a/posthog-android/api/posthog-android.api +++ b/posthog-android/api/posthog-android.api @@ -42,6 +42,8 @@ public final class com/posthog/android/internal/MainHandler { } public final class com/posthog/android/internal/PostHogAndroidUtilsKt { + public static final fun base64 (Landroid/graphics/Bitmap;Landroid/graphics/Bitmap$CompressFormat;I)Ljava/lang/String; + public static synthetic fun base64$default (Landroid/graphics/Bitmap;Landroid/graphics/Bitmap$CompressFormat;IILjava/lang/Object;)Ljava/lang/String; public static final fun getApplicationInfo (Landroid/content/Context;)Landroid/content/pm/ApplicationInfo; } diff --git a/posthog-android/src/main/java/com/posthog/android/internal/PostHogAndroidUtils.kt b/posthog-android/src/main/java/com/posthog/android/internal/PostHogAndroidUtils.kt index 63ae20ad..e3c1e214 100644 --- a/posthog-android/src/main/java/com/posthog/android/internal/PostHogAndroidUtils.kt +++ b/posthog-android/src/main/java/com/posthog/android/internal/PostHogAndroidUtils.kt @@ -9,16 +9,19 @@ import android.content.pm.ApplicationInfo import android.content.pm.PackageInfo import android.content.pm.PackageManager import android.content.pm.PackageManager.GET_META_DATA +import android.graphics.Bitmap import android.graphics.Point import android.net.ConnectivityManager import android.net.Uri import android.os.Build import android.os.Process import android.telephony.TelephonyManager +import android.util.Base64 import android.util.DisplayMetrics import android.view.WindowManager import com.posthog.PostHogInternal import com.posthog.android.PostHogAndroidConfig +import java.io.ByteArrayOutputStream @Suppress("DEPRECATION") internal fun getPackageInfo( @@ -205,3 +208,52 @@ public fun getApplicationInfo(context: Context): ApplicationInfo = .packageManager .getApplicationInfo(context.packageName, GET_META_DATA) } + +private fun Bitmap.isValid(): Boolean { + return !isRecycled && + width > 0 && + height > 0 +} + +@PostHogInternal +@Suppress("DEPRECATION") +public fun Bitmap.base64( + format: Bitmap.CompressFormat = Bitmap.CompressFormat.JPEG, + quality: Int = 30, +): String? { + if (!isValid()) { + return null + } + + val lossyFormat = + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { + Bitmap.CompressFormat.WEBP_LOSSY + } else { + Bitmap.CompressFormat.WEBP + } + + val losslessFormat = + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { + Bitmap.CompressFormat.WEBP_LOSSLESS + } else { + Bitmap.CompressFormat.WEBP + } + + val htmlFormat = + when (format) { + Bitmap.CompressFormat.JPEG -> "jpeg" + Bitmap.CompressFormat.PNG -> "png" + Bitmap.CompressFormat.WEBP -> "webp" + lossyFormat -> "webp" + losslessFormat -> "webp" + else -> "jpeg" + } + + ByteArrayOutputStream(allocationByteCount).use { + // we can make format and type configurable + compress(format, quality, it) + val byteArray = it.toByteArray() + val encoded = Base64.encodeToString(byteArray, Base64.DEFAULT) ?: return null + return "data:image/$htmlFormat;base64,$encoded" + } +} diff --git a/posthog-android/src/main/java/com/posthog/android/replay/PostHogReplayIntegration.kt b/posthog-android/src/main/java/com/posthog/android/replay/PostHogReplayIntegration.kt index e02ca8fb..29848ebc 100644 --- a/posthog-android/src/main/java/com/posthog/android/replay/PostHogReplayIntegration.kt +++ b/posthog-android/src/main/java/com/posthog/android/replay/PostHogReplayIntegration.kt @@ -24,7 +24,6 @@ import android.os.Build import android.os.Handler import android.os.HandlerThread import android.text.InputType -import android.util.Base64 import android.util.TypedValue import android.view.Gravity import android.view.MotionEvent @@ -54,6 +53,7 @@ import com.posthog.PostHog import com.posthog.PostHogIntegration import com.posthog.android.PostHogAndroidConfig import com.posthog.android.internal.MainHandler +import com.posthog.android.internal.base64 import com.posthog.android.internal.densityValue import com.posthog.android.internal.displayMetrics import com.posthog.android.internal.screenSize @@ -83,7 +83,6 @@ import curtains.onDecorViewReady import curtains.phoneWindow import curtains.touchEventInterceptors import curtains.windowAttachCount -import java.io.ByteArrayOutputStream import java.lang.ref.WeakReference import java.util.WeakHashMap import java.util.concurrent.CountDownLatch @@ -121,6 +120,10 @@ public class PostHogReplayIntegration( private val isSessionReplayEnabled: Boolean get() = PostHog.isSessionReplayActive() + // flutter captures snapshots, so we don't need to capture them here + private val isNativeSdk: Boolean + get() = (config.sdkName != "posthog-flutter") + private fun addView( view: View, added: Boolean = true, @@ -144,7 +147,7 @@ public class PostHogReplayIntegration( config.dateProvider, config.sessionReplayConfig.debouncerDelayMs, ) { - if (!isSessionReplayEnabled) { + if (!isSessionReplayEnabled || !isNativeSdk) { return@onNextDraw } val timestamp = config.dateProvider.currentTimeMillis() @@ -1096,26 +1099,6 @@ public class PostHogReplayIntegration( return null } - private fun Bitmap.isValid(): Boolean { - return !isRecycled && - width > 0 && - height > 0 - } - - private fun Bitmap.base64(): String? { - if (!isValid()) { - return null - } - - ByteArrayOutputStream(allocationByteCount).use { - // we can make format and type configurable - compress(Bitmap.CompressFormat.JPEG, 30, it) - val byteArray = it.toByteArray() - val encoded = Base64.encodeToString(byteArray, Base64.DEFAULT) ?: return null - return "data:image/jpeg;base64,$encoded" - } - } - private fun Drawable.base64( width: Int, height: Int,