Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: recording for flutter does not capture screenshots on both sides #208

Merged
merged 3 commits into from
Nov 26, 2024
Merged
Show file tree
Hide file tree
Changes from all 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
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -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))
Expand Down
2 changes: 2 additions & 0 deletions posthog-android/api/posthog-android.api
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down Expand Up @@ -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"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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")

Choose a reason for hiding this comment

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

I imagine this is a computed property by design?

Copy link
Member Author

Choose a reason for hiding this comment

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

Copy link
Member Author

Choose a reason for hiding this comment

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

can be refactored but a string match should not be an issue for now


private fun addView(
view: View,
added: Boolean = true,
Expand All @@ -144,7 +147,7 @@ public class PostHogReplayIntegration(
config.dateProvider,
config.sessionReplayConfig.debouncerDelayMs,
) {
if (!isSessionReplayEnabled) {
if (!isSessionReplayEnabled || !isNativeSdk) {
return@onNextDraw
}
val timestamp = config.dateProvider.currentTimeMillis()
Expand Down Expand Up @@ -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,
Expand Down
Loading