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

No way to create the "IAttributeSet" required by Android ExoPlayer constructor in .NET/C# #102300

Closed
jonmdev opened this issue May 16, 2024 · 3 comments

Comments

@jonmdev
Copy link

jonmdev commented May 16, 2024

Description

ExoPlayer is the Android video player recommended by Google and used by the MAUI Community Toolkit for video playback.

It has the following constructor in .NET:

public unsafe StyledPlayerView (global::Android.Content.Context? context, global::Android.Util.IAttributeSet? attrs) : base (IntPtr.Zero, JniHandleOwnership.DoNotTransfer)

ExoPlayer can be constructed with a SurfaceView, TextureView, or none type of surface_type. This surface_type determines rendering behavior of the video player. It can only be declared on construction of the ExoPlayer.

In order to specify this, we are intended by Google to create or load some XML stating the surface_type, convert it to an IAttributeSet and then pass it to this constructor.

However, this does not work in .NET/C# and there is therefore currently no way to build a TextureView type ExoPlayer. SurfaceView is the default but TextureView is needed in many situations, and there is no way in .NET to get it.

Prior Discussion

See:

Despite two Android discussions, two MAUI discussions, and two StackOverflow discussions, no one anywhere can propose a working method for this to be done. Thus it seems this is a C#/.NET bug that must be fixed so we can use this properly.

By contrast a supposedly working Kotlin method is proposed here, but the functions referenced don't have matching C# equivalents so this is a dead end.

My Best Attempt

My best attempt to do this is is with adding the following code to a default .NET Android Application:

protected override void OnCreate(Bundle? savedInstanceState) {
    base.OnCreate(savedInstanceState);

    string xmlString =
        "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n" +
        "<Com.Google.Android.Exoplayer2.UI.StyledPlayerView " +
        //"<com.google.android.exoplayer2.ui.PlayerView " +
        "android:id=\"@+id/player_view\" " +
        "app:surface_type=\"texture_view\" " +
        "android:layout_width=\"match_parent\" " +
        "android:layout_height=\"match_parent\"/>";

    XmlReader xmlReader = XmlReader.Create(new StringReader(xmlString));
    xmlReader.Read(); // https://learn.microsoft.com/en-us/dotnet/api/system.xml.xmlreader.read?view=net-8.0
    
    Android.Util.IAttributeSet attributes = Android.Util.Xml.AsAttributeSet(xmlReader);
    
    //BUILD EXOPLAYER
    Com.Google.Android.Exoplayer2.UI.StyledPlayerView styledPlayerView = new(this, attributes);
    System.Diagnostics.Debug.WriteLine("SURFACE TYPE " + styledPlayerView.VideoSurfaceView.GetType());

Error

However, this returns the error:

**Java.Lang.ClassCastException:** 'android.util.XmlPullAttributes cannot be cast to android.content.res.XmlBlock$Parser'

The only reference I can find to this error suggests it is an insurmountable dead end: https://stackoverflow.com/questions/33331935/xmlpullattributes-cannot-be-cast-to-xmlblockparser#45918669

So what is the solution? Can .NET be fixed so that we can use this constructor and build ExoPlayer with a TextureView rather than SurfaceView?

Bug Project

See reproduction bug Project here: https://github.com/jonmdev/AndroidIAttributeSetBug

Reproduction Steps

Play bug project above. Or, to remake it, in Visual Studio 2022:

  1. File > New > Android Application
  2. Add the ExoPlayer NuGet Xam.Plugins.Android.ExoPlayer
  3. Then in MainActivity.cs, copy/paste the code from above or also here: https://github.com/jonmdev/AndroidIAttributeSetBug/blob/main/AndroidIAttributeSetBug/MainActivity.cs

Expected behavior

Should be able to make a TextureView ExoPlayer.

Actual behavior

Dead end error - cannot do so.

Regression?

I can find no reference anywhere on the Internet that suggests this ever worked or anyone has ever successfully made it work.

Known Workarounds

None known seemingly by anyone anywhere.

Other information

Any help toward a solution is greatly appreciated.

@dotnet-issue-labeler dotnet-issue-labeler bot added the needs-area-label An area label is needed to ensure this gets routed to the appropriate area owners label May 16, 2024
@dotnet-policy-service dotnet-policy-service bot added the untriaged New issue has not been triaged by the area owner label May 16, 2024
@am11 am11 added area-Meta and removed needs-area-label An area label is needed to ensure this gets routed to the appropriate area owners labels May 16, 2024
Copy link
Contributor

Tagging subscribers to this area: @dotnet/area-meta
See info in area-owners.md if you want to be subscribed.

@huoyaoyuan
Copy link
Member

Android API for .NET lives in https://github.com/xamarin/xamarin-android. Discussions should go there.

Searching for the corresponding API of kotlin, I can find an API at https://learn.microsoft.com/en-us/dotnet/api/android.content.res.resources.getxml .

@jonmdev
Copy link
Author

jonmdev commented May 16, 2024

Thank you actually @huoyaoyuan !

Your reply made me realize the Kotlin solution I posted was not programmatically creating the XML but just loading from resources. It seems Android offers no way to allow one to programmatically do this. One must save the XML to resources and then load it.

Absolutely absurd in my opinion, but this does work.

.NET SOLUTION

  1. Create XML file named "test.xml" in Resources\layout
  2. Copy paste into it:
<?xml version="1.0" encoding="utf-8" ?> 
<com.google.android.exoplayer2.ui.StyledPlayerView 
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/test"
    app:surface_type="texture_view"
    android:layout_width= "match_parent"
    android:layout_height= "match_parent" />
  1. Run code in MainActivity.cs:
XmlReader xmlResource = this.Resources.GetXml(Resource.Layout.test);
xmlResource.Read();

Android.Util.IAttributeSet attributes = Android.Util.Xml.AsAttributeSet(xmlResource);

//BUILD EXOPLAYER
Com.Google.Android.Exoplayer2.UI.StyledPlayerView styledPlayerView = new(this, attributes); 

This does work.

@jonmdev jonmdev closed this as completed May 16, 2024
@dotnet-policy-service dotnet-policy-service bot removed the untriaged New issue has not been triaged by the area owner label May 16, 2024
@github-actions github-actions bot locked and limited conversation to collaborators Jun 15, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

3 participants