Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor SetOrientation #2233

Merged
merged 17 commits into from
Feb 25, 2025
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