EXP-068 — Generic View inheritance + Floating Next button
Problem:
EXP-067's renderer used class-name pattern matching to identify View types (TextView, EditText, etc.). This is fragile — anonymous subclasses like LoginActivity$PhoneView$1 were recognized by a hardcoded LoginActivity$PhoneView$ prefix check, not by semantic superclass resolution. Additionally, the FragmentFloatingButton (Telegram's Next button) existed in the heap but was excluded from rendering because it's a sibling of PhoneView, not a child.
Evidence:
| Metric |
EXP-067 |
EXP-068 |
| View type detection |
class-name patterns |
semantic superclass chain |
| Class→superclass map |
not built |
41,099 entries (41,078 APK + 21 framework) |
| EditText detected |
14 (pattern) |
14 (semantic — same count, but now correct) |
| ViewGroup detected |
1 (pattern) |
112 (semantic — was vastly under-counted) |
| Floating Next button |
missing |
visible at bottom-right |
| login_ui.png SHA256 |
17d1d406... |
39ca3cd7... |
| OCR match_rate |
1.0 |
1.0 |
| 3-run reproducibility |
identical |
identical |
| Generic regression |
PASS |
PASS |
Root cause:
- View inheritance: The DEX
class_defs only contain classes DEFINED in the APK. Framework classes (LinearLayout, EditText, etc.) are referenced via type_idx but their class_defs are not in the APK. So the superclass chain lookup failed for framework classes.
- Floating button exclusion: The renderer's
select_visible_slide() picks PhoneView as the slide root and only renders its subtree. FragmentFloatingButton is a child of LoginActivity$2 (the ViewPager), not PhoneView — so it was excluded.
Fix:
Phase 1 — Generic View inheritance model
- Added
class_to_superclass_ map to DalvikExecutionEngine.
- Pre-populated with 21 Android framework View hierarchy entries (from AOSP source):
View → Object, ViewGroup → View, LinearLayout → ViewGroup, FrameLayout → ViewGroup
TextView → View, EditText → TextView, Button → TextView, ImageView → View
CheckBox → Button, RadioButton → Button, etc.
- AppCompat variants (AndroidX)
- Added APK-defined classes from
dex_report_->classes (41,078 classes with superclass_name).
- Implemented
is_subclass_of(class, ancestor) — walks the superclass chain with cycle protection (max depth 50).
- Added
is_view_class, is_text_view_class, is_edit_text_class, is_image_view_class, is_button_class, is_view_group_class queries.
dump_view_tree() now exports a semantic view_type field: EditText / TextView / ImageView / Button / ViewGroup / View.
- Renderer updated to use
view_type field (falls back to class-name patterns for older view trees).
Result: LoginActivity$PhoneView$1 and $3 are now correctly classified as EditText via the superclass chain: PhoneView$1 → AnimatedPhoneNumberEditText → HintEditText → EditTextBoldCursor → EditText → TextView → View.
Phase 8 — Floating Next button
- Discovered
FragmentFloatingButton (id=3869, parent=LoginActivity$2, VISIBLE) in the heap.
- Its children:
RLottieImageView (id=3872, VISIBLE), RadialProgressView (id=3873, GONE), TransformableLoginButtonView (id=3911, GONE).
- The button was excluded because it's a SIBLING of PhoneView, not a child.
- Updated the renderer to also include
FragmentFloatingButton as a floating overlay:
- Positioned at bottom-right (84px FAB size, 48px margins).
- Only visible children are included (GONE/INVISIBLE excluded).
- Rendered on top of the slide content.
Generic impact:
- The View inheritance model is GENERIC — works for any Android APK. The framework hierarchy is hardcoded (21 classes from AOSP), but APK classes are loaded from DEX metadata. The
is_subclass_of query is a generic superclass chain walk.
- The
view_type field in view_tree.json is a generic classification — any renderer can use it without knowing Telegram-specific class names.
- The FragmentFloatingButton overlay is a generic pattern — any floating action button (FAB) that's a sibling of the slide root will be included.
Tests:
- 3-run reproducibility: identical SHA256 (
39ca3cd7c2d03582384202feb87d8f091a6e2c7d6958d1b0cfb11ce3d44c0169)
- Generic regression (synthetic Acme app): PASS — match_rate=1.0
- OCR: all 3 expected strings detected (Please confirm..., Phone number, Country)
- View type distribution: 112 ViewGroup, 103 TextView, 29 ImageView, 27 View, 14 EditText (vs. 1 ViewGroup before — was vastly under-counted)
Before/after:
|
Before (EXP-067) |
After (EXP-068) |
| View type detection |
class-name patterns |
semantic superclass chain |
| ViewGroup detected |
1 |
112 |
| Floating Next button |
missing |
visible at bottom-right |
| login_ui.png SHA256 |
17d1d406... |
39ca3cd7... |
Memory:
Runtime RSS ~519 MB (unchanged). The class_to_superclass_ map adds ~41K entries (~4MB). Renderer RSS < 100 MB.
Image result:
The image now shows:
- Header text ("Please confirm your country code...")
- Country input field (with "Country" label)
- Phone input field (with "Phone number" label and "+" prefix)
- Circular Next button at bottom-right (NEW — the FragmentFloatingButton with RLottieImageView icon)
Checkpoint:
CHECKPOINT_L_LOGIN_UI = PROVEN (maintained, with semantic View inheritance + floating button)
Remaining blockers:
- Real measure/layout engine (Phase 2) — current layout uses heuristics
- Generic LayoutInflater wired to setContentView (Phase 4)
- EditText text state management (Phase 6) — setText/getText on custom subclasses
- Hint propagation for OBJECT_REF args (Phase 7)
- Input dispatch system (Phase 9/10)
- Click dispatch system (Phase 11)
- Controlled mock network backend (Phase 13)
- SMS View transition (Phase 15/16)
- Exception engine, reflection, SQLite, JNI, networking
Final commit: d055dc6 — EXP-068 Phase 1+8: Generic View inheritance + Floating Next button
The image is the gate. The pixels contain the correct text + the floating Next button. ✅
EXP-068 — Generic View inheritance + Floating Next button
Problem:
EXP-067's renderer used class-name pattern matching to identify View types (TextView, EditText, etc.). This is fragile — anonymous subclasses like
LoginActivity$PhoneView$1were recognized by a hardcodedLoginActivity$PhoneView$prefix check, not by semantic superclass resolution. Additionally, the FragmentFloatingButton (Telegram's Next button) existed in the heap but was excluded from rendering because it's a sibling of PhoneView, not a child.Evidence:
Root cause:
class_defsonly contain classes DEFINED in the APK. Framework classes (LinearLayout, EditText, etc.) are referenced viatype_idxbut theirclass_defsare not in the APK. So the superclass chain lookup failed for framework classes.select_visible_slide()picks PhoneView as the slide root and only renders its subtree. FragmentFloatingButton is a child ofLoginActivity$2(the ViewPager), not PhoneView — so it was excluded.Fix:
Phase 1 — Generic View inheritance model
class_to_superclass_map toDalvikExecutionEngine.View → Object,ViewGroup → View,LinearLayout → ViewGroup,FrameLayout → ViewGroupTextView → View,EditText → TextView,Button → TextView,ImageView → ViewCheckBox → Button,RadioButton → Button, etc.dex_report_->classes(41,078 classes withsuperclass_name).is_subclass_of(class, ancestor)— walks the superclass chain with cycle protection (max depth 50).is_view_class,is_text_view_class,is_edit_text_class,is_image_view_class,is_button_class,is_view_group_classqueries.dump_view_tree()now exports a semanticview_typefield:EditText/TextView/ImageView/Button/ViewGroup/View.view_typefield (falls back to class-name patterns for older view trees).Result:
LoginActivity$PhoneView$1and$3are now correctly classified asEditTextvia the superclass chain:PhoneView$1 → AnimatedPhoneNumberEditText → HintEditText → EditTextBoldCursor → EditText → TextView → View.Phase 8 — Floating Next button
FragmentFloatingButton(id=3869, parent=LoginActivity$2, VISIBLE) in the heap.RLottieImageView(id=3872, VISIBLE),RadialProgressView(id=3873, GONE),TransformableLoginButtonView(id=3911, GONE).FragmentFloatingButtonas a floating overlay:Generic impact:
is_subclass_ofquery is a generic superclass chain walk.view_typefield inview_tree.jsonis a generic classification — any renderer can use it without knowing Telegram-specific class names.Tests:
39ca3cd7c2d03582384202feb87d8f091a6e2c7d6958d1b0cfb11ce3d44c0169)Before/after:
Memory:
Runtime RSS ~519 MB (unchanged). The
class_to_superclass_map adds ~41K entries (~4MB). Renderer RSS < 100 MB.Image result:
The image now shows:
Checkpoint:
CHECKPOINT_L_LOGIN_UI = PROVEN(maintained, with semantic View inheritance + floating button)Remaining blockers:
Final commit:
d055dc6—EXP-068 Phase 1+8: Generic View inheritance + Floating Next buttonThe image is the gate. The pixels contain the correct text + the floating Next button. ✅