ReviewOS

also looking at this

craft-native/craft

feat(android): setKeepAwake through the trampoline — ratchet 70 → 69

#174
Merged glennmichael123 wants to merge feat/android-keep-awake into main
7 files +140 -13
packages/zig/src/bridge_android_orientation.zig packages/zig/src/bridge_android_screen.zigrenamed+45-4
Changes to packages/zig/src/bridge_android_screen.zig
@@ -1,8 +1,8 @@
1//! `lockOrientation` and `unlockOrientation` on Android.
1//! The screen: `lockOrientation`, `unlockOrientation` and `setKeepAwake`.
22//!
3//! The first pair to go through `android_main_thread`: both do their whole job
4//! on the main looper and neither touches state the shim keeps, which is what
5//! makes them the right thing to prove the trampoline with.
3//! Everything here goes through `android_main_thread`, because everything here
4//! touches the Activity's window and the shim wraps each one in
5//! `runOnUiThread { ... }`.
66//!
77//! ## They answer by returning, not through the reply channel
88//!
@@ -41,6 +41,7 @@ const jobject = jni.jobject;
4141pub const A = struct {
4242 pub const lock_orientation = "lockOrientation";
4343 pub const unlock_orientation = "unlockOrientation";
44 pub const set_keep_awake = "setKeepAwake";
4445};
4546
4647/// Which `ActivityInfo` constant a page's string names.
@@ -85,6 +86,45 @@ pub fn apply(j: Jni, activity: jobject, mode: Mode) !void {
8586 try main_thread.post(j, activity, .{ .set_requested_orientation = constant }, 0);
8687}
8788
89// =============================================================================
90// setKeepAwake
91// =============================================================================
92//
93// ## The field it writes is read by nothing
94//
95// The shim's block ends `isKeepingAwake = enabled`, and that field is written
96// there and read nowhere else in `CraftBridge.kt`. So unlike the flashlight
97// pair — where `toggleFlashlight` reads what `setFlashlight` wrote, and Zig
98// serving one would leave the other inverting a stale value — there is no
99// state to keep in step here. Worth saying, because the two look identical
100// from the outside and only one of them is safe to take.
101
102/// `WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON`.
103///
104/// Read through JNI rather than written down. A wrong column name throws and a
105/// wrong flag does not: the window would quietly get `FLAG_DIM_BEHIND` or
106/// `FLAG_BLUR_BEHIND` instead, and the screen would keep timing out while
107/// everything reported success.
108pub fn keepScreenOnFlag(j: Jni) !i32 {
109 try j.pushLocalFrame(4);
110 defer _ = j.popLocalFrame(null);
111
112 const params_cls = try j.findClass("android/view/WindowManager$LayoutParams");
113 return j.staticIntField(
114 params_cls,
115 try j.staticFieldId(params_cls, "FLAG_KEEP_SCREEN_ON", "I"),
116 );
117}
118
119/// Queue `window.addFlags(...)` or `window.clearFlags(...)` for the main thread.
120pub fn keepAwake(j: Jni, activity: jobject, enabled: bool) !void {
121 const flag = try keepScreenOnFlag(j);
122 try main_thread.post(j, activity, .{ .set_window_flags = .{
123 .flags = flag,
124 .add = enabled,
125 } }, 0);
126}
127
88128// =============================================================================
89129// Tests
90130// =============================================================================
@@ -146,4 +186,5 @@ test "each mode names a real ActivityInfo field" {
146186test "the actions match the shim exactly" {
147187 try testing.expectEqualStrings("lockOrientation", A.lock_orientation);
148188 try testing.expectEqualStrings("unlockOrientation", A.unlock_orientation);
189 try testing.expectEqualStrings("setKeepAwake", A.set_keep_awake);
149190}