Skip to content

Commit

Permalink
refactor SetOrientation (#2233)
Browse files Browse the repository at this point in the history
* inline GetEffectiveSupportedOrientations()

* remove GetEffectiveSupportedOrientations()

* move supported

* simplify supported

* split supported check

* move deviceManager

* duplicate code

* simplify deviceManager null check

* default supported

* use deviceManager.SupportedOrientations

* remove _supportedOrientations

* simplify default supported

* refactor ratio check

* refactor SetOrientation(...)

* refactor ratio check

* WindowOrientationChanged event

* subscribe to WindowOrientationChanged
  • Loading branch information
nkast authored Feb 25, 2025
1 parent e98da10 commit 55e9a90
Show file tree
Hide file tree
Showing 12 changed files with 194 additions and 85 deletions.
30 changes: 30 additions & 0 deletions Platforms/Game/.Android/AndroidConfigChangedEventArgs.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
// Copyright (C)2025 Nick Kastellanos

using System;
using Microsoft.Xna.Framework;


namespace Microsoft.Xna.Platform
{
internal class AndroidConfigChangedEventArgs : EventArgs
{
public readonly Android.Content.Res.Configuration NewConfig;

public AndroidConfigChangedEventArgs(Android.Content.Res.Configuration newConfig)
{
NewConfig = newConfig;
}
}

internal class AndroidConfigChangedOrientationEventArgs : AndroidConfigChangedEventArgs
{
public readonly Android.Content.Res.Orientation NewOrientation;

public AndroidConfigChangedOrientationEventArgs(Android.Content.Res.Configuration newConfig, Android.Content.Res.Orientation newOrientation)
: base(newConfig)
{
this.NewOrientation = newOrientation;
}
}

}
13 changes: 12 additions & 1 deletion Platforms/Game/.Android/AndroidGameActivity.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ public class AndroidGameActivity : Activity

internal event EventHandler WindowFocused;
internal event EventHandler WindowUnfocused;
internal event EventHandler<AndroidConfigChangedOrientationEventArgs> WindowOrientationChanged;

public event EventHandler Paused;
public event EventHandler Resumed;
Expand Down Expand Up @@ -49,8 +50,18 @@ protected override void OnCreate(Bundle savedInstanceState)

public override void OnConfigurationChanged(Android.Content.Res.Configuration newConfig)
{
// we need to refresh the viewport here.
base.OnConfigurationChanged(newConfig);

Android.Content.PM.ConfigChanges changes = (Android.Content.PM.ConfigChanges)newConfig.UpdateFrom(Resources.Configuration);

if ((changes & Android.Content.PM.ConfigChanges.Orientation) != 0)
{
Android.Content.Res.Orientation newOrientation = newConfig.Orientation;

var handler = WindowOrientationChanged;
if (handler != null)
handler(this, new AndroidConfigChangedOrientationEventArgs(newConfig, newOrientation));
}
}

protected override void OnPause()
Expand Down
46 changes: 13 additions & 33 deletions Platforms/Game/.Android/AndroidGameWindow.cs
Original file line number Diff line number Diff line change
Expand Up @@ -44,13 +44,12 @@ internal static AndroidGameWindow FromHandle(IntPtr windowHandle)
internal RunnableObject _runner;

internal AndroidGameActivity _activity;
private readonly Game _game;
internal readonly Game _game;
private bool _isActivated = false;
private AndroidGameWindow.AppState _appState = AndroidGameWindow.AppState.Exited;
MediaState _mediaPlayer_PrevState = MediaState.Stopped;

private Rectangle _clientBounds;
internal DisplayOrientation _supportedOrientations = DisplayOrientation.Default;
private DisplayOrientation _currentOrientation;

private OrientationListener _orientationListener;
Expand All @@ -70,6 +69,7 @@ public AndroidGameWindow(AndroidGameActivity activity, Game game)

_activity.WindowFocused += Activity_WindowFocused;
_activity.WindowUnfocused += Activity_WindowUnfocused;
_activity.WindowOrientationChanged += Activity_WindowOrientationChanged;

Point size;
// GetRealSize() was defined in JellyBeanMr1 / API 17 / Android 4.2
Expand Down Expand Up @@ -236,6 +236,12 @@ private void Activity_WindowUnfocused(object sender, EventArgs e)
}
}

private void Activity_WindowOrientationChanged(object sender, AndroidConfigChangedOrientationEventArgs e)
{
Android.Content.Res.Orientation NewOrientation = e.NewOrientation;

}

internal void ForceSetFullScreen(bool _isFullScreen)
{
if (_isFullScreen)
Expand All @@ -249,40 +255,13 @@ internal void ForceSetFullScreen(bool _isFullScreen)
}
}

