-
Notifications
You must be signed in to change notification settings - Fork 3
feat: Initial version of double masking #327
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
Changes from 67 commits
61069a5
69799b5
81c369f
8b0c650
6dafcb3
04b4c75
55b00a7
8ddba24
008a414
4d5536b
ce45b42
50aee55
04c252e
54f08de
d6fd378
59c2f6d
3ff3e81
41e2645
ac99967
801ae96
e618524
a92e869
d86bd09
1ece408
3e570b4
aef3154
12ed36c
343690e
a4cf491
b117d79
55e29da
4c0db23
0144cef
31bb519
4daa13f
4558bbe
7cb314b
15825ce
89ba6c5
0079a42
1180d8b
04d2537
a632d0e
7584f01
483930b
3052849
50033e8
7a21080
934607b
87c3415
16a967c
278da36
fe4fa07
caac714
164dc72
8b2351a
b2b1aed
277ae2e
238b8bd
1703c99
842a899
b80c0db
4720fb0
d8574cc
71d58cf
556365a
b92e75c
45f64f9
9e45460
8a97643
a053d38
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,111 @@ | ||
| package com.launchdarkly.observability.replay.masking | ||
|
|
||
| import android.graphics.Canvas | ||
| import android.graphics.Color | ||
| import android.graphics.Paint | ||
| import android.graphics.Path | ||
| import android.graphics.Rect | ||
| import kotlin.math.abs | ||
|
|
||
| class MaskApplier { | ||
| private val beforeMaskPaint = Paint().apply { | ||
| color = Color.DKGRAY | ||
| style = Paint.Style.FILL | ||
| } | ||
abelonogov-ld marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| private val afterMaskPaint = Paint().apply { | ||
| color = Color.GRAY | ||
| style = Paint.Style.FILL | ||
| } | ||
|
|
||
| private val maskIntRect = Rect() | ||
| private val path = Path() | ||
|
|
||
| fun drawMasks(canvas: Canvas, beforeMasks: List<Mask>?, afterMasks: List<Mask>?) { | ||
| if (afterMasks == null && beforeMasks == null) return | ||
|
|
||
| beforeMasks?.forEach { mask -> | ||
| drawMask(mask, path, canvas, beforeMaskPaint) | ||
| } | ||
| afterMasks?.forEach { mask -> | ||
| drawMask(mask, path, canvas, afterMaskPaint) | ||
| } | ||
| } | ||
|
|
||
| private fun drawMask(mask: Mask, path: Path, canvas: Canvas, paint: Paint) { | ||
| var isRectangle = true | ||
| if (mask.points != null) { | ||
| val pts = mask.points | ||
| isRectangle = pts[0] == pts[6] && pts[1] == pts[3] && pts[2] == pts[4] && pts[5] == pts[7] | ||
| if (!isRectangle) { | ||
|
|
||
| path.reset() | ||
| path.moveTo(pts[0], pts[1]) | ||
| path.lineTo(pts[2], pts[3]) | ||
| path.lineTo(pts[4], pts[5]) | ||
| path.lineTo(pts[6], pts[7]) | ||
| path.close() | ||
|
|
||
| canvas.drawPath(path, paint) | ||
| } | ||
| } | ||
|
|
||
| if (isRectangle) { | ||
| maskIntRect.left = mask.rect.left.toInt() | ||
| maskIntRect.top = mask.rect.top.toInt() | ||
| maskIntRect.right = mask.rect.right.toInt() | ||
| maskIntRect.bottom = mask.rect.bottom.toInt() | ||
| canvas.drawRect(maskIntRect, paint) | ||
| } | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Bug: Axis-aligned rectangle masks may use wrong coordinatesWhen |
||
| } | ||
|
|
||
| fun filteredBeforeMasksMap( | ||
| beforeMasksMap: Map<Int, List<Mask>>, | ||
| afterMasksMap: Map<Int, List<Mask>> | ||
| ): Map<Int, List<Mask>>? { | ||
| if (afterMasksMap.count() != beforeMasksMap.count()) { | ||
| return null | ||
| } | ||
|
|
||
| if (afterMasksMap.count() == 0) { | ||
| return null | ||
| } | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Bug: Empty mask maps cause all captures to failThe Additional Locations (1) |
||
|
|
||
| val result = mutableMapOf<Int, List<Mask>>() | ||
| for ((i, before) in beforeMasksMap) { | ||
| val after = afterMasksMap[i] ?: return null | ||
| val merged = filteredBeforeMasks(before, after) ?: return null | ||
| result[i] = merged | ||
| } | ||
|
|
||
| return result | ||
| } | ||
|
|
||
| // Check if masks are stable and returns null if not | ||
| private fun filteredBeforeMasks( | ||
| beforeMasks: List<Mask>, | ||
| afterMasks: List<Mask> | ||
| ): List<Mask>? { | ||
| if (afterMasks.count() != beforeMasks.count()) { | ||
| return null | ||
| } | ||
|
|
||
| if (afterMasks.count() == 0) { | ||
| return listOf() | ||
| } | ||
|
|
||
| val stabilityTolerance = 40f | ||
| val resultMasks = mutableListOf<Mask>() | ||
| for ((before, after) in beforeMasks.zip(afterMasks)) { | ||
| if (before.viewId != after.viewId) { | ||
| return null | ||
| } | ||
| val diff = abs(after.rect.top - before.rect.top) | ||
| if (diff > stabilityTolerance) { | ||
| return null | ||
| } | ||
| resultMasks += before | ||
| } | ||
|
|
||
| return resultMasks | ||
| } | ||
| } | ||
Uh oh!
There was an error while loading. Please reload this page.