| author | |
| committer | |
| log | 20174448f624d39ffedda6ad2291f07b96542644 |
| tree | 21a40c982e7614309df3c330ac47e951e43bd755 |
| parent | 4534c84f0003ef1bc0827ad8d1ab37a6ce30655f |
| signature | Signed by SSH key SHA256:52mNGHRsVFBDED9IAX5pe+LRWUefqTbxEReunq21QvU (~clover) |
On a device without Vulkan, wgpu kept one EGL surface across resizes, and the
emulator's EGL took the window's new size a resize late. A cold start that
opened with the keyboard showing drew the page into buffers of the old height,
leaving it blank above a black band until a tap; the next resize left a stray
copy of the page's title box near the bottom. A resize under GL now makes a
new surface, as GLSurfaceView does, and the Android check fails when the
reopened page leaves the screen black.
- The page draws on Android 8 as soon as it opens, without a tap.
Fixes #153
Assisted-by: claude-opus-5.52 files changed, 29 insertions(+), 3 deletions(-)
apps/android/check.py+11-1| ... | ... | @@ -6,12 +6,14 @@ the caller starts and stops: |
| 6 | 6 | |
| 7 | 7 | It types a token into the page, waits until the section reports it saved, force-stops the app, |
| 8 | 8 | turns the network off, starts it again and screenshots the page, then reads the section file |
| 9 | back with onestore's inspect example and looks for the token in it. | |
| 9 | back with onestore's inspect example and looks for the token in it. The page must have drawn | |
| 10 | where the keyboard was, which GL on Android 8 once left black. | |
| 10 | 11 | """ |
| 11 | 12 | import argparse |
| 12 | 13 | import json |
| 13 | 14 | from pathlib import Path |
| 14 | 15 | import secrets |
| 16 | import struct | |
| 15 | 17 | import subprocess |
| 16 | 18 | import time |
| 17 | 19 | |
| ... | ... | @@ -70,6 +72,11 @@ def main(): |
| 70 | 72 | adb('shell', 'cmd', 'connectivity', 'airplane-mode', 'enable') |
| 71 | 73 | launch() |
| 72 | 74 | (output / 'reopened.png').write_bytes(adb('exec-out', 'screencap', '-p', binary=True)) |
| 75 | # A raw capture: width and height, then RGBA rows after a header whose size varies by release. | |
| 76 | screen = adb('exec-out', 'screencap', binary=True) | |
| 77 | columns, rows = struct.unpack_from('<2I', screen) | |
| 78 | pixel = len(screen) - columns * rows * 4 + (rows * 3 // 4 * columns + columns // 2) * 4 | |
| 79 | drawn = any(screen[pixel:pixel + 3]) | |
| 73 | 80 | section = output / 'section.one' |
| 74 | 81 | section.write_bytes(adb('exec-out', 'run-as', PACKAGE, 'cat', SECTION, binary=True)) |
| 75 | 82 | (output / 'logcat.txt').write_text(adb('logcat', '-d')) |
| ... | ... | @@ -84,11 +91,14 @@ def main(): |
| 84 | 91 | 'intact': inspected.endswith(' 0 checksum mismatches'), |
| 85 | 92 | # Text is stored as UTF-16, or as single bytes where it fits them. |
| 86 | 93 | 'tokenInSection': token.encode('utf-16-le') in data or token.encode() in data, |
| 94 | 'drawn': drawn, | |
| 87 | 95 | } |
| 88 | 96 | (output / 'result.json').write_text(json.dumps(result, indent=2) + '\n') |
| 89 | 97 | print(json.dumps(result, indent=2)) |
| 90 | 98 | if not (result['intact'] and result['tokenInSection']): |
| 91 | 99 | raise SystemExit('The edit did not survive') |
| 100 | if not drawn: | |
| 101 | raise SystemExit('The reopened page left the screen black') | |
| 92 | 102 | |
| 93 | 103 | |
| 94 | 104 | if __name__ == '__main__': |
crates/mobile/src/lib.rs+18-2| ... | ... | @@ -1167,8 +1167,8 @@ pub unsafe extern "C" fn sb_view_free(view: *mut View) { |
| 1167 | 1167 | |
| 1168 | 1168 | #[unsafe(no_mangle)] |
| 1169 | 1169 | pub extern "C" fn sb_view_resize(view: &mut View, width: f32, height: f32, scale: f32) { |
| 1170 | let gpu = gpu(); | |
| 1171 | let Some(gpu) = gpu.as_ref() else { return }; | |
| 1170 | let guard = gpu(); | |
| 1171 | let Some(gpu) = guard.as_ref() else { return }; | |
| 1172 | 1172 | let Some(pixels) = report(view_pixels( |
| 1173 | 1173 | [width, height], |
| 1174 | 1174 | scale, |
| ... | ... | @@ -1182,6 +1182,22 @@ pub extern "C" fn sb_view_resize(view: &mut View, width: f32, height: f32, scale |
| 1182 | 1182 | let _ = report(canvas.page.scale_factor_changed(scale)); |
| 1183 | 1183 | } |
| 1184 | 1184 | let _ = report(canvas.page.resized(pixels)); |
| 1185 | #[cfg(target_os = "android")] | |
| 1186 | if gpu.adapter.get_info().backend == wgpu::Backend::Gl | |
| 1187 | && let Some(Presentation { | |
| 1188 | surface, | |
| 1189 | _window: window, | |
| 1190 | .. | |
| 1191 | }) = view.presentation.take() | |
| 1192 | { | |
| 1193 | // The emulator's EGL takes a window's new size late, so GL makes a new surface, as | |
| 1194 | // GLSurfaceView does. | |
| 1195 | drop(surface); | |
| 1196 | drop(guard); | |
| 1197 | // SAFETY: `window` holds a reference until the new presentation has acquired its own. | |
| 1198 | view.presentation = report(unsafe { Presentation::new(window.0.as_ptr(), pixels) }); | |
| 1199 | return; | |
| 1200 | } | |
| 1185 | 1201 | if let Some(presentation) = &mut view.presentation { |
| 1186 | 1202 | presentation.config.width = pixels[0]; |
| 1187 | 1203 | presentation.config.height = pixels[1]; |