/// <summary>
/// In Xna, setting SupportedOrientations = DisplayOrientation.Default (which is the default value)
/// has the effect of setting SupportedOrientations to landscape only or portrait only, based on the
/// aspect ratio of PreferredBackBufferWidth / PreferredBackBufferHeight
/// </summary>
/// <returns></returns>
internal DisplayOrientation GetEffectiveSupportedOrientations()
{
if (_supportedOrientations == DisplayOrientation.Default)
{
GraphicsDeviceManager deviceManager = (_game.Services.GetService(typeof(IGraphicsDeviceManager)) as GraphicsDeviceManager);
if (deviceManager != null)
{
if (deviceManager.PreferredBackBufferWidth > deviceManager.PreferredBackBufferHeight)
return (DisplayOrientation.LandscapeLeft | DisplayOrientation.LandscapeRight);
else
return (DisplayOrientation.Portrait | DisplayOrientation.PortraitDown);
}

return (DisplayOrientation.LandscapeLeft | DisplayOrientation.LandscapeRight);
}

return _supportedOrientations;
}

/// <summary>
/// Updates the screen orientation. Filters out requests for unsupported orientations.
/// </summary>
internal void SetOrientation(DisplayOrientation newOrientation, bool applyGraphicsChanges)
internal void SetOrientation(DisplayOrientation newOrientation, DisplayOrientation supported, bool applyGraphicsChanges)
{
DisplayOrientation supported = GetEffectiveSupportedOrientations();

// If the new orientation is not supported, force a supported orientation
if ((supported & newOrientation) == 0)
if ((newOrientation & supported) == 0)
{
if ((supported & DisplayOrientation.LandscapeLeft) != 0)
newOrientation = DisplayOrientation.LandscapeLeft;
Expand All @@ -306,7 +285,7 @@ internal void SetOrientation(DisplayOrientation newOrientation, bool applyGraphi
newOrientation = DisplayOrientation.PortraitDown;
}

if ((supported & newOrientation) != 0)
if ((newOrientation & supported) != 0)
{
DisplayOrientation oldOrientation = CurrentOrientation;
_currentOrientation = newOrientation;
Expand All @@ -316,7 +295,7 @@ internal void SetOrientation(DisplayOrientation newOrientation, bool applyGraphi

TouchPanel.DisplayOrientation = newOrientation;

if (applyGraphicsChanges && (oldOrientation != newOrientation))
if ((newOrientation != oldOrientation) && applyGraphicsChanges)
{
GraphicsDeviceManager gdm = ((IPlatformGame)_game).GetStrategy<ConcreteGame>().GraphicsDeviceManager;
if (gdm != null)
Expand Down Expand Up @@ -424,6 +403,7 @@ public void Dispose()

_activity.WindowFocused += Activity_WindowFocused;
_activity.WindowUnfocused += Activity_WindowUnfocused;
_activity.WindowOrientationChanged += Activity_WindowOrientationChanged;

_activity = null;
}
Expand Down
33 changes: 27 additions & 6 deletions Platforms/Game/.Android/ConcreteGraphicsDeviceManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -66,9 +66,6 @@ public override DisplayOrientation SupportedOrientations
set
{
base.SupportedOrientations = value;

if (base.Game.Window != null)
((AndroidGameWindow)base.Game.Window)._supportedOrientations = base.SupportedOrientations;
}
}

Expand Down Expand Up @@ -111,7 +108,15 @@ public override void CreateDevice()
// ApplyChanges
{
// Trigger a change in orientation in case the supported orientations have changed
androidGameWindow.SetOrientation(base.Game.Window.CurrentOrientation, false);
DisplayOrientation supported = this.SupportedOrientations;
if (supported == DisplayOrientation.Default)
{
if (this.PreferredBackBufferWidth <= this.PreferredBackBufferHeight)
supported = (DisplayOrientation.Portrait | DisplayOrientation.PortraitDown);
else
supported = (DisplayOrientation.LandscapeLeft | DisplayOrientation.LandscapeRight);
}
androidGameWindow.SetOrientation(base.Game.Window.CurrentOrientation, supported, false);

base.GraphicsDevice.PresentationParameters.DisplayOrientation = base.Game.Window.CurrentOrientation;

Expand All @@ -136,7 +141,15 @@ public override void CreateDevice()

Android.App.Activity activity = AndroidGameWindow.Activity;
DisplayOrientation currentOrientation = AndroidCompatibility.Current.GetAbsoluteOrientation(activity);
androidGameWindow.SetOrientation(currentOrientation, false);
DisplayOrientation supported2 = this.SupportedOrientations;
if (supported2 == DisplayOrientation.Default)
{
if (this.PreferredBackBufferWidth <= this.PreferredBackBufferHeight)
supported2 = (DisplayOrientation.Portrait | DisplayOrientation.PortraitDown);
else
supported2 = (DisplayOrientation.LandscapeLeft | DisplayOrientation.LandscapeRight);
}
androidGameWindow.SetOrientation(currentOrientation, supported2, false);

// TODO: check if the PreferredBackBufferWidth/Hight is supported and throw an error similar to fullscreen Windows Desktop.
base.GraphicsDevice.PresentationParameters.BackBufferWidth = surfaceView.Width;
Expand Down Expand Up @@ -165,7 +178,15 @@ public override void ApplyChanges()
View surfaceView = androidGameWindow.GameView;

// Trigger a change in orientation in case the supported orientations have changed
androidGameWindow.SetOrientation(base.Game.Window.CurrentOrientation, false);
DisplayOrientation supported = this.SupportedOrientations;
if (supported == DisplayOrientation.Default)
{
if (this.PreferredBackBufferWidth <= this.PreferredBackBufferHeight)
supported = (DisplayOrientation.Portrait | DisplayOrientation.PortraitDown);
else
supported = (DisplayOrientation.LandscapeLeft | DisplayOrientation.LandscapeRight);
}
androidGameWindow.SetOrientation(base.Game.Window.CurrentOrientation, supported, false);

base.GraphicsDevice.PresentationParameters.DisplayOrientation = base.Game.Window.CurrentOrientation;

Expand Down
61 changes: 56 additions & 5 deletions Platforms/Game/.Android/OrientationListener.cs
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,38 @@ public override void OnOrientationChanged(int orientation)

DisplayOrientation absOrientation = AndroidCompatibility.Current.GetAbsoluteOrientation(orientation);

if ((_gameWindow.GetEffectiveSupportedOrientations() & absOrientation) == 0
|| absOrientation == _gameWindow.CurrentOrientation
GraphicsDeviceManager deviceManager = (_gameWindow._game.Services.GetService(typeof(IGraphicsDeviceManager)) as GraphicsDeviceManager);
if (deviceManager != null)
{
DisplayOrientation supported = deviceManager.SupportedOrientations;
if (supported == DisplayOrientation.Default)
{
if (deviceManager.PreferredBackBufferWidth <= deviceManager.PreferredBackBufferHeight)
supported = (DisplayOrientation.Portrait | DisplayOrientation.PortraitDown);
else
supported = (DisplayOrientation.LandscapeLeft | DisplayOrientation.LandscapeRight);
}

if ((supported & absOrientation) == 0)
{
targetOrientation = DisplayOrientation.Unknown;
elapsed = TimeSpan.Zero;
return;
}
}
else
{
DisplayOrientation supported = (DisplayOrientation.LandscapeLeft | DisplayOrientation.LandscapeRight);

if ((supported & absOrientation) == 0)
{
targetOrientation = DisplayOrientation.Unknown;
elapsed = TimeSpan.Zero;
return;
}
}

if (absOrientation == _gameWindow.CurrentOrientation
|| absOrientation == DisplayOrientation.Unknown
)
{
Expand Down Expand Up @@ -86,9 +116,30 @@ internal void Update()
// orientation must be stable for 0.5 seconds before changing.
if (elapsed.TotalSeconds > 0.5)
{
_gameWindow.SetOrientation(targetOrientation, true);
targetOrientation = DisplayOrientation.Unknown;
elapsed = TimeSpan.Zero;
GraphicsDeviceManager deviceManager = (_gameWindow._game.Services.GetService(typeof(IGraphicsDeviceManager)) as GraphicsDeviceManager);
if (deviceManager != null)
{
DisplayOrientation supported = deviceManager.SupportedOrientations;
if (supported == DisplayOrientation.Default)
{
if (deviceManager.PreferredBackBufferWidth <= deviceManager.PreferredBackBufferHeight)
supported = (DisplayOrientation.Portrait | DisplayOrientation.PortraitDown);
else
supported = (DisplayOrientation.LandscapeLeft | DisplayOrientation.LandscapeRight);
}
_gameWindow.SetOrientation(targetOrientation, supported, true);

targetOrientation = DisplayOrientation.Unknown;
elapsed = TimeSpan.Zero;
}
else
{
DisplayOrientation supported = (DisplayOrientation.LandscapeLeft | DisplayOrientation.LandscapeRight);
_gameWindow.SetOrientation(targetOrientation, supported, true);

targetOrientation = DisplayOrientation.Unknown;
elapsed = TimeSpan.Zero;
}
}
}
}
Expand Down
13 changes: 12 additions & 1 deletion Platforms/Game/.CardboardLegacy/AndroidGameActivity.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ public class AndroidGameActivity : VRCardboard.CardboardActivity

internal event EventHandler WindowFocused;
internal event EventHandler WindowUnfocused;
internal event EventHandler<AndroidConfigChangedOrientationEventArgs> WindowOrientationChanged;

public event EventHandler Paused;
public event EventHandler Resumed;
Expand Down Expand Up @@ -57,8 +58,18 @@ protected override void OnCreate(Bundle savedInstanceState)

public override void OnConfigurationChanged(Android.Content.Res.Configuration newConfig)
{
// we need to refresh the viewport here.
base.OnConfigurationChanged(newConfig);

Android.Content.PM.ConfigChanges changes = (Android.Content.PM.ConfigChanges)newConfig.UpdateFrom(Resources.Configuration);

if ((changes & Android.Content.PM.ConfigChanges.Orientation) != 0)
{
Android.Content.Res.Orientation newOrientation = newConfig.Orientation;

var handler = WindowOrientationChanged;
if (handler != null)
handler(this, new AndroidConfigChangedOrientationEventArgs(newConfig, newOrientation));
}
}

protected override void OnPause()
Expand Down
Loading

0 comments on commit 55e9a90

Please sign in to comment.