Communities

Writing
Writing
Codidact Meta
Codidact Meta
The Great Outdoors
The Great Outdoors
Photography & Video
Photography & Video
Scientific Speculation
Scientific Speculation
Cooking
Cooking
Electrical Engineering
Electrical Engineering
Judaism
Judaism
Languages & Linguistics
Languages & Linguistics
Software Development
Software Development
Mathematics
Mathematics
Christianity
Christianity
Code Golf
Code Golf
Music
Music
Physics
Physics
Linux Systems
Linux Systems
Power Users
Power Users
Tabletop RPGs
Tabletop RPGs
Community Proposals
Community Proposals
tag:snake search within a tag
answers:0 unanswered questions
user:xxxx search by author id
score:0.5 posts with 0.5+ score
"snake oil" exact phrase
votes:4 posts with 4+ votes
created:<1w created < 1 week ago
post_type:xxxx type of post
Search help
Notifications
Mark all as read See all your notifications »
Q&A

Welcome to Software Development on Codidact!

Will you help us build our independent community of developers helping developers? We're small and trying to grow. We welcome questions about all aspects of software development, from design to code to QA and more. Got questions? Got answers? Got code you'd like someone to review? Please join us.

Android CameraPreview not rendering for MLKit barcode analyis on MAUI custom control

+1
−0

I have a QR code which needs to read through Google's ML kit for Android since Zxing.MAUI doesnt read it. I followed the code in ml-kit/vision/barcode-scanning/android and VinayByte/mlkit-qr-code-scan-android-kotlin and also hjam40/Camera.MAUI I was not able to use Camera.MAUI since it doesnt work for .net 9

Here is my custom control code, if anyone has an idea why the preview is not showing up that would be a great help!

builder.ConfigureMauiHandlers(handlers =>
{
    handlers.AddHandler<QRCodeReaderView, QRCodeReaderViewHandler>();
});

Custom control

public class QRCodeReaderView : View {}
public partial class QRCodeReaderViewHandler
{
    public static IPropertyMapper<QRCodeReaderView, QRCodeReaderViewHandler> PropertyMapper = new PropertyMapper<QRCodeReaderView, QRCodeReaderViewHandler>(ViewMapper)
    {
       
    };

    public static CommandMapper<QRCodeReaderView, QRCodeReaderViewHandler> CommandMapper = new CommandMapper<QRCodeReaderView, QRCodeReaderViewHandler>(ViewCommandMapper)
    {
    };

  
    public QRCodeReaderViewHandler() : base(PropertyMapper, CommandMapper) { }
}
using System.Diagnostics;
using AndroidX.Camera.Core;
using AndroidX.Camera.Core.ResolutionSelector;
using AndroidX.Camera.Lifecycle;
using AndroidX.Camera.View;
using AndroidX.Core.Content;
using AndroidX.Lifecycle;
using Java.Lang;
using Java.Util.Concurrent;
using Microsoft.Maui.Handlers;
using Exception = System.Exception;
using Size = Android.Util.Size;

namespace QRCodeScanner;

public partial class QRCodeReaderViewHandler : ViewHandler<QRCodeReaderView, AndroidQRCodeReaderView>
{
    private Preview? _cameraPreview;
    private PreviewView _previewView;
    private IExecutorService? cameraExecutor;
    private ICamera? _camera;
    
    protected override AndroidQRCodeReaderView CreatePlatformView()
    {
        var context = MauiContext?.Context ?? Platform.AppContext;
        _previewView = new PreviewView(context);
        return new AndroidQRCodeReaderView(context, _previewView);
    }

    protected override void ConnectHandler(AndroidQRCodeReaderView platformView)
    {
        base.ConnectHandler(platformView);
        if (MauiContext is not null)
        {
            Connect(MauiContext, platformView.PreviewView);
        }
        
    }

    public void Connect(IMauiContext mauiContext, PreviewView previewView)
    {
        try
        {
            if (mauiContext.Context is null)
            {
                return;
            }
            cameraExecutor = Executors.NewSingleThreadExecutor();
            var cameraProviderFuture = ProcessCameraProvider.GetInstance(mauiContext.Context);
            if (cameraExecutor is null)
                return;
            var cameraProvider = cameraProviderFuture.Get() as ProcessCameraProvider;
            if (cameraProvider is null)
                return;
            cameraProviderFuture.AddListener(new Runnable(() =>
             {

                 var resolutionSelector = new ResolutionSelector.Builder().SetResolutionStrategy(new ResolutionStrategy(boundSize: new Size(1280, 700),
                                                                                                                        fallbackRule: ResolutionStrategy.FallbackRuleClosestHigherThenLower))
                                                                          .Build();

                 _cameraPreview = new Preview.Builder().SetResolutionSelector(resolutionSelector).Build();
                 _cameraPreview.SetSurfaceProvider(cameraExecutor, previewView.SurfaceProvider);

                 var imageAnalyzer = new ImageAnalysis.Builder()
                                     .SetBackpressureStrategy(ImageAnalysis.StrategyKeepOnlyLatest) 
                                     .SetResolutionSelector(resolutionSelector)
                                     .Build();
                 var mLkitQrCodeAnalyzer = new MLkitQRCodeAnalyzer();
                 imageAnalyzer.SetAnalyzer(cameraExecutor, mLkitQrCodeAnalyzer);
                 cameraProvider.UnbindAll();
                 var cameraSelector = CameraSelector.DefaultBackCamera;
                 var hasCamera = cameraProvider.HasCamera(cameraSelector);
                 Debug.WriteLine($"hasCamera: {hasCamera}");
                 if (previewView.Context is ILifecycleOwner lifecycleOwner)
                 {
                     _camera = cameraProvider.BindToLifecycle(lifecycleOwner, cameraSelector, _cameraPreview, imageAnalyzer);
                 }
                 else if (Platform.CurrentActivity is ILifecycleOwner maLifecycleOwner)
                 {
                     _camera = cameraProvider.BindToLifecycle(maLifecycleOwner, cameraSelector, _cameraPreview, imageAnalyzer);
                 }
             }),
             ContextCompat.GetMainExecutor(mauiContext.Context));
        }
        catch (Exception ex)
        {
            Debug.WriteLine(ex.StackTrace);
        }
    }
}

