Skip to content

ActivityResultContracts.CreateDocument class implementation error #504

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

Closed
josago97 opened this issue Mar 8, 2022 · 3 comments · Fixed by #512
Closed

ActivityResultContracts.CreateDocument class implementation error #504

josago97 opened this issue Mar 8, 2022 · 3 comments · Fixed by #512

Comments

@josago97
Copy link

josago97 commented Mar 8, 2022

Version Information

  • Visual Studio version: 17.1.0
  • Xamarin.Android version: 12.2.0.4
  • Using AndroidX or Support Libraries:
  • Xamarin.AndroidX.AppCompat: 1.4.1
  • Xamarin.AndroidX.SwipeRefreshLayout: 1.1.0.7
  • Xamarin.Essentials: 1.7.1
  • Xamarin.Google.Android.Material: 1.5.0

Describe your Issue:

The implementation of the ActivityResultContracts.CreateDocument class does not correspond to the official implementation https://developer.android.com/reference/androidx/activity/result/contract/ActivityResultContracts.CreateDocument. According to the official page, this class has a constructor with 1 parameter of type string and the CreateIntent method does not match the type of the parameters. This difference in implementation causes a compile error when overriding the CreateIntent method.

image
image
image

@moljac moljac mentioned this issue Mar 16, 2022
@moljac moljac linked a pull request Mar 16, 2022 that will close this issue
@moljac
Copy link
Contributor

moljac commented Mar 16, 2022

fixed in

#512

@josago97
Copy link
Author

Thanks, so I will close this

@moljac
Copy link
Contributor

moljac commented Mar 17, 2022

Thanks
Normally you would close after PR merge, publishing of the packages and confirmation.

If the issue persits open new issue.

jonpryor pushed a commit to dotnet/java-interop that referenced this issue Apr 19, 2022
Fixes: #967

Context: dotnet/android-libraries#504
Context: #424
Context: #586
Context: #918

Java generics continues to be a "difficulty" in creating bindings.
Consider [`ActivityResultContracts.RequestPermission`][0]:

	// Java
	public abstract /* partial */ class ActivityResultContract<I, O> {
	    public abstract Intent createIntent(Context context, I input);
	}
	public /* partial */ class /* ActivityResultContracts. */ RequestPermission
	    extends ActivityResultContract<String, Boolean>
	{
	    @OverRide public Intent createIntent(Context context, String input) {…}
	}

The JNI Signature for
`ActivityResultContracts.RequestPermission.createIntent()` is
`(Landroid/content/Context;Ljava/lang/String;)Landroid/content/Intent;`,
i.e. `class-parse` & `generator` believe that the `input` parameter
is of type `String`, which we bind by default as `string`.  Thus:

	// C#
	public abstract partial class ActivityResultContract {
	    public abstract Intent CreateIntent (Context? context, Java.Lang.Object? input) => …
	}
	public partial class /* ActivityResultContracts. */ RequestPermission {
	    public override Intent CreateIntent (Context? context, string? input) => …
	}

This fails to compile with a [CS0115][1]:

	'RequestPermission.CreateIntent(Context?, string?)': no suitable method found to override

as the `input` parameter of `RequestPermission.CreateIntent()` changes
from `Java.Lang.Object?` to `string?`.

We can attempt to address this via Metadata:

	<attr
	  path="/api/package[@name='androidx.activity.result.contract']/class[@name='ActivityResultContracts.RequestPermission']/method[@name='createIntent' and count(parameter)=2 and parameter[1][@type='android.content.Context'] and parameter[2][@type='java.lang.String']]"
	  name="managedType"
	>Java.Lang.Object</attr>

This fixes one error, as `generator` now emits:

	public partial class /* ActivityResultContracts. */ RequestPermission {
	    [Register ("createIntent", "(Landroid/content/Context;Ljava/lang/String;)Landroid/content/Intent;", "")]
	    public override unsafe global::Android.Content.Intent CreateIntent (global::Android.Content.Context context, global::Java.Lang.Object input)
	    {
	        const string __id = "createIntent.(Landroid/content/Context;Ljava/lang/String;)Landroid/content/Intent;";
	        IntPtr native_input = JNIEnv.NewString (input);
	        try {
	            JniArgumentValue* __args = stackalloc JniArgumentValue [2];
	            __args [0] = new JniArgumentValue ((context == null) ? IntPtr.Zero : ((global::Java.Lang.Object) context).Handle);
	            __args [1] = new JniArgumentValue (native_input);
	            var __rm = _members.InstanceMethods.InvokeAbstractObjectMethod (__id, this, __args);
	            return global::Java.Lang.Object.GetObject<global::Android.Content.Intent> (__rm.Handle, JniHandleOwnership.TransferLocalRef);
	        } finally {
	            JNIEnv.DeleteLocalRef (native_input);
	            global::System.GC.KeepAlive (context);
	            global::System.GC.KeepAlive (input);
	        }
	    }
	}

The `override` method declaration is correct.

However, this introduces a [CS1503][2] error:

	IntPtr native_input = JNIEnv.NewString (input);
	// Error CS1503 Argument 1: cannot convert from 'Java.Lang.Object' to 'string?'

The workaround is to remove `createIntent()` ~entirely, and manually
bind it, as done in dotnet/android-libraries#512.

Fix this issue by always emitting a cast to `(string)` as
part of the `JNIEnv.NewString()` invocation, instead emitting:

	IntPtr native_input = JNIEnv.NewString ((string?) input);

This works because `Java.Lang.Object` defines an
[explicit conversion to `string?`][3], and if a `Java.Lang.String`
instance is provided to the `input` parameter, it's equivalent to
calling `.ToString()`.

This fix allows the original suggested Metadata solution to work.

[0]: https://developer.android.com/reference/androidx/activity/result/contract/ActivityResultContracts.RequestPermission
[1]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/compiler-messages/cs0115
[2]: https://docs.microsoft.com/en-us/dotnet/csharp/misc/cs1503
[3]: https://github.com/xamarin/xamarin-android/blob/a58d4e9706455227eabb6e5b5103b25da716688b/src/Mono.Android/Java.Lang/Object.cs#L434-L439
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants