Skip to content

Add support to make AndroidForegroundService optional to MediaElement #2658

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

Draft
wants to merge 10 commits into
base: main
Choose a base branch
from

Conversation

ne0rrmatrix
Copy link
Contributor

@ne0rrmatrix ne0rrmatrix commented May 7, 2025

  • Feature/Proposal

Description of Change

Updated MediaElement to include AndroidForegroundServiceEnabled property for better control over media playback on Android. Adjusted related methods and classes to handle this new property, ensuring the foreground service is utilized appropriately during media playback. Removed unnecessary properties and streamlined the popup media element configuration.

Linked Issues

PR Checklist

  • Has a linked Issue, and the Issue has been approved(bug) or Championed (feature/proposal)
  • Has tests (if omitted, state reason in description)
  • Has samples (if omitted, state reason in description)
  • Rebased on top of main at time of PR
  • Changes adhere to coding standard
  • Documentation created or updated: https://github.com/MicrosoftDocs/CommunityToolkit/pulls

Additional information

This PR is for the community to see how making android service optional could be implemented.

MediaElement.shared.cs

/// <summary>
/// Read the MediaElementOptions set in on construction, cannot be changed after construction
/// </summary>
public AndroidViewType AndroidViewType { get; init; } = MediaElementOptions.DefaultAndroidViewType;

MediaElementOptions

/// <summary>
/// Set Android Foreground Service for MediaElement on construction
/// </summary>
internal static bool AndroidForeServiceEnabled { get; private set; } = true;

/// <summary>
/// Set Android Foreground Service for MediaElement on construction
/// </summary>
/// <param name="androidForegroundServiceEnabled"></param>
public void SetDefaultAndroidForegroundService(bool androidForegroundServiceEnabled) => AndroidForeServiceEnabled = androidForegroundServiceEnabled;

Updated MediaElement to include AndroidForegroundServiceEnabled property for better control over media playback on Android. Adjusted related methods and classes to handle this new property, ensuring the foreground service is utilized appropriately during media playback. Removed unnecessary properties and streamlined the popup media element configuration.
@ne0rrmatrix ne0rrmatrix added do not merge Do not merge this PR 📽️ MediaElement Issue/PR that has to do with MediaElement labels May 7, 2025
Copy link
Contributor

@bijington bijington left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the general approach looks good. I am surprised it takes such little code change.

I think we should add an Is prefix to the property to follow typical Boolean naming conventions (e.g. IsAndroidForegroundServiceEnabled)

I understand that you wanted to have Android as the initial prefix here. Why did we do this for the AndroidViewType property in stead of making it a property that only exists for Android? Was it to simplify the code that needs to be written?

Renamed `AndroidForegroundServiceEnabled` to `IsAndroidForegroundServiceEnabled` across multiple files, including XAML, C#, and shared code. Updated the default value for the foreground service option to true in `MediaElementOptions`. Added unit tests to verify the default behavior and the ability to disable the foreground service setting. These changes improve clarity and maintainability by standardizing the naming convention.
@ne0rrmatrix
Copy link
Contributor Author

ne0rrmatrix commented May 7, 2025

I understand that you wanted to have Android as the initial prefix here. Why did we do this for the AndroidViewType property in stead of making it a property that only exists for Android? Was it to simplify the code that needs to be written?

I honestly have no idea how or when we came up with that. I am simply using the same convention used in texture view as it is has already been established and keeping it the same made sense to me.

edit: I think it was so that we can use it in xaml.

@mrucker
Copy link

mrucker commented May 7, 2025

Do these code changes also remove the foreground service permission from the Android manifest file? That is the real problem, because that is what Google checks when you submit to the app store.

@Elinares-82
Copy link

Hi all, we just got rejected out app since the MediaElement control added this permission. We only use this control to display a video in the Splash screen. When can we get this new CommunityToolkit nuget version? In the meantime, we will appeal the rejection, however, this is just to see if they understand the situation. I would appreciate it if we could move a little faster. Thanks

@mrucker
Copy link

mrucker commented May 7, 2025

@Elinares-82 there's an easy work around for this in the meantime. You just need to remove like 3 lines of code from the MAUI project, build it, and then include the package you just built in your app instead of the Nuget package. It took me like an hour to get a version in my app without the foreground permission requirement.

@Elinares-82
Copy link

Elinares-82 commented May 7, 2025

@Elinares-82 there's an easy work around for this in the meantime. You just need to remove like 3 lines of code from the MAUI project, build it, and then include the package you just built in your app instead of the Nuget package. It took me like an hour to get a version in my app without the foreground permission requirement.

Thanks!, I will give it a try.

@bijington
Copy link
Contributor

Hi all, we just got rejected out app since the MediaElement control added this permission. We only use this control to display a video in the Splash screen. When can we get this new CommunityToolkit nuget version? In the meantime, we will appeal the rejection, however, this is just to see if they understand the situation. I would appreciate it if we could move a little faster. Thanks

I think a PR opened within a few hours is moving pretty quickly. If you would like things to move more quickly please free to get involved and help out

@Elinares-82
Copy link

Hi all, we just got rejected out app since the MediaElement control added this permission. We only use this control to display a video in the Splash screen. When can we get this new CommunityToolkit nuget version? In the meantime, we will appeal the rejection, however, this is just to see if they understand the situation. I would appreciate it if we could move a little faster. Thanks

I think a PR opened within a few hours is moving pretty quickly. If you would like things to move more quickly please free to get involved and help out

Sure, give me the permissions and I click on Approve button. The Play Store is rejecting our apps since you decided to add permissions by default, why? Let the developers add or not the permissions.

Copy link
Member

@pictos pictos left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see that you added the property inside the MediaElement, how is the behavior if I have two media elements in different pages, one setting foreground to true and other to false, what will be the behavior? I didn't see code to tear down the ForegroundService if it changes to false in fly.

But I think it should only be something that you set on AppBuilder and only once

@Elinares-82
Copy link

That I could see is prevent to start the service here
image
I'm taking the @ne0rrmatrix branch a create an assembly in the meantime, since we need our app get approved ASAP.

@ne0rrmatrix
Copy link
Contributor Author

I see that you added the property inside the MediaElement, how is the behavior if I have two media elements in different pages, one setting foreground to true and other to false, what will be the behavior? I didn't see code to tear down the ForegroundService if it changes to false in fly.

But I think it should only be something that you set on AppBuilder and only once

The behavior if one media element is using the service and the other is not is that one will have access to the service and the other will not. This PR was meant to allow input and let ppl see how it could be done. It is marked as draft and I explicitly created it so I could gather feedback and make changes. I was hoping for this exact sort of input.

Do we want to have it as init only and apply to any media elements that launch? Or do we want to allow each media element the option at runtime to decide?

If one media element is already using the service and the second one is not using it it will not tear down the service. I do not believe that is possible without tearing down the media element using the service. The service is tightly integrated with media session and is as close to default implementation as I could create based on platform limitations. The only thing I could do to make it more like the google example is to move the Exoplayer Builder into the service itself. That was the original goal but do to various factors in the original media2 to media3 PR it never happened.

I would prefer to keep this as simple as possible for maintainability while allowing developers the choice to do what they want. My goal here is to add the option to opt out of the service at runtime. Do you want it set in builder only? Or does anyone have any better suggestions? I am not looking at adding anything complex or doing something new. I simply want to add developer choice.

Anyone who has an opinion please speak up. I still think of this as being in design phase. This PR was purely to allow ppl to see the idea I had for design.

@Elinares-82
Copy link

Do we want to have it as init only and apply to any media elements that launch? Or do we want to allow each media element the option at runtime to decide?

What if we can have both?, We can have an initial flag to disable it for all the media elements, and force with the new IsAndroidForegroundServiceEnabled to start individually? I do not know if this make sense.

I the other hand, I know that each team have processes, I don't like to sound rude at all. I'd just like to know when this version might be coming out.

Thanks,

@mrucker
Copy link

mrucker commented May 7, 2025

I was reading back through old discussions because I've been confused. I think there are two different issues being discussed. I'm going to call them issue 1 and issue 2 here.

Issue 1 -- MediaElement should only turn on a foreground service if it is requested
Issue 2 -- MediaElement should only add foreground permissions to the Android Manifest if requested

I think this PR will likely fix what I call issue 1, but it won't fix what I call issue 2.

@ne0rrmatrix Is this PR intended to fix both issue 1 and 2? Or are you only trying to fix issue 1?

@Elinares-82 I think you have an issue 2 problem (which is what I had when I joined these threads several months ago). Unless ne0rrmatrix says otherwise, I don't think this PR is going to fix your issue.

@ne0rrmatrix
Copy link
Contributor Author

@mrucker ty for the clarification. I will update the PR to address both issues. I appreciate all the help and input.

@mrucker
Copy link

mrucker commented May 7, 2025

(Also, I seem to be the one to blame for the confusion. Looking back through the discussion history, I hijacked discussion #2225, which was initially about issue 1, and started talking about issue 2 because I didn't understand the difference at the time. Sorry everyone.)

@Elinares-82
Copy link

Elinares-82 commented May 7, 2025

MediaElementOptions

You are totally right; I think this will not fix my issue. Google rejected our app since in the Manifest are several permissions like FOREGROUND_SERVICE_MEDIA_PLAYBACK and FOREGROUND_SERVICE, but we just display a promo video in the splash screen. We are stuck at this point. The only way that I can see is use an old version or use an alternative like Blazor component.

@ne0rrmatrix
Copy link
Contributor Author

Updating the service to address both issues will require the developer to add permissions manually to manifest and will only allow the service to run if permissions and foreground service are turned on. My questions is how do we want to deal with that. The reason we set the permissions ourselves was to fix the issue with constant bug reports where the solution was to simply add the service and intent filter to the manifest.

@mrucker
Copy link

mrucker commented May 7, 2025

Updating the service to address both issues will require the developer to add permissions manually to manifest and will only allow the service to run if permissions and foreground service are turned on. My questions is how do we want to deal with that. The reason we set the permissions ourselves was to fix the issue with constant bug reports where the solution was to simply add the service and intent filter to the manifest.

Yes... That's kind of the problem we never solved in an old discussion about it... Which is why I've never offered my own PR... There didn't seem to be a great solution.

@Elinares-82
Copy link

Updating the service to address both issues will require the developer to add permissions manually to manifest and will only allow the service to run if permissions and foreground service are turned on. My questions is how do we want to deal with that. The reason we set the permissions ourselves was to fix the issue with constant bug reports where the solution was to simply add the service and intent filter to the manifest.

I think, if this is documented all of us have to read and follow the guidance. For me is normal to add the permissions that the controls need. But, is there a possibility to disabled to add the permissions to the Manifest if the new Flag is turn it on? In a complex scenario use a project property to disable this in the source generator (I'm assuming that these permissions are being added using a source generator)

@mrucker
Copy link

mrucker commented May 7, 2025

@Elinares-82

You are totally right; I think this will not fix my issue. Google rejected our app since in the Manifest are several permissions like FOREGROUND_SERVICE_MEDIA_PLAYBACK and FOREGROUND_SERVICE, but we just display a promo video in the splash screen. We are stuck at this point. The only way that I can see is use an old version or use an alternative like Blazor component.

It is easy to remove the permission requirements if you are able to build the MediaElement yourself and create your own Nuget Package. It's not ideal, but if you're really up against a wall it will allow you to release your app. I'd send you my team's custom Nuget package we've been using to remove this permission, but handing out code to strangers on the internet doesn't seem like a best practice 😄.

@pictos
Copy link
Member

pictos commented May 7, 2025

MediaElementOptions

You are totally right; I think this will not fix my issue. Google rejected our app since in the Manifest are several permissions like FOREGROUND_SERVICE_MEDIA_PLAYBACK and FOREGROUND_SERVICE, but we just display a promo video in the splash screen. We are stuck at this point. The only way that I can see is use an old version or use an alternative like Blazor component.

@Elinares-82 there are tools that you allow you to edit the manifest on android app, so when you build your project and it generates the apk or aab you can unzip it, remove the permissions that you don't want and zip it again to ship into stores. I already did that for many apps that I worked and never had issues with that, and since are tools for it, I would say, isn't something unusual

@Elinares-82
Copy link

@Elinares-82

You are totally right; I think this will not fix my issue. Google rejected our app since in the Manifest are several permissions like FOREGROUND_SERVICE_MEDIA_PLAYBACK and FOREGROUND_SERVICE, but we just display a promo video in the splash screen. We are stuck at this point. The only way that I can see is use an old version or use an alternative like Blazor component.

It is easy to remove the permission requirements if you are able to build the MediaElement yourself and create your own Nuget Package. It's not ideal, but if you're really up against it will allow you to release your app. I'd send you my team's custom Nuget package we've been using to remove this permission, but handing out code to strangers on the internet doesn't seem like a best practice 😄.

I think these are the lines that I have to comment out. I'm trying to use the generated "custom" DLL but I'm getting several compiler errors so I will try the @pictos suggestion.

image

Thanks to all for your help and recommendations.

@ne0rrmatrix
Copy link
Contributor Author

Give me an hour or two and I will update this PR to address issues brought up. I have an idea of how we can do this and have everyone get what they want.

@mrucker
Copy link

mrucker commented May 7, 2025

@Elinares-82 Those two and I think you'd also need to get these two (it's been a while since I made the change)

image

- Added a new service for media playback in `AndroidManifest.xml` with intent filters for media button actions and media session service.
- Changed default value of `AndroidForegroundServiceEnabled` to `false` in `MediaElementOptions.shared.cs`.
- Removed unnecessary permission attributes from `MauiMediaElement.android.cs`.
- Updated test cases in `AppBuilderExtensionsTests.cs` to reflect the new default value for `AndroidForegroundServiceEnabled`.
@ne0rrmatrix
Copy link
Contributor Author

@Elinares-82 Those two and I think you'd also need to get these two (it's been a while since I made the change)

image

I was unable to remove those two items. It simply will not work without them. If you can test the latest PR in your project and see if not adding anything in manifest and then disabling the service using builder works for you I would appreciate it.

@Elinares-82
Copy link

Elinares-82 commented May 7, 2025

@Elinares-82 Those two and I think you'd also need to get these two (it's been a while since I made the change)
image

I was unable to remove those two items. It simply will not work without them. If you can test the latest PR in your project and see if not adding anything in manifest and then disabling the service using builder works for you I would appreciate it.

Thanks, I'm trying to compile and use the assembly, however, in my app several compilation errors come up and this is because I just need the Android part. I'm using the conditional references as well like

image

@Elinares-82
Copy link

MediaElementOptions

You are totally right; I think this will not fix my issue. Google rejected our app since in the Manifest are several permissions like FOREGROUND_SERVICE_MEDIA_PLAYBACK and FOREGROUND_SERVICE, but we just display a promo video in the splash screen. We are stuck at this point. The only way that I can see is use an old version or use an alternative like Blazor component.

@Elinares-82 there are tools that you allow you to edit the manifest on android app, so when you build your project and it generates the apk or aab you can unzip it, remove the permissions that you don't want and zip it again to ship into stores. I already did that for many apps that I worked and never had issues with that, and since are tools for it, I would say, isn't something unusual

I tried this, but, the installer is not be able to run.

