@@ -170,6 +170,17 @@ fn acquire_android_wake_lock() {
170170static SCREEN_WAKE_LOCK : std:: sync:: Mutex < Option < jni:: objects:: GlobalRef > > =
171171 std:: sync:: Mutex :: new ( None ) ;
172172
173+ /// JNI global reference to the `PROXIMITY_SCREEN_OFF_WAKE_LOCK` held while a
174+ /// session is active over the lock screen.
175+ ///
176+ /// When this lock is held, Android's power manager monitors the proximity
177+ /// sensor and automatically turns off the screen (and disables touch input)
178+ /// when the phone is placed in a pocket or bag, preventing accidental touches.
179+ /// The screen turns back on as soon as proximity is no longer detected.
180+ #[ cfg( target_os = "android" ) ]
181+ static PROXIMITY_WAKE_LOCK : std:: sync:: Mutex < Option < jni:: objects:: GlobalRef > > =
182+ std:: sync:: Mutex :: new ( None ) ;
183+
173184/// Configure Android lock-screen behaviour based on whether a session is active.
174185///
175186/// When `active` is `true`:
@@ -279,6 +290,42 @@ pub fn set_active_session_lock_screen(active: bool) {
279290 . new_global_ref ( & wake_lock)
280291 . map_err ( |e| format ! ( "new_global_ref: {e}" ) ) ?;
281292 * guard = Some ( global) ;
293+
294+ // Acquire PROXIMITY_SCREEN_OFF_WAKE_LOCK (0x20) so that
295+ // Android automatically turns off the screen (and disables
296+ // touch input) whenever the proximity sensor fires — e.g.
297+ // when the phone is slipped into a pocket — preventing
298+ // accidental touches while the session is running.
299+ let mut prox_guard = PROXIMITY_WAKE_LOCK . lock ( ) . unwrap ( ) ;
300+ if prox_guard. is_none ( ) {
301+ // PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK = 32 (0x20)
302+ let prox_tag = env
303+ . new_string ( "logout:proximity" )
304+ . map_err ( |e| format ! ( "new_string proximity: {e}" ) ) ?;
305+ let prox_lock = env
306+ . call_method (
307+ & pm,
308+ "newWakeLock" ,
309+ "(ILjava/lang/String;)Landroid/os/PowerManager$WakeLock;" ,
310+ & [ JValue :: Int ( 0x20i32 ) , ( & prox_tag) . into ( ) ] ,
311+ )
312+ . map_err ( |e| format ! ( "newWakeLock proximity: {e}" ) ) ?
313+ . l ( )
314+ . map_err ( |e| format ! ( "ProximityWakeLock obj: {e}" ) ) ?;
315+ env. call_method (
316+ & prox_lock,
317+ "setReferenceCounted" ,
318+ "(Z)V" ,
319+ & [ JValue :: Bool ( 0u8 ) ] ,
320+ )
321+ . map_err ( |e| format ! ( "setReferenceCounted proximity: {e}" ) ) ?;
322+ env. call_method ( & prox_lock, "acquire" , "()V" , & [ ] )
323+ . map_err ( |e| format ! ( "acquire proximity: {e}" ) ) ?;
324+ let prox_global = env
325+ . new_global_ref ( & prox_lock)
326+ . map_err ( |e| format ! ( "new_global_ref proximity: {e}" ) ) ?;
327+ * prox_guard = Some ( prox_global) ;
328+ }
282329 }
283330 } else {
284331 let mut guard = SCREEN_WAKE_LOCK . lock ( ) . unwrap ( ) ;
@@ -287,6 +334,13 @@ pub fn set_active_session_lock_screen(active: bool) {
287334 let wake_lock = global. as_obj ( ) ;
288335 let _ = env. call_method ( wake_lock, "release" , "()V" , & [ ] ) ;
289336 }
337+ // Release the proximity wake lock so normal screen-off behaviour
338+ // is restored (the screen will time out as usual).
339+ let mut prox_guard = PROXIMITY_WAKE_LOCK . lock ( ) . unwrap ( ) ;
340+ if let Some ( prox_global) = prox_guard. take ( ) {
341+ let prox_lock = prox_global. as_obj ( ) ;
342+ let _ = env. call_method ( prox_lock, "release" , "()V" , & [ ] ) ;
343+ }
290344 // Restore normal lock-screen behaviour.
291345 env. call_method ( & activity, "setShowWhenLocked" , "(Z)V" , & [ JValue :: Bool ( 0u8 ) ] )
292346 . map_err ( |e| format ! ( "setShowWhenLocked(false): {e}" ) ) ?;
0 commit comments