-keep public class com.amplitude.android.sessionreplay.** { *; }
-keep public class com.amplitude.android.sessionreplay.internal.** { *; }
-keep class kotlin.Metadata

-keepclassmembers,allowobfuscation class * {
    @com.google.gson.annotations.SerializedName <fields>;
}

-keep class androidx.compose.ui.platform.AndroidComposeView { *; }
-keep class androidx.compose.ui.platform.ComposeView { *; }
-keep class androidx.compose.ui.graphics.Canvas { *; }
-keep class androidx.core.graphics.Insets { *; }
-keep class androidx.compose.ui.node.LayoutNode { *; }
-keep class androidx.compose.ui.node.NodeChain { *; }
-keep class androidx.compose.ui.node.BackwardsCompatNode { *; }
-keep class androidx.compose.ui.node.DelegatingNode { *; }

# Keep fields accessed via reflection: child, kindSet
-keep class androidx.compose.ui.Modifier$Node { *; }

# Keep LogcatLogger implementation for session replay
-keep class com.amplitude.android.sessionreplay.LogcatLogger { *; }
-keep class com.amplitude.android.sessionreplay.LogcatLogger$Companion { *; }

# Keep CoreTextFieldSemanticsModifier and its imeOptions property
-keep class androidx.compose.foundation.text.input.internal.CoreTextFieldSemanticsModifier {
    androidx.compose.ui.text.input.ImeOptions imeOptions;
}

# Keep the ImeOptions class that imeOptions references
-keep class androidx.compose.ui.text.input.ImeOptions { *; }

# Keep Owner class, used by AndroidComposeViewUtils
-keep class androidx.compose.ui.node.Owner { *; }

-keep class dev.chrisbanes.haze.HazeEffectNode
-keep class dev.chrisbanes.haze.HazeSourceNode

# Keep EmbeddedEvent class and its no-argument constructor
-keep class com.amplitude.android.sessionreplay.internal.embedded.EmbeddedEvent { *; }

# Keep EmbeddedView classes for better error messages
# Keep only the EmbeddedView communication callback function
-keepclassmembers class com.amplitude.android.sessionreplay.internal.embedded.EmbeddedViewData {
    # Callback method referenced via ::handleEmbeddedViewEvent in setMessageCallback
    public void handleEmbeddedViewEvent(java.lang.String);
}

# ============================================================
# Amplitude Session Replay — Compose bytecode-instrumentation keep rules
# Origin: 2026-05-13 `apkanalyzer dex packages` of a real R8-minified release
# build showed every SR-injected method on the (then-instrumented)
# `androidx.compose.ui.graphics.layer.GraphicsLayerV23` was being DCE'd
# (R8 full mode + no consumer-side use-site at compile time). The rules
# below were added to keep them. After the 2026-05-15 public-class pivot
# (see docs/proposals/plugin-architecture-decision.md) the instrumentation
# target moved from impl-layer V23/V29 to the public `GraphicsLayer` class;
# the keep rules cover the new and old instrumented packages (the impl
# classes still live under `androidx.compose.ui.graphics.layer.**` and are
# matched by the wildcard rule).
# ============================================================

# 1) Dispatch functions on the SR side. The bytecode-instrumentation plugin
#    INVOKESTATIC's these from inside the rewritten Compose classes — R8 can't
#    see that call edge because it happens at a transform that runs *before*
#    R8, so without an explicit keep rule R8 considers them unreachable and
#    removes them. Failure mode: NoClassDefFoundError / AbstractMethodError at
#    runtime when the rewritten Compose class calls a missing dispatcher.
#
#    The dispatch functions are `@JvmSynthetic internal fun` top-level Kotlin
#    declarations — Kotlin lowers them to static methods on a synthetic
#    `*Kt` class. With `android.enableR8.fullMode=true` (workspace default),
#    matching by member-pattern alone allows R8 to keep the members but
#    horizontal-class-merge the holder class away, leaving the bytecode
#    `INVOKESTATIC *HooksKt.sessionReplayDispatch*` dangling. The
#    `-keep class ... { *; }` form keeps both the class symbol and members.
#
#    One rule per hook Kt class. Add a new line here when wiring a new
#    dispatcher class on the SR side.
-keep class com.amplitude.android.sessionreplay.compose.instrumentation.GraphicsLayerRecordHooksKt { *; }
-keep class com.amplitude.android.sessionreplay.compose.instrumentation.CoordinatorDrawHooksKt { *; }
-keep class com.amplitude.android.sessionreplay.compose.instrumentation.OwnedLayerDrawHooksKt { *; }
-keep class com.amplitude.android.sessionreplay.compose.instrumentation.AndroidInteropViewDrawHooksKt { *; }
-keep class com.amplitude.android.sessionreplay.compose.instrumentation.RippleHostViewDrawHooksKt { *; }

