diff --git a/samples/CommunityToolkit.Maui.Sample/Pages/Views/MediaElement/MediaElementPage.xaml b/samples/CommunityToolkit.Maui.Sample/Pages/Views/MediaElement/MediaElementPage.xaml index f017af2ed..984f94c6f 100644 --- a/samples/CommunityToolkit.Maui.Sample/Pages/Views/MediaElement/MediaElementPage.xaml +++ b/samples/CommunityToolkit.Maui.Sample/Pages/Views/MediaElement/MediaElementPage.xaml @@ -30,6 +30,7 @@ + + + + + + + + + + diff --git a/src/CommunityToolkit.Maui.MediaElement/AppBuilderExtensions.shared.cs b/src/CommunityToolkit.Maui.MediaElement/AppBuilderExtensions.shared.cs index 3f7eb8863..e3d70f8d3 100644 --- a/src/CommunityToolkit.Maui.MediaElement/AppBuilderExtensions.shared.cs +++ b/src/CommunityToolkit.Maui.MediaElement/AppBuilderExtensions.shared.cs @@ -25,7 +25,7 @@ public static MauiAppBuilder UseMauiCommunityToolkitMediaElement(this MauiAppBui { // Update the default MediaElementOptions for MediaElement if Action is not null options?.Invoke(new MediaElementOptions(builder)); - + // Perform Handler configuration builder.ConfigureMauiHandlers(h => { diff --git a/src/CommunityToolkit.Maui.MediaElement/Handlers/MediaElementHandler.android.cs b/src/CommunityToolkit.Maui.MediaElement/Handlers/MediaElementHandler.android.cs index bd1e00e6e..9a1ed2e36 100644 --- a/src/CommunityToolkit.Maui.MediaElement/Handlers/MediaElementHandler.android.cs +++ b/src/CommunityToolkit.Maui.MediaElement/Handlers/MediaElementHandler.android.cs @@ -24,7 +24,7 @@ protected override MauiMediaElement CreatePlatformView() VirtualView, Dispatcher.GetForCurrentThread() ?? throw new InvalidOperationException($"{nameof(IDispatcher)} cannot be null")); - var (_, playerView) = MediaManager.CreatePlatformView(VirtualView.AndroidViewType); + var (_, playerView) = MediaManager.CreatePlatformView(VirtualView.AndroidViewType, VirtualView.IsAndroidForegroundServiceEnabled); return new(Context, playerView); } diff --git a/src/CommunityToolkit.Maui.MediaElement/MediaElement.shared.cs b/src/CommunityToolkit.Maui.MediaElement/MediaElement.shared.cs index 6d663135f..a95109cfc 100644 --- a/src/CommunityToolkit.Maui.MediaElement/MediaElement.shared.cs +++ b/src/CommunityToolkit.Maui.MediaElement/MediaElement.shared.cs @@ -225,6 +225,11 @@ internal event EventHandler StopRequested /// public AndroidViewType AndroidViewType { get; init; } = MediaElementOptions.DefaultAndroidViewType; + /// + /// Gets or sets whether the Android Foreground Service is enabled. + /// + public bool IsAndroidForegroundServiceEnabled { get; init; } = MediaElementOptions.IsAndroidForegroundServiceEnabled; + /// /// Gets or sets whether the media should start playing as soon as it's loaded. /// Default is . This is a bindable property. diff --git a/src/CommunityToolkit.Maui.MediaElement/MediaElementOptions.shared.cs b/src/CommunityToolkit.Maui.MediaElement/MediaElementOptions.shared.cs index 35c839d2a..ec2c724f9 100644 --- a/src/CommunityToolkit.Maui.MediaElement/MediaElementOptions.shared.cs +++ b/src/CommunityToolkit.Maui.MediaElement/MediaElementOptions.shared.cs @@ -17,8 +17,19 @@ internal MediaElementOptions(in MauiAppBuilder builder) : this() /// internal static AndroidViewType DefaultAndroidViewType { get; private set; } = AndroidViewType.SurfaceView; + /// + /// Set Android Foreground Service for MediaElement on construction + /// + internal static bool IsAndroidForegroundServiceEnabled { get; private set; } = true; + /// /// Set Android View type for MediaElement as SurfaceView or TextureView on construction /// public void SetDefaultAndroidViewType(AndroidViewType androidViewType) => DefaultAndroidViewType = androidViewType; + + /// + /// Set Android Foreground Service for MediaElement on construction + /// + /// + public void SetDefaultAndroidForegroundService(bool androidForegroundServiceEnabled) => IsAndroidForegroundServiceEnabled = androidForegroundServiceEnabled; } \ No newline at end of file diff --git a/src/CommunityToolkit.Maui.MediaElement/Views/MauiMediaElement.android.cs b/src/CommunityToolkit.Maui.MediaElement/Views/MauiMediaElement.android.cs index 05aafd5d0..50c06b756 100644 --- a/src/CommunityToolkit.Maui.MediaElement/Views/MauiMediaElement.android.cs +++ b/src/CommunityToolkit.Maui.MediaElement/Views/MauiMediaElement.android.cs @@ -8,11 +8,6 @@ using AndroidX.Media3.UI; using CommunityToolkit.Maui.Views; -[assembly: UsesPermission(Android.Manifest.Permission.ForegroundServiceMediaPlayback)] -[assembly: UsesPermission(Android.Manifest.Permission.ForegroundService)] -[assembly: UsesPermission(Android.Manifest.Permission.MediaContentControl)] -[assembly: UsesPermission(Android.Manifest.Permission.PostNotifications)] - namespace CommunityToolkit.Maui.Core.Views; /// diff --git a/src/CommunityToolkit.Maui.MediaElement/Views/MediaManager.android.cs b/src/CommunityToolkit.Maui.MediaElement/Views/MediaManager.android.cs index 180f82610..91f066232 100644 --- a/src/CommunityToolkit.Maui.MediaElement/Views/MediaManager.android.cs +++ b/src/CommunityToolkit.Maui.MediaElement/Views/MediaManager.android.cs @@ -20,6 +20,7 @@ namespace CommunityToolkit.Maui.Core.Views; public partial class MediaManager : Java.Lang.Object, IPlayerListener { + bool androidForegroundServiceEnabled; const int bufferState = 2; const int readyState = 3; const int endedState = 4; @@ -129,11 +130,11 @@ or PlaybackState.StateSkippingToQueueItem /// The platform native counterpart of . /// Thrown when is or when the platform view could not be created. [MemberNotNull(nameof(Player), nameof(PlayerView), nameof(session))] - public (PlatformMediaElement platformView, PlayerView PlayerView) CreatePlatformView(AndroidViewType androidViewType) + public (PlatformMediaElement platformView, PlayerView PlayerView) CreatePlatformView(AndroidViewType androidViewType, bool androidForegroundServiceEnabled) { Player = new ExoPlayerBuilder(MauiContext.Context).Build() ?? throw new InvalidOperationException("Player cannot be null"); Player.AddListener(this); - + this.androidForegroundServiceEnabled = androidForegroundServiceEnabled; if (androidViewType is AndroidViewType.SurfaceView) { PlayerView = new PlayerView(MauiContext.Context) @@ -352,7 +353,7 @@ protected virtual async partial ValueTask PlatformUpdateSource() return; } - if (connection is null) + if (connection is null && androidForegroundServiceEnabled) { StartService(); } diff --git a/src/CommunityToolkit.Maui.UnitTests/Extensions/AppBuilderExtensionsTests.cs b/src/CommunityToolkit.Maui.UnitTests/Extensions/AppBuilderExtensionsTests.cs index 5f25d2497..dc308f284 100644 --- a/src/CommunityToolkit.Maui.UnitTests/Extensions/AppBuilderExtensionsTests.cs +++ b/src/CommunityToolkit.Maui.UnitTests/Extensions/AppBuilderExtensionsTests.cs @@ -139,5 +139,24 @@ public void UseMauiCommunityToolkitMediaElement_ShouldSetDefaultAndroidViewType( MediaElementOptions.DefaultAndroidViewType.Should().Be(AndroidViewType.TextureView); } + + [Fact] + public void UseMauiCommunityToolkitMediaElement_ShouldSetAndroidServiceByDefault() + { + var builder = MauiApp.CreateBuilder(); + builder.UseMauiCommunityToolkitMediaElement(); + MediaElementOptions.IsAndroidForegroundServiceEnabled.Should().Be(true); + } + + [Fact] + public void UseMauiCommunityToolkitMediaElement_ServiceCanBeDisabled() + { + var builder = MauiApp.CreateBuilder(); + builder.UseMauiCommunityToolkitMediaElement(static options => + { + options.SetDefaultAndroidForegroundService(false); + }); + MediaElementOptions.IsAndroidForegroundServiceEnabled.Should().Be(false); + } } #pragma warning restore CA1416 \ No newline at end of file