AndroidX icon indicating copy to clipboard operation
AndroidX copied to clipboard

AbstractMethodError: abstract method "android.util.Size androidx.camera.core.ImageAnalysis$Analyzer.getDefaultTargetResolution()"

Open rgroenewoudt opened this issue 2 years ago • 9 comments

Android application type

Android for .NET (net6.0-android, etc.)

Affected platform version

VS2022 17.6.5

Description

With the latest version of CameraX we are running into an exception when inheriting from ImageAnalysis.IAnalyzer:

JNI DETECTED ERROR IN APPLICATION: JNI CallObjectMethodA called with pending exception java.lang.AbstractMethodError: abstract method "android.util.Size androidx.camera.core.ImageAnalysis$Analyzer.getDefaultTargetResolution()"
at android.util.Size crc64c8b333e758042baf.MainActivity_MyAnalyzer.n_getDefaultTargetResolution() (MainActivity_MyAnalyzer.java:-2)
at android.util.Size crc64c8b333e758042baf.MainActivity_MyAnalyzer.getDefaultTargetResolution() (MainActivity_MyAnalyzer.java:34)
at androidx.camera.core.impl.UseCaseConfig androidx.camera.core.ImageAnalysis.onMergeConfig(androidx.camera.core.impl.CameraInfoInternal, androidx.camera.core.impl.UseCaseConfig$Builder) (ImageAnalysis.java:277)
at androidx.camera.core.impl.UseCaseConfig androidx.camera.core.UseCase.mergeConfigs(androidx.camera.core.impl.CameraInfoInternal, androidx.camera.core.impl.UseCaseConfig, androidx.camera.core.impl.UseCaseConfig) (UseCase.java:277)
at java.util.Map androidx.camera.core.internal.CameraUseCaseAdapter.calculateSuggestedStreamSpecs(int, androidx.camera.core.impl.CameraInfoInternal, java.util.Collection, java.util.Collection, java.util.Map) (CameraUseCaseAdapter.java:682)

We are not calling getDefaultTargetResolution() directly, just passing a ImageAnalysis.IAnalyzer object to the library.

Steps to Reproduce

Minimum reproducible app: AndroidApp7.zip

Tested & affected versions for: Xamarin.AndroidX.Camera.Camera2/Xamarin.AndroidX.Camera.Lifecycle: 1.2.3.1, 1.2.2

Did you find any workaround?

Revert back Xamarin.AndroidX.Camera.* back to 1.2.1

Relevant log output

No response

rgroenewoudt avatar Jul 28 '23 09:07 rgroenewoudt

same issue

pulmuone avatar Jul 28 '23 12:07 pulmuone

Adding DefaultTargetResolution property to the class being passed to SetAnalyzer method seems solving the issue:

imageAnalysis.SetAnalyzer(ContextCompat.GetMainExecutor(Context), this); ... public Android.Util.Size DefaultTargetResolution => new Android.Util.Size(200, 200);

lexboss777 avatar Jul 31 '23 11:07 lexboss777

Adding DefaultTargetResolution property to the class being passed to SetAnalyzer method seems solving the issue:

imageAnalysis.SetAnalyzer(ContextCompat.GetMainExecutor(Context), this); ... public Android.Util.Size DefaultTargetResolution => new Android.Util.Size(200, 200);

Thank you.

pulmuone avatar Jul 31 '23 14:07 pulmuone

Investigation notes (net8.0-android):

getDefaultTargetResolution is a default interface method on the Analyzer interface, it gets bound like this:

[Register("androidx/camera/core/ImageAnalysis$Analyzer", "", "AndroidX.Camera.Core.ImageAnalysis/IAnalyzerInvoker")]
public interface IAnalyzer : IJavaObject, IDisposable, IJavaPeerable {
    unsafe Size? DefaultTargetResolution
    {
        [Register("getDefaultTargetResolution", "()Landroid/util/Size;", "GetGetDefaultTargetResolutionHandler:AndroidX.Camera.Core.ImageAnalysis/IAnalyzer, Xamarin.AndroidX.Camera.Core")]
        get {
            return Java.Lang.Object.GetObject<Size>(_members.InstanceMethods.InvokeVirtualObjectMethod("getDefaultTargetResolution.()Landroid/util/Size;", this, null).Handle, JniHandleOwnership.TransferLocalRef);
        }
    }

    private static Delegate? cb_getDefaultTargetResolution;

    private static Delegate GetGetDefaultTargetResolutionHandler()
    {
        if ((object)cb_getDefaultTargetResolution == null)
        {
            cb_getDefaultTargetResolution = JNINativeWrapper.CreateDelegate(new global::_JniMarshal_PP_L(n_GetDefaultTargetResolution));
        }

        return cb_getDefaultTargetResolution;
    }

    private static nint n_GetDefaultTargetResolution(nint jnienv, nint native__this)
    {
        return JNIEnv.ToLocalJniHandle(Java.Lang.Object.GetObject<IAnalyzer>(jnienv, native__this, JniHandleOwnership.DoNotTransfer).DefaultTargetResolution);
    }
}

This appears to be an issue with Java calling a default interface method where the C# type has not provided a non-default method implementation.

Providing a non-default method implementation in C# fixes the crash.

jpobst avatar Mar 15 '24 17:03 jpobst

As per discussion on Discord

TL;DR: The problem is Desugaring. (TODO: links?)

Before API-24, in order to support some Java 8 features such as default interface methods and interface static methods, the Dalvik code had to be "desugared", which resulted in moving various methods into new $Foo-suffixed types. See also e.g.:

  • https://github.com/dotnet/java-interop/commit/1f27ab552d03aeb74cdc6f8985fcffbfdb9a7ddf
  • https://github.com/dotnet/java-interop/commit/bbaeda6f698369bdd48bfc2dd1a32a41c9d23229

The problem here is with default interface methods, and our binding tries to non-virtually invoke the interface method.

In a Desugared "environment", the default interface method body is not in the interface; it's "elsewhere". The interface does have an abstract method for the (former) default interface method, which we then try to non virtually invoke, which fails.

The Workaround: Set your minimum supported API level to API-26 or later. This means Desugaring isn't needed, and things work.

The Fix? (lol): Update dotnet/java-interop to support desugared default interface methods. (There is no current timeline for this.)

jonpryor avatar Oct 31 '24 00:10 jonpryor

@jpobst: how easy or plausible would it be to:

  1. Detect if a given binding contains a default interface method or interface static method, and
  2. When found, include an AndroidManifest.xml within the binding that sets android:minSdkVersion to 26?

Setting the minimum to API-26 will prevent desugaring, thus avoiding this scenario.

jonpryor avatar Oct 31 '24 00:10 jonpryor

am facing the same problem each time i add Plugin.maui.ocr, am new to programing how can i fix or add the suggested or mention solution?

Shabz614 avatar Dec 10 '24 07:12 Shabz614

Change the

<SupportedOSPlatformVersion>21</SupportedOSPlatformVersion>

in your .csproj file to:

<SupportedOSPlatformVersion>24</SupportedOSPlatformVersion>

(or add it with 24 if it doesn't exist.)

jpobst avatar Dec 10 '24 08:12 jpobst

@jpobst thank you

Shabz614 avatar Dec 10 '24 08:12 Shabz614