# 2) The SPI accessor interfaces. After instrumentation the rewritten Compose
#    classes implement these, but R8's reachability view still pre-transform
#    shows no use-site (the interfaces' only declared callers are the
#    dispatchers above, which themselves needed a keep rule). Without these
#    the rewritten classes lose their `implements` clauses and casts in the
#    SR dispatchers fail ClassCastException at runtime.
#
#    One rule per accessor interface. Add a new line here when defining a
#    new SPI accessor.
-keep interface com.amplitude.android.sessionreplay.compose.instrumentation.SessionReplayGraphicsLayerAccessor { *; }
-keep interface com.amplitude.android.sessionreplay.compose.instrumentation.SessionReplayContentTypeAccessor { *; }
-keep interface com.amplitude.android.sessionreplay.compose.instrumentation.SessionReplayNodeAccessor { *; }
-keep interface com.amplitude.android.sessionreplay.compose.instrumentation.SessionReplayCoordinatorAccessor { *; }
-keep interface com.amplitude.android.sessionreplay.compose.instrumentation.SessionReplayOwnedLayerAccessor { *; }
-keep interface com.amplitude.android.sessionreplay.compose.instrumentation.SessionReplayAndroidComposeViewAccessor { *; }
-keep interface com.amplitude.android.sessionreplay.compose.instrumentation.SessionReplayRippleHostViewDrawAccessor { *; }

# 3) The injected accessor / bridge / *Original methods on rewritten classes.
#    The dispatcher functions read them by name at runtime (e.g. the dispatch
#    body calls `layer.sessionReplayRecordOriginal(...)` to invoke the renamed
#    Compose method); R8 sees no consumer-side compile-time reference because
#    the rewrite happens in a transform R8 doesn't trace.
#
#    With `android.enableR8.fullMode=true` (the workspace default), the
#    `-keepclassmembers class * implements <SR-interface>` form is not enough —
#    R8 full mode treats it conservatively and only retains members that the
#    interface itself declares as reachable. Since SR's consumer-side use-sites
#    sit inside the dispatcher Kt classes (which were themselves kept by §1
#    above) the consumer→accessor edge IS visible, yet R8 still strips the
#    implementing class's `sessionReplay*` methods. The workaround is the
#    explicit "name-pattern-keep-everywhere" rules below.
#
#    Rules are narrowly scoped to each instrumented Compose class so the
#    SR-internal name pattern can't accidentally retain unrelated members.
#    Add a new rule when adding a new spec target to
#    `ComposeAbiSpec.TARGETS` in the plugin.
#
#    **Three patterns per block** because the SR accessor surface mixes
#    Kotlin `fun` (lowered to method names starting with `sessionReplay`)
#    and Kotlin `val` / `var` properties (lowered to JVM getter / setter
#    method names starting with `getSessionReplay` / `setSessionReplay`).
#    ProGuard glob matching is case-sensitive — `sessionReplay*` alone
#    misses `getSessionReplayOwnedLayer` (the lone `val` property on
#    `SessionReplayCoordinatorAccessor` today). Covering all three Kotlin
#    lowering forms here means future property additions on any SPI
#    accessor don't need a corresponding ProGuard rule update.
-keepclassmembers class androidx.compose.ui.graphics.layer.** {
    *** sessionReplay*(...);
    *** getSessionReplay*(...);
    *** setSessionReplay*(...);
}
-keepclassmembers class androidx.compose.ui.node.LayoutNode {
    *** sessionReplay*(...);
    *** getSessionReplay*(...);
    *** setSessionReplay*(...);
}
-keepclassmembers class androidx.compose.ui.node.NodeCoordinator {
    *** sessionReplay*(...);
    *** getSessionReplay*(...);
    *** setSessionReplay*(...);
}
-keepclassmembers class androidx.compose.ui.platform.AndroidComposeView {
    *** sessionReplay*(...);
    *** getSessionReplay*(...);
    *** setSessionReplay*(...);
}
-keepclassmembers class androidx.compose.ui.platform.GraphicsLayerOwnerLayer {
    *** sessionReplay*(...);
    *** getSessionReplay*(...);
    *** setSessionReplay*(...);
}
-keepclassmembers class androidx.compose.material.ripple.RippleHostView {
    *** sessionReplay*(...);
    *** getSessionReplay*(...);
    *** setSessionReplay*(...);
}
-keepclassmembers class androidx.compose.ui.autofill.AndroidContentType {
    *** sessionReplay*(...);
    *** getSessionReplay*(...);
    *** setSessionReplay*(...);
}

# Suppress warning for Java 9+ string concatenation optimization class
-dontwarn java.lang.invoke.StringConcatFactory

# Keep Flutter classes for session replay Flutter integration
-keep class io.flutter.embedding.android.FlutterImageView { *; }
-keep class io.flutter.embedding.android.FlutterSurfaceView { *; }
-keep class io.flutter.embedding.android.FlutterTextureView { *; }
-keep class io.flutter.embedding.android.FlutterView { *; }
-keep class io.flutter.embedding.engine.FlutterEngine { *; }
-keep class io.flutter.embedding.engine.dart.DartExecutor { *; }
-keep class io.flutter.plugin.common.BinaryMessenger { *; }
-keep class io.flutter.plugin.common.BinaryMessenger$BinaryMessageHandler { *; }

-dontwarn io.flutter.embedding.android.FlutterImageView
-dontwarn io.flutter.embedding.android.FlutterSurfaceView
-dontwarn io.flutter.embedding.android.FlutterTextureView
-dontwarn io.flutter.embedding.android.FlutterView
-dontwarn io.flutter.embedding.engine.FlutterEngine
-dontwarn io.flutter.embedding.engine.dart.DartExecutor
-dontwarn io.flutter.plugin.common.BinaryMessenger$BinaryMessageHandler
-dontwarn io.flutter.plugin.common.BinaryMessenger$BinaryReply
-dontwarn io.flutter.plugin.common.BinaryMessenger