- Introduced `UseMauiCommunityToolkitMediaElement_ShouldSetAndroidServiceByDefaultToFalse` to verify that `AndroidForegroundServiceEnabled` is `false` by default.
- Renamed `UseMauiCommunityToolkitMediaElement_ServiceCanBeDisabled` to `UseMauiCommunityToolkitMediaElement_ServiceCanBeEnabled` and updated its logic to check the service's initial state and enable it.
@ne0rrmatrix
Copy link
Contributor Author

I created a blank Maui app targeting dotnet 9. I then added the package after building and creating a nuget. I did not add anything to android manifest. I did add this to builder:

.UseMauiCommunityToolkitMediaElement(options => options.SetDefaultAndroidForegroundService(false));

It works as expected and service is disabled. Note that the rich media notifications do not work without the service. This is one of the tradeoffs.

@Elinares-82
Copy link

I then added the package after building and creating a nuget.

Thanks a lot @ne0rrmatrix , I was trying to create the nuget like yours, however, I do not know how, then I was researching about it.

@ne0rrmatrix ne0rrmatrix added breaking change This label is used for PRs that include a breaking change and removed breaking change This label is used for PRs that include a breaking change labels May 8, 2025
Fix tests
Service needs to be on by default in android as that will unify behavior
@mrucker
Copy link

mrucker commented May 8, 2025

I will test out this PR as well tomorrow. Thank you for your work @ne0rrmatrix!

Changed the property name for enabling the Android Foreground Service from `AndroidForegroundServiceEnabled` to `IsAndroidForegroundServiceEnabled` in `MediaElement.shared.cs` and `MediaElementOptions.shared.cs`. Updated the initialization and setter method accordingly. Modified related test cases in `AppBuilderExtensionsTests.cs` to reflect the new property name and ensure accurate verification of the service setting.
@Elinares-82
Copy link

I created a blank Maui app targeting dotnet 9. I then added the package after building and creating a nuget. I did not add anything to android manifest. I did add this to builder:

.UseMauiCommunityToolkitMediaElement(options => options.SetDefaultAndroidForegroundService(false));

It works as expected and service is disabled. Note that the rich media notifications do not work without the service. This is one of the tradeoffs.

@ne0rrmatrix I just tested the PR, I was able to create the nuget and load it to my DevOps Artifacts. The only additional thing that I had to do was downgrade the Microsoft.Maui.Controls to 9.0.40, since the 9.0.50 and 9.0.60 has and issue with the Keyboard and the Scroll, when the Keyboard appear the scroll of the view does not work as expected and the user is not able to scroll the view to see other controls. We are currently loading the aab file to the Google Store, I let you know if the app is approved. Thanks so much.

@Elinares-82
Copy link

I created a blank Maui app targeting dotnet 9. I then added the package after building and creating a nuget. I did not add anything to android manifest. I did add this to builder:

.UseMauiCommunityToolkitMediaElement(options => options.SetDefaultAndroidForegroundService(false));

It works as expected and service is disabled. Note that the rich media notifications do not work without the service. This is one of the tradeoffs.

@ne0rrmatrix I just tested the PR, I was able to create the nuget and load it to my DevOps Artifacts. The only additional thing that I had to do was downgrade the Microsoft.Maui.Controls to 9.0.40, since the 9.0.50 and 9.0.60 has and issue with the Keyboard and the Scroll, when the Keyboard appear the scroll of the view does not work as expected and the user is not able to scroll the view to see other controls. We are currently loading the aab file to the Google Store, I let you know if the app is approved. Thanks so much.

Hi, our app was rejected. The permission android.permission.FOREGROUND_SERVICE is added to our AndroidManifest, we are reviewing why since, we actually did not add it. I think is because of the Service definition (image below), the other permission was not added, I mean the ForegroundServiceMediaPlayback.

image

@pictos
Copy link
Member

pictos commented May 8, 2025

@Elinares-82 this issue with scroll view and keyboard is reported on Maui repo? If don't, do you mind to it?

@Elinares-82
Copy link

I created a blank Maui app targeting dotnet 9. I then added the package after building and creating a nuget. I did not add anything to android manifest. I did add this to builder:

