Commit ecef37b
Feat/floating forms (#441)
* Implement WindowManager approach for floating forms (POC)
Add FloatingFormWindow class that uses WindowManager.addView() with
TYPE_APPLICATION_PANEL to display floating forms as window overlays,
allowing the host Activity to remain fully interactive (including
keyboard input).
Key changes:
- FormLayout data classes for layout configuration (position, dimensions, margins)
- FloatingFormWindow for WindowManager-based presentation
- KlaviyoPresentationManager now routes to Activity or WindowManager based on layout
- WebViewClient.getWebView() for accessing the WebView instance
- Bump formWillAppear handshake version to 2 for layout support
- Hardcoded TEST_LAYOUT in KlaviyoNativeBridge for testing (BOTTOM_RIGHT, 300x200dp)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* fix: Correct bugs found in code review of floating forms POC
- Restore activity.startActivity() in presentActivity() to avoid
AndroidRuntimeException when starting from application context
- Move all view manipulation into runOnUiThread in FloatingFormWindow.show()
to prevent crashes from off-UI-thread view access
- Call detachWebView() in floating window dismiss path for consistency
- Restore webView.visibility = VISIBLE before adding to FloatingFormWindow
- Remove unnecessary cast in dismiss(), fix inline android.view.ViewGroup FQN
- Eliminate !! operator, use takeUnless pattern for floatingLayout capture
- Add TODO comments for orientation change handling, debug background,
deprecated API, and unused updateLayout scaffolding
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* refactor: Simplify FloatingFormWindow.dismiss() by removing redundant child removal
Since detachWebView() is called before window.dismiss() in the manager,
explicitly removing the child WebView before windowManager.removeView()
is redundant and fragile (relies on getChildAt(0) index assumption).
Removing the extra step simplifies the code.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: Downgrade error log to warning, add TODOs for BugBot feedback
- Change ERROR→WARNING for null WebView guard in presentFloatingWindow()
since this is a state check, not an exception (aligns with AGENTS.md
logging guidelines: ERROR requires an exception)
- Add TODO documenting that presentationState should ideally transition
to Presented inside the runOnUiThread callback (POC shortcut noted)
- Add TODO to hostActivity explaining it's scaffolding for future
orientation change recovery and dynamic layout updates
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: Address PR feedback — replace suspicious test ID, add zoom TODO
- Replace test form ID '64CjgW' with 'aPiKeY' to avoid resembling
a real key
- Add TODO for testing toPixels with system-wide zoom/scaling settings
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* refactor: Rename Margins to Offsets across floating forms POC
Aligns naming with the bridge contract where these are SDK-applied
offsets of the form content, not CSS-style margins.
Renamed: Margins → Offsets, margins → offsets in FormLayout,
FloatingFormWindow, KlaviyoNativeBridge, and all tests.
JSON key also updated from "margins" to "offsets".
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* MAGE-328 (#427)
* MAGE-328: cleanup PoC
* support rotation with floating form open
* resolve WindowLeaked error
* backgrounding and margins
* keyboard with bottom form
* handle keyboard behavior
* pr-loop: 1
* pr-loop: 2
* address memory leak concerns
* add test coverage for floating forms
* bugbot fixes
* bugbot
* bugbot
* correct bottom offset direction
* address PR feedback
* fix bugbot
* bugbot
* MAGE-323: safe zone handling (#432)
* MAGE-323: safe zone handling
* offset should be user + safezone
* horizantal safe zones
* fix: address review feedback and fix CI
* refactor: observe keyboard via probe view to avoid clobbering host app callbacks (#438)
Previously, FloatingFormWindow set WindowInsetsAnimationCallback directly on
the host activity's root view, silently replacing any callback the host app
had registered there. The fallback OnApplyWindowInsetsListener had the same
clobbering problem.
Replace with a two-layer approach that doesn't touch the host app's view
hierarchy:
1. Inject a zero-size probe View as a direct child of the host DecorView and
attach WindowInsetsAnimationCallback there. Since DISPATCH_MODE_STOP on a
sibling only blocks recursion into that sibling's subtree (not other
children of the same parent), our probe view receives animation callbacks
independently. Uses DISPATCH_MODE_CONTINUE_ON_SUBTREE to signal no intent
to interfere with dispatch.
2. Fall back to ViewTreeObserver.OnGlobalLayoutListener on the DecorView.
This is fully additive (add vs set), unaffected by DISPATCH_MODE_STOP, and
handles pre-API 30 devices where the compat animation shim may not reach a
non-root child. When an ancestor blocks the animation callback, the form
snaps to its shifted position rather than tracking the keyboard slide
frame-by-frame. The isAnimatingKeyboard flag prevents both paths from
applying a shift simultaneously.
Co-authored-by: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
* resolve bugbot
* resolve bugbot again
* resolve bugbot 3
* resolve bugbot 4
* resolve bugbot 5
* resolve bugbot 6
* resolve bugbot 7
* resolve bugbot 8
* resolve bugbot 9
---------
Co-authored-by: Evan C Masseau <5167687+evan-masseau@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Evan Masseau <evan.masseau@klaviyo.com>
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Co-authored-by: Evan C Masseau <5167687+evan-masseau@users.noreply.github.com>1 parent 6924768 commit ecef37b
15 files changed
Lines changed: 1868 additions & 56 deletions
File tree
- sdk/forms/src
- main/java/com/klaviyo/forms
- bridge
- presentation
- webview
- test/java/com/klaviyo/forms
- bridge
- presentation
Lines changed: 175 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
| 103 | + | |
| 104 | + | |
| 105 | + | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
| 111 | + | |
| 112 | + | |
| 113 | + | |
| 114 | + | |
| 115 | + | |
| 116 | + | |
| 117 | + | |
| 118 | + | |
| 119 | + | |
| 120 | + | |
| 121 | + | |
| 122 | + | |
| 123 | + | |
| 124 | + | |
| 125 | + | |
| 126 | + | |
| 127 | + | |
| 128 | + | |
| 129 | + | |
| 130 | + | |
| 131 | + | |
| 132 | + | |
| 133 | + | |
| 134 | + | |
| 135 | + | |
| 136 | + | |
| 137 | + | |
| 138 | + | |
| 139 | + | |
| 140 | + | |
| 141 | + | |
| 142 | + | |
| 143 | + | |
| 144 | + | |
| 145 | + | |
| 146 | + | |
| 147 | + | |
| 148 | + | |
| 149 | + | |
| 150 | + | |
| 151 | + | |
| 152 | + | |
| 153 | + | |
| 154 | + | |
| 155 | + | |
| 156 | + | |
| 157 | + | |
| 158 | + | |
| 159 | + | |
| 160 | + | |
| 161 | + | |
| 162 | + | |
| 163 | + | |
| 164 | + | |
| 165 | + | |
| 166 | + | |
| 167 | + | |
| 168 | + | |
| 169 | + | |
| 170 | + | |
| 171 | + | |
| 172 | + | |
| 173 | + | |
| 174 | + | |
| 175 | + | |
Lines changed: 1 addition & 1 deletion
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
95 | 95 | | |
96 | 96 | | |
97 | 97 | | |
98 | | - | |
| 98 | + | |
99 | 99 | | |
100 | 100 | | |
101 | 101 | | |
| |||
Lines changed: 6 additions & 3 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
29 | 29 | | |
30 | 30 | | |
31 | 31 | | |
| 32 | + | |
32 | 33 | | |
33 | 34 | | |
34 | 35 | | |
35 | | - | |
| 36 | + | |
| 37 | + | |
36 | 38 | | |
37 | 39 | | |
38 | 40 | | |
| |||
104 | 106 | | |
105 | 107 | | |
106 | 108 | | |
107 | | - | |
| 109 | + | |
108 | 110 | | |
109 | 111 | | |
110 | 112 | | |
| |||
130 | 132 | | |
131 | 133 | | |
132 | 134 | | |
133 | | - | |
| 135 | + | |
| 136 | + | |
134 | 137 | | |
135 | 138 | | |
136 | 139 | | |
| |||
0 commit comments