Camera permissions <uses-permission android:name="android.permission.CAMERA"/>

private async Task CheckAndRequestCameraPermission()
{
    var status = await Permissions.CheckStatusAsync<Permissions.Camera>();
    if (status != PermissionStatus.Granted)
    {
        status = await Permissions.RequestAsync<Permissions.Camera>();
        if (status != PermissionStatus.Granted)
        {
            await DisplayAlert("Camera Permission Denied", "This app needs access to the camera to scan QR codes.", "OK");
        }
    }
}

protected override async void OnAppearing()
{
    base.OnAppearing();
    await CheckAndRequestCameraPermission();
}

UI

<?xml version="1.0" encoding="utf-8"?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:toolkit="http://schemas.microsoft.com/dotnet/2022/maui/toolkit"
             xmlns:local="clr-namespace:QRCodeScanner"
             x:DataType="{x:Type local:MainViewModel}"
             x:Class="QRCodeScanner.MainPage">
    <ContentPage.Resources>
        <toolkit:BoolToObjectConverter x:TypeArguments="x:String"
                                       x:Key="BoolToStringConverter"
                                       TrueObject="On"
                                       FalseObject="Off" />
    </ContentPage.Resources>
    <VerticalStackLayout Spacing="10"
                         Padding="20">
        <Label Text="Below is the scanner"
               HorizontalOptions="Center" />
        <local:QRCodeReaderView HorizontalOptions="Fill"
                                VerticalOptions="Fill"
                                HeightRequest="400"
                                WidthRequest="400"
                                ResultCommand="{Binding QRResultCommand}"
                                IsFlashOn="{Binding IsFlashOn}"
                                IsVisible="{Binding IsVisible}"
                                x:Name="qrCodeReaderView" />
        <HorizontalStackLayout HorizontalOptions="Center"
                               Spacing="20"
                               IsVisible="{Binding IsVisible}">
            <Label Text="{Binding IsFlashOn, Source={Reference qrCodeReaderView}, Converter={StaticResource BoolToStringConverter}, StringFormat='Flash {0}'}"
                   VerticalOptions="Center"
                   VerticalTextAlignment="Center" />
            <Switch IsToggled="{Binding IsFlashOn}" />
        </HorizontalStackLayout>
        <Label HorizontalOptions="Center"
               VerticalOptions="End"
               Margin="0,0,0,20"
               Text="{Binding Result}" />
    </VerticalStackLayout>
</ContentPage>

Edit:

On further analysis through Logcat I found the issue to be as following

Unable to configure camera Camera@461d7c2[id=0]
                                                                                                    java.util.concurrent.TimeoutException: Future[androidx.camera.core.impl.utils.futures.ListFuture@4c0973e] is not done within 5000 ms.

The possible solution to set android:hardwareAccelerated="true" application level or MainActivity level is not working too.

Screenshot

History
Why does this post require attention from curators or moderators?
You might want to add some details to your flag.
Why should this post be closed?

0 comment threads

1 answer

+0
−0

Answering my own question in case anyone else stumbles upon this.

Changing native platform implementation from Android.Views.View to AndroidX.CoordinatorLayout.Widget.CoordinatorLayout like following fixed the issue of preview not showing.

protected override AndroidQRCodeReaderView CreatePlatformView()
{
    var context = MauiContext?.Context ?? Platform.AppContext;
    _previewView = new PreviewView(context)
    {
        LayoutParameters = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.MatchParent, ViewGroup.LayoutParams.MatchParent)
    };
    var _relativeLayout = new RelativeLayout(context)
    {
        LayoutParameters = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.MatchParent, ViewGroup.LayoutParams.MatchParent)
    };
    _relativeLayout.AddView(_previewView);
    var platformview = new AndroidQRCodeReaderView(context);
    platformview.AddView(_relativeLayout);
    return platformview;
}

Reference: github/afriscic/BarcodeScanning.Native.Maui

History
Why does this post require attention from curators or moderators?
You might want to add some details to your flag.

0 comment threads

Sign up to answer this question »