.UseMauiCommunityToolkitMediaElement(options => options.SetDefaultAndroidForegroundService(false));

It works as expected and service is disabled. Note that the rich media notifications do not work without the service. This is one of the tradeoffs.

@ne0rrmatrix I just tested the PR, I was able to create the nuget and load it to my DevOps Artifacts. The only additional thing that I had to do was downgrade the Microsoft.Maui.Controls to 9.0.40, since the 9.0.50 and 9.0.60 has and issue with the Keyboard and the Scroll, when the Keyboard appear the scroll of the view does not work as expected and the user is not able to scroll the view to see other controls. We are currently loading the aab file to the Google Store, I let you know if the app is approved. Thanks so much.

Hi, our app was rejected. The permission android.permission.FOREGROUND_SERVICE is added to our AndroidManifest, we are reviewing why since, we actually did not add it. I think is because of the Service definition (image below), the other permission was not added, I mean the ForegroundServiceMediaPlayback.

image

Apparently is a rejected error was for a previous version of the app. We do not know why Google is rejecting the app for previous versions that have those permissions. We send an update that override the old versions (This was made in the Play Console)

@Elinares-82
Copy link

@Elinares-82 this issue with scroll view and keyboard is reported on Maui repo? If don't, do you mind to it?

@pictos sure, I'll check is this issue was already reported, in case not, I'll do it!

@Elinares-82
Copy link

Finally, our apps were approved by Google. Thanks. Now I'm reviewing the issue regarding the Scroll and Microsoft.Maui.Controls 9.0.50 and 60. and log it into the repo.

@Elinares-82
Copy link

Finally, our apps were approved by Google. Thanks. Now I'm reviewing the issue regarding the Scroll and Microsoft.Maui.Controls 9.0.50 and 60. and log it into the repo.

The issue is already logged

dotnet/maui#19014

2023 almost 2 years ago.

@ne0rrmatrix
Copy link
Contributor Author

ne0rrmatrix commented Jun 4, 2025

I am thinking we should switch to using just a builder option with no ability to toggle the service off and on. ATM switching back and forth does work but the images are not loading after turning off service and then turning it back on. Can see this bug live by loading popup in media element page. In this PR I have the service disabled when you load the popup to test this out. I will look at why the image is not loading. This may be caused by having two media elements loaded where one has it turned off and the other has it on. I will investigate the behavior.

Does anyone need or want the ability to switch at runtime? Or is a builder option ok? This PR currently has both. We could end up with issues when using multiple media elements where one is turned on and one is off? How do we want to handle that? It would be much simpler to have just the builder and no runtime switch. This would simplify implementation and make it easier to maintain. My bad for overcomplicating things.

@ne0rrmatrix ne0rrmatrix added the needs discussion Discuss it on the next Monthly standup label Jun 4, 2025
@bijington
Copy link
Contributor

I say just go with the builder option and keep things simple

@JoacimWall
Copy link

JoacimWall commented Jun 23, 2025

Hi
is this fixed now and then in what version? and are they instruction on how to disable foreground service?
Regards Joacim

@bijington
Copy link
Contributor

@JoacimWall this hasn't merged yet so is not yet available.

@ne0rrmatrix where are we with this? I think we have a solution but it is breaking? Do you think there is anything we could mark as Obsolete in an upcoming release that would indicate to developers they needed to opt-in to the foreground service in future releases? I am suspecting it wouldn't be easy given the developer didn't have to call any foreground specific code?

@ne0rrmatrix
Copy link
Contributor Author

The main changes are having to add service registration and permissions to Android manifest. We had removed that and added it directly. With this PR developers will be required to do so again. Also they need to opt out of service. i don't see how to use obsolete as intended with how this works.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
do not merge Do not merge this PR 📽️ MediaElement Issue/PR that has to do with MediaElement needs discussion Discuss it on the next Monthly standup
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[Proposal] Add MediaElement Foreground Service to Media Options
6 participants