also looking at this
feat(android): setKeepAwake through the trampoline — ratchet 70 → 69
#174
7 files
+140
-13
| @@ -1,8 +1,8 @@ | ||
| 1 | //! `lockOrientation` and `unlockOrientation` on Android. | |
| 1 | //! The screen: `lockOrientation`, `unlockOrientation` and `setKeepAwake`. | |
| 2 | 2 | //! |
| 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 { ... }`. | |
| 6 | 6 | //! |
| 7 | 7 | //! ## They answer by returning, not through the reply channel |
| 8 | 8 | //! |
| @@ -41,6 +41,7 @@ const jobject = jni.jobject; | ||
| 41 | 41 | pub const A = struct { |
| 42 | 42 | pub const lock_orientation = "lockOrientation"; |
| 43 | 43 | pub const unlock_orientation = "unlockOrientation"; |
| 44 | pub const set_keep_awake = "setKeepAwake"; | |
| 44 | 45 | }; |
| 45 | 46 | |
| 46 | 47 | /// Which `ActivityInfo` constant a page's string names. |
| @@ -85,6 +86,45 @@ pub fn apply(j: Jni, activity: jobject, mode: Mode) !void { | ||
| 85 | 86 | try main_thread.post(j, activity, .{ .set_requested_orientation = constant }, 0); |
| 86 | 87 | } |
| 87 | 88 | |
| 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. | |
| 108 | pub 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. | |
| 120 | pub 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 | ||
| 88 | 128 | // ============================================================================= |
| 89 | 129 | // Tests |
| 90 | 130 | // ============================================================================= |
| @@ -146,4 +186,5 @@ test "each mode names a real ActivityInfo field" { | ||
| 146 | 186 | test "the actions match the shim exactly" { |
| 147 | 187 | try testing.expectEqualStrings("lockOrientation", A.lock_orientation); |
| 148 | 188 | try testing.expectEqualStrings("unlockOrientation", A.unlock_orientation); |
| 189 | try testing.expectEqualStrings("setKeepAwake", A.set_keep_awake); | |
| 149 | 190 | } |