@@ -88,6 +88,14 @@ public partial class OsuGameAndroid : OsuGame
8888 private object ? activeMixersList ;
8989
9090 private object ? nativeBridges ;
91+
92+ /// <summary>
93+ /// Last value passed to <see cref="OsuGameActivity.RequestedOrientation"/> by
94+ /// <see cref="updateOrientation"/>. Cached locally so we can short-circuit
95+ /// redundant updates without round-tripping through the activity getter, which
96+ /// itself performs a binder IPC on modern Android.
97+ /// </summary>
98+ private global ::Android . Content . PM . ScreenOrientation ? lastRequestedOrientation ;
9199 private int currentRefreshRate ;
92100
93101 public OsuGameAndroid ( OsuGameActivity activity )
@@ -753,24 +761,44 @@ private void updateOrientation()
753761
754762 var orientation = MobileUtils . GetOrientation ( this , currentScreen , gameActivity . IsTablet ) ;
755763
764+ global ::Android . Content . PM . ScreenOrientation desired ;
765+
766+ switch ( orientation )
767+ {
768+ case MobileUtils . Orientation . Locked :
769+ desired = global ::Android . Content . PM . ScreenOrientation . Locked ;
770+ break ;
771+
772+ case MobileUtils . Orientation . Portrait :
773+ desired = global ::Android . Content . PM . ScreenOrientation . Portrait ;
774+ break ;
775+
776+ case MobileUtils . Orientation . Default :
777+ desired = gameActivity . DefaultOrientation ;
778+ break ;
779+
780+ default :
781+ return ;
782+ }
783+
784+ // Short-circuit when no change is required. We track the last requested orientation
785+ // locally because Activity.getRequestedOrientation() itself performs a binder IPC
786+ // on modern Android, and the whole point of this guard is to avoid binder traffic.
787+ // ScreenChanged fires on every screen push/pop and the resolved orientation rarely
788+ // differs between adjacent screens, so without this guard we flood the UI looper
789+ // with redundant Activity.setRequestedOrientation transactions, which under
790+ // system_server CPU pressure can wedge input dispatch and trigger an ANR
791+ // ("Input dispatching timed out ... Waited 10000ms for MotionEvent").
792+ if ( lastRequestedOrientation == desired )
793+ return ;
794+
795+ lastRequestedOrientation = desired ;
796+
756797 gameActivity . RunOnUiThread ( ( ) =>
757798 {
758799 try
759800 {
760- switch ( orientation )
761- {
762- case MobileUtils . Orientation . Locked :
763- gameActivity . RequestedOrientation = global ::Android . Content . PM . ScreenOrientation . Locked ;
764- break ;
765-
766- case MobileUtils . Orientation . Portrait :
767- gameActivity . RequestedOrientation = global ::Android . Content . PM . ScreenOrientation . Portrait ;
768- break ;
769-
770- case MobileUtils . Orientation . Default :
771- gameActivity . RequestedOrientation = gameActivity . DefaultOrientation ;
772- break ;
773- }
801+ gameActivity . RequestedOrientation = desired ;
774802 }
775803 catch ( Exception e )
776804 {
0 commit comments