osu-framework icon indicating copy to clipboard operation
osu-framework copied to clipboard

The `Game.Window.Resizable` setter on Android causes unexpected screen rotation

Open Frederisk opened this issue 7 months ago • 1 comments

Through this issue, we already know that when SDL3Window initializes, it reads the SDL_HINT_ORIENTATIONS instead of RequestedOrientation, which can cause problems.

So, a possible solution is to use SDL.SDL3.SDL_SetHint to pre-assign the orientation we need.

However, this still doesn't avoid another problem: besides during initialization, the Window.Resizable property will call this setOrientationBis method again when its value changes. And I think users might not expect this. For example:

  • A user might initially, similar to osu!, not assign a hint and use RequestedOrientation to set the screen orientation to a specific value. Then, some method (perhaps a cross-platform settings option) tries to change the value of Resizable: Window.Resizable = !Window.Resizable. Then, RequestedOrientation will suddenly be changed to FullUser. And what's stranger is that executing Window.Resizable = !Window.Resizable again will not restore the screen orientation, but will fix the screen to landscape or portrait.
    class MyGame : Game {
      [Reslove]
      AndroidGameActivity activity;
      [BackgroundDependencyLoader]
      load() => this.activity.RequestedOrientation = ScreenOrientation.Landscape;
    
      // By this action, RequestedOrientation may become `FullUser`, or `SensorLandscape`, or `SensorLandscape`
      override OnClick() => Window.Resizable = !Window.Resizable;
    }
    
  • Alternatively, a user might use a hint to make the screen display in landscape for things like loading screens. Then, there's an in-game setting to force the program into portrait mode. At this point, RequestedOrientation must be used, as SDL_HINT_ORIENTATIONS does not notify Android that its status has changed. Then, if an attempt is made to change the Resizable value while in portrait mode, the SDL_HINT_ORIENTATIONS takes effect again, forcing the screen back to landscape. And changing Resizable back to its original value has no effect. I believe users who haven't seen any comments about this would be very confused.
    class AndroidGameActivity {
      override OnCreate() => SDL.SDL3.SDL_SetHint(SDL.SDL3.SDL_HINT_ORIENTATIONS, "LandscapeRight"u8);
    }
    class MyGame : Game {
      [Reslove]
      AndroidGameActivity activity;
      [BackgroundDependencyLoader]
      load() => this.activity.RequestedOrientation = ScreenOrientation.Landscape;
    
      // By this action, RequestedOrientation will become `ReverseLandscape`
      override OnClick() => Window.Resizable = !Window.Resizable;
    }
    

Here's a sample program. Just install the compiled SampleGame.Android project on your device. You can try clicking some buttons and observe how the screen orientation changes.

So, do we also need additional wiki documentation or comments for Resizable to inform users about this unusual issue? For example, mentioning that changing Resizable in Android can cause unexpected orientation changes, or reminding users to record the value of RequestedOrientation before modifying Resizable in Android and restore it after the call is complete.

By the way, I have a potentially viable solution for the three related issues, which is to override the SetOrientationBis method in AndroidGameActivity. I have already checked the complete call chain. But after asking for others' opinions on Discord, I received the reply, "If it works, then don't touch it." So, whether to solve these problems, or to consider them not to be problems, is entirely up to you guys. I have no other ideas.😕

Frederisk avatar May 19 '25 14:05 Frederisk

I have a potentially viable solution for the three related issues, which is to override the SetOrientationBis method in AndroidGameActivity. I have already checked the complete call chain.

flowchart TD
 subgraph s1["SDL.android-project"]
        n1["SDLActivity.setOrientationBis"]
        n2["SDLActivity.setOrientation"]
  end
 subgraph s2["SDL"]
        n4["Android_JNI_SetOrientation"]
        n5["Android_CreateWindow"]
        n7["SDL_CreateWindowWithProperties"]
        n8["SDL_CreateWindow"]
        n9["Android_SetWindowResizable"]
        n10["SDL_SetWindowResizable"]
  end
 subgraph s3["osu.Framework"]
        n17["AndroidGameActivity.SetOrientationBis"]
        n15["SDL3Window.Create"]
        n13["SDL3Window.Resizable"]
        n14["SDL3Window.UpdateWindowStateAndSize"]
  end
 subgraph s4["SDL3-CS"]
        n16["SDLActivity.SetOrientationBis"]
  end
    n1 --> n2
    n1 -.-> n16
    n4 --> n5 & n9
    n5 --> n7
    n7 --> n8
    n9 --> n10
    n10 --> n13 & n14
    n8 --> n15
    n2 --> n4
    n16 -.-> n17
    n17 o--o n18["Maybe override it here?"]
    n1@{ shape: rect}
    n18@{ shape: braces}
    style n17 stroke-dasharray: 2
    click n1 "https://github.com/libsdl-org/SDL/blob/d16371b923fed57e5df676a84435baf1d1061a6a/android-project/app/src/main/java/org/libsdl/app/SDLActivity.java#L1125"
    click n2 "https://github.com/libsdl-org/SDL/blob/d16371b923fed57e5df676a84435baf1d1061a6a/android-project/app/src/main/java/org/libsdl/app/SDLActivity.java#L1115"
    click n4 "https://github.com/libsdl-org/SDL/blob/514d96de07c3b1b8603ee4701229bb055a1dd2e3/src/core/android/SDL_android.c#L1625"
    click n5 "https://github.com/libsdl-org/SDL/blob/514d96de07c3b1b8603ee4701229bb055a1dd2e3/src/video/android/SDL_androidwindow.c#L39"
    click n7 "https://github.com/libsdl-org/SDL/blob/514d96de07c3b1b8603ee4701229bb055a1dd2e3/src/video/SDL_video.c#L2335"
    click n8 "http://github.com/libsdl-org/SDL/blob/514d96de07c3b1b8603ee4701229bb055a1dd2e3/src/video/SDL_video.c#L2554"
    click n9 "https://github.com/libsdl-org/SDL/blob/514d96de07c3b1b8603ee4701229bb055a1dd2e3/src/video/android/SDL_androidwindow.c#L171"
    click n10 "https://github.com/libsdl-org/SDL/blob/514d96de07c3b1b8603ee4701229bb055a1dd2e3/src/video/SDL_video.c#L2978"
    click n17 "https://github.com/ppy/osu-framework/blob/a7815796130dbf24194d76437599464999976f02/osu.Framework.Android/AndroidGameActivity.cs?plain=1#L17C1-L17C60"
    click n15 "https://github.com/ppy/osu-framework/blob/a7815796130dbf24194d76437599464999976f02/osu.Framework/Platform/SDL3/SDL3Window.cs?plain=1#L201"
    click n13 "https://github.com/ppy/osu-framework/blob/a7815796130dbf24194d76437599464999976f02/osu.Framework/Platform/SDL3/SDL3Window_Windowing.cs?plain=1#L176"
    click n14 "https://github.com/ppy/osu-framework/blob/a7815796130dbf24194d76437599464999976f02/osu.Framework/Platform/SDL3/SDL3Window_Windowing.cs?plain=1#L636"

Frederisk avatar May 20 '25 14:05 Frederisk