Skip to content

feat: Android Incremental Image Diff compression#390

Merged
abelonogov-ld merged 24 commits intomainfrom
andrey/tile-compression
Feb 27, 2026
Merged

feat: Android Incremental Image Diff compression#390
abelonogov-ld merged 24 commits intomainfrom
andrey/tile-compression

Conversation

@abelonogov-ld
Copy link
Copy Markdown
Contributor

@abelonogov-ld abelonogov-ld commented Feb 24, 2026

Summary

Incremental Image Diff compression, layers = 15, backtracking = true


Note

Medium Risk
Touches the core session replay capture/export pipeline (frame encoding, diffing, and rrweb event generation), so regressions could break replay rendering or increase memory/CPU usage. No auth or sensitive data handling logic is introduced beyond existing screenshot capture/masking.

Overview
Implements incremental image diff compression for Android session replay by switching capture output from a single full-screen base64 image to an ExportFrame model that can add/remove tiled image layers, with configurable ReplayOptions.compression (default OverlayTiles(layers=15, backtracking=true)).

Refactors capture into ImageCaptureService (raw bitmap capture + masking) plus ExportDiffManager/TileDiffManager (tile signatures, diff rectangle cropping, keyframe layering, and optional backtracking rollbacks), and updates instrumentation/exporter flow to use CaptureManager and the new frame format.

Replaces the previous string-templated rrweb canvas events with RRWebEventGenerator, generating DOM mutation adds/removes of positioned img nodes (and related rrweb type enums), and updates exporter logic/tests to decide full vs incremental snapshots based on session/dimension changes and canvas buffer limits.

Written by Cursor Bugbot for commit 91087e4. This will update automatically on new commits. Configure here.

Updated the class name from SessionReplayEventGenerator to RRWebEventGenerator for improved clarity and consistency. Adjusted the instantiation in SessionReplayExporter accordingly.
Updated the RRWebEventGenerator to improve the generation of incremental events. Introduced new constants for DOM elements and refined the state management for image nodes. The event generation now utilizes a more structured approach for adding and removing nodes, enhancing clarity and maintainability.
Modified the RRWebEventGenerator to use a constant for the image MIME type, ensuring consistency in data URL generation for incremental events. This change enhances maintainability and clarity in the codebase.
…natureManager

Updated the observability module to replace instances of CaptureEvent with the new ExportFrame class, enhancing the structure of exported frames. Introduced TileSignatureManager for improved tile-based signature computation. Adjusted related tests and export logic to accommodate these changes, ensuring consistency across the codebase.
Added CaptureManager class to facilitate capturing frames from the lowest visible window. This implementation includes functionality for emitting captured frames as ExportFrame objects, integrating session management, and applying masks for privacy. The new class enhances the observability module by providing a structured approach to frame capture, with future optimizations planned for capture quality and memory management.
Modified ExportDiffManager to accept ImageCaptureService.RawFrame instead of the previously defined RawFrame data class. This change streamlines the frame capture process and enhances integration with the ImageCaptureService, improving overall code clarity and maintainability. Additionally, removed the RawFrame data class from ExportDiffManager to reduce redundancy.
…ions

Modified the TileSignatureManager to accept separate width and height parameters for tile size during signature computation. This change enhances flexibility in tile processing and improves the accuracy of tile-based signatures. Additionally, updated the ExportDiffManager to utilize the new signature computation method, ensuring consistency across the observability module.
…roved state management

Updated the SessionReplayExporter to include a condition for forcing full captures based on canvas size and keyframe status. Refined the RRWebEventGenerator to manage node IDs and image handling more effectively, including the introduction of a new tile-based signature system. Adjusted the ExportFrame structure to utilize IntSize for original dimensions, enhancing clarity and consistency across the observability module.
…hashing and signature computation

Modified the TileSignature data class to include separate hashLo and hashHi values, enhancing the hashing mechanism. Updated the TileSignatureManager to support multiple compute methods with preferred tile dimensions and added convenience overloads for square tiles. Adjusted internal hashing logic to reduce collision probability and improved test cases to reflect changes in tile signature handling.
@abelonogov-ld abelonogov-ld requested a review from a team as a code owner February 24, 2026 04:28
Copy link
Copy Markdown

@cursor cursor Bot left a comment

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 2 potential issues.

(cherry picked from commit 49e4fb9)
@abelonogov-ld abelonogov-ld changed the title WIP Tile compression WIP feat: Android Tile compression Feb 24, 2026
* main:
  chore: release main (#396)
  fix: Android span e2e tests (#397)
  fix: improve network response capture (#379)
  feat: initial upload of mobile-dotnet (#393)
  chore: release main (#394)
  fix: Fix event sorting in session replay export (#392)
  fix: Touch move event buffering using wrong clock and mismatched constants (#391)
* main:
  chore: release main (#400)
  fix: correct react native session replay build step (#399)
@abelonogov-ld abelonogov-ld changed the title WIP feat: Android Tile compression feat: Android Tile compression Feb 27, 2026
@abelonogov-ld abelonogov-ld changed the title feat: Android Tile compression feat: Android Incremental Image Diff compression Feb 27, 2026
@abelonogov-ld abelonogov-ld enabled auto-merge (squash) February 27, 2026 23:04
## Summary

Fixes and removes ignore on span e2e tests. Flag Eval on the launch was
intervening with tests

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Low Risk**
> Low risk: changes are limited to the Android E2E test harness and test
annotations, with no impact on production SDK logic beyond skipping a
test-only span trigger during tests.
> 
> **Overview**
> Fixes flaky Android span E2E tests by preventing `BaseApplication`
from running `flagEvaluation()` during test runs (gated on `testUrl ==
null`), avoiding extra spans that interfered with assertions.
> 
> Re-enables previously ignored span-related E2E coverage by removing
`@Ignore` from several trace/export and sampling tests in
`DisablingConfigOptionsE2ETest` and `SamplingE2ETest`.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
618e2b1. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
…ervability-sdk into andrey/tile-compression

* 'andrey/tile-compression' of github.com:launchdarkly/observability-sdk:
  chore: add CLAUDE.md (#398)
@abelonogov-ld abelonogov-ld enabled auto-merge (squash) February 27, 2026 23:07
@abelonogov-ld abelonogov-ld merged commit 5ff93f6 into main Feb 27, 2026
24 checks passed
@abelonogov-ld abelonogov-ld deleted the andrey/tile-compression branch February 27, 2026 23:24
abelonogov-ld added a commit that referenced this pull request Feb 27, 2026
* main:
  feat: Android Incremental Image Diff compression (#390)
abelonogov-ld added a commit that referenced this pull request Feb 28, 2026
* main:
  feat: Optional Jet Compose (#402)
  feat: Android Incremental Image Diff compression (#390)
  chore: add CLAUDE.md (#398)
  chore: release main (#400)
  fix: correct react native session replay build step (#399)
  chore: release main (#396)
  fix: Android span e2e tests (#397)
  fix: improve network response capture (#379)

# Conflicts:
#	sdk/@launchdarkly/mobile-dotnet/.vscode/tasks.json
abelonogov-ld pushed a commit that referenced this pull request Feb 28, 2026
🤖 I have created a release *beep* *boop*
---


<details><summary>launchdarkly-observability-android: 0.27.0</summary>

##
[0.27.0](launchdarkly-observability-android-0.26.1...launchdarkly-observability-android-0.27.0)
(2026-02-28)


### Features

* Android Incremental Image Diff compression
([#390](#390))
([5ff93f6](5ff93f6))
* Optional Jet Compose
([#402](#402))
([8f3a671](8f3a671))
</details>

---
This PR was generated with [Release
Please](https://github.com/googleapis/release-please). See
[documentation](https://github.com/googleapis/release-please#release-please).

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> <sup>[Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) is
generating a summary for commit
bd91847. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants