123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316 |
- using Android;
- using Android.Content;
- using Android.Graphics;
- using AndroidX.Camera.Core;
- using AndroidX.Camera.Core.ResolutionSelector;
- using AndroidX.Camera.View;
- using AndroidX.Camera.View.Transform;
- using AndroidX.Core.Content;
- using AndroidX.Lifecycle;
- using Avalonia.Media;
- using Avalonia.Threading;
- using InABox.Avalonia.Platform.Barcodes;
- using Java.Util.Concurrent;
- using Microsoft.Maui.Devices;
- using static Android.Views.ViewGroup;
- using Color = Android.Graphics.Color;
- using AvColor = Avalonia.Media.Color;
- using Avalonia;
- namespace InABox.Avalonia.Platform.Android.Barcodes;
- internal class CameraManager : IDisposable
- {
- internal BarcodeView BarcodeView { get => _barcodeView; }
- internal CameraView? CameraView { get => _cameraView; }
- internal PreviewView PreviewView { get => _previewView; }
- internal CameraState? OpenedCameraState { get; set; }
- private readonly BarcodeAnalyzer _barcodeAnalyzer;
- private readonly BarcodeView _barcodeView;
- private readonly Context _context;
- private readonly IExecutorService _analyzerExecutor;
- private readonly ImageView _imageView;
- private readonly LifecycleCameraController _cameraController;
- private readonly ILifecycleOwner _lifecycleOwner;
- private readonly PreviewView _previewView;
- private readonly RelativeLayout _relativeLayout;
- private readonly CameraStateObserver _cameraStateObserver;
- private readonly CameraView? _cameraView;
- // Caches of CameraView properties to avoid calling on non-main threads.
- internal bool _pauseScanning;
- internal bool _forceInverted;
- internal bool _forceFrameCapture;
- internal bool _captureNextFrame;
- internal bool _aimMode;
- internal bool _viewFinderMode;
- private ICameraInfo? _currentCameraInfo;
- private const int aimRadius = 25;
- static CameraManager()
- {
- }
- internal CameraManager(CameraView cameraView, Context context)
- {
- _context = context;
- _cameraView = cameraView;
- ILifecycleOwner? owner = null;
- if (_context is ILifecycleOwner)
- owner = _context as ILifecycleOwner;
- else if ((_context as ContextWrapper)?.BaseContext is ILifecycleOwner)
- owner = (_context as ContextWrapper)?.BaseContext as ILifecycleOwner;
- // else if (Platform.CurrentActivity is ILifecycleOwner)
- // owner = Platform.CurrentActivity as ILifecycleOwner;
-
- var executor = Executors.NewSingleThreadExecutor();
- ArgumentNullException.ThrowIfNull(owner);
- ArgumentNullException.ThrowIfNull(executor);
- _lifecycleOwner = owner;
- _analyzerExecutor = executor;
- _barcodeAnalyzer = new BarcodeAnalyzer(this);
- _cameraStateObserver = new CameraStateObserver(this, _cameraView);
- _cameraController = new LifecycleCameraController(_context)
- {
- TapToFocusEnabled = _cameraView?.TapToFocusEnabled ?? false,
- ImageAnalysisBackpressureStrategy = ImageAnalysis.StrategyKeepOnlyLatest
- };
- _cameraController.SetEnabledUseCases(CameraController.ImageAnalysis);
- _cameraController.ZoomState.ObserveForever(_cameraStateObserver);
- _cameraController.InitializationFuture.AddListener(new Java.Lang.Runnable(() =>
- {
- _currentCameraInfo?.CameraState.RemoveObserver(_cameraStateObserver);
- _currentCameraInfo = _cameraController.CameraInfo;
- _currentCameraInfo?.CameraState.ObserveForever(_cameraStateObserver);
- }), ContextCompat.GetMainExecutor(_context));
- ArgumentNullException.ThrowIfNull(PreviewView.ImplementationMode.Compatible);
- ArgumentNullException.ThrowIfNull(PreviewView.ScaleType.FillCenter);
- ArgumentNullException.ThrowIfNull(Bitmap.Config.Argb8888);
- _previewView = new PreviewView(_context)
- {
- LayoutParameters = new RelativeLayout.LayoutParams(LayoutParams.MatchParent, LayoutParams.MatchParent)
- };
- var background = (_cameraView?.Background as SolidColorBrush)?.Color ?? Colors.Transparent;
- _previewView.SetBackgroundColor(new Color(background.R, background.G, background.B, background.A));
- _previewView.SetImplementationMode(PreviewView.ImplementationMode.Compatible);
- _previewView.SetScaleType(PreviewView.ScaleType.FillCenter);
-
- using var layoutParams = new RelativeLayout.LayoutParams(LayoutParams.WrapContent, LayoutParams.WrapContent);
- layoutParams.AddRule(LayoutRules.CenterInParent);
- using var circleBitmap = Bitmap.CreateBitmap(2 * aimRadius, 2 * aimRadius, Bitmap.Config.Argb8888);
- using var canvas = new Canvas(circleBitmap);
- canvas.DrawCircle(aimRadius, aimRadius, aimRadius, new Paint
- {
- AntiAlias = true,
- Color = Color.Red,
- Alpha = 150
- });
- _imageView = new ImageView(_context)
- {
- LayoutParameters = layoutParams
- };
- _imageView.SetImageBitmap(circleBitmap);
- _relativeLayout = new RelativeLayout(_context)
- {
- LayoutParameters = new RelativeLayout.LayoutParams(LayoutParams.MatchParent, LayoutParams.MatchParent)
- };
- _relativeLayout.AddView(_previewView);
- _barcodeView = new BarcodeView(_context);
- _barcodeView.AddView(_relativeLayout);
- DeviceDisplay.Current.MainDisplayInfoChanged += MainDisplayInfoChangedAsync;
- }
- internal void Start()
- {
- if (_previewView is not null)
- _previewView.Controller = null;
- if (OpenedCameraState?.GetType() != CameraState.Type.Closed)
- _cameraController?.Unbind();
-
- _cameraController?.ClearImageAnalysisAnalyzer();
- if (_barcodeAnalyzer is not null && _analyzerExecutor is not null)
- _cameraController?.SetImageAnalysisAnalyzer(_analyzerExecutor, _barcodeAnalyzer);
- UpdateResolution();
- UpdateCamera();
- UpdateSymbologies();
- UpdateTorch();
- if (_lifecycleOwner is not null)
- _cameraController?.BindToLifecycle(_lifecycleOwner);
-
- if (_previewView is not null && _cameraController is not null)
- _previewView.Controller = _cameraController;
- }
- internal void Stop()
- {
- _cameraController?.Unbind();
- }
- internal void UpdateAimMode()
- {
- if (_aimMode)
- _relativeLayout?.AddView(_imageView);
- else
- _relativeLayout?.RemoveView(_imageView);
- }
- internal void UpdateBackgroundColor()
- {
- var background = (_cameraView?.Background as SolidColorBrush)?.Color ?? Colors.Transparent;
- _previewView.SetBackgroundColor(new Color(background.R, background.G, background.B, background.A));
- }
- internal void UpdateCamera()
- {
- if (_cameraController is not null)
- {
- if (_cameraView?.CameraFacing == CameraFacing.Front)
- _cameraController.CameraSelector = CameraSelector.DefaultFrontCamera;
- else
- _cameraController.CameraSelector = CameraSelector.DefaultBackCamera;
- }
- }
- internal void UpdateCameraEnabled()
- {
- if (_cameraView?.CameraEnabled ?? false)
- Start();
- else
- Stop();
- }
- internal void UpdateResolution()
- {
- using var analysisStrategy = new ResolutionStrategy(Methods.TargetResolution(_cameraView?.CaptureQuality), ResolutionStrategy.FallbackRuleClosestHigherThenLower);
- using var resolutionBuilder = new ResolutionSelector.Builder();
- resolutionBuilder.SetAllowedResolutionMode(ResolutionSelector.PreferHigherResolutionOverCaptureRate);
- resolutionBuilder.SetResolutionStrategy(analysisStrategy);
- resolutionBuilder.SetAspectRatioStrategy(AspectRatioStrategy.Ratio169FallbackAutoStrategy);
- var selector = resolutionBuilder.Build();
- if (_cameraController is not null)
- {
- _cameraController.ImageAnalysisResolutionSelector = selector;
- _cameraController.PreviewResolutionSelector = selector;
- }
- }
- internal void UpdateSymbologies()
- {
- _barcodeAnalyzer?.UpdateSymbologies();
- }
- internal void UpdateTapToFocus()
- {
- if (_cameraController is not null)
- _cameraController.TapToFocusEnabled = _cameraView?.TapToFocusEnabled ?? false;
- }
- internal void UpdateTorch()
- {
- _cameraController?.EnableTorch(_cameraView?.TorchOn ?? false);
- }
- internal void UpdateVibration()
- {
- // if ((_cameraView?.VibrationOnDetected ?? false) &&
- // !Permissions.IsDeclaredInManifest(Manifest.Permission.Vibrate))
- // _cameraView.VibrationOnDetected = false;
- }
- internal void UpdateZoomFactor()
- {
- if (_cameraView is not null && (_cameraController?.ZoomState?.IsInitialized ?? false))
- {
- var factor = _cameraView.RequestZoomFactor;
- if (factor > 0)
- {
- factor = Math.Max(factor, _cameraView.MinZoomFactor);
- factor = Math.Min(factor, _cameraView.MaxZoomFactor);
- if (factor != _cameraView.CurrentZoomFactor)
- _cameraController.SetZoomRatio(factor);
- }
- }
- }
- internal CoordinateTransform? GetCoordinateTransform(IImageProxy proxy)
- {
- var imageOutputTransform = new ImageProxyTransformFactory().GetOutputTransform(proxy);
- var previewOutputTransform = Dispatcher.UIThread.InvokeAsync(() => _previewView?.OutputTransform).GetAwaiter().GetResult();
- if (imageOutputTransform is not null && previewOutputTransform is not null)
- return new CoordinateTransform(imageOutputTransform, previewOutputTransform);
- else
- return null;
- }
- private async void MainDisplayInfoChangedAsync(object? sender, DisplayInfoChangedEventArgs e)
- {
- if (OpenedCameraState?.GetType() == CameraState.Type.Open)
- {
- if (_previewView is not null)
- _previewView.Controller = null;
- await Task.Delay(100);
- if (_previewView is not null)
- _previewView.Controller = _cameraController;
- }
- }
-
- public void Dispose()
- {
- Dispose(true);
- GC.SuppressFinalize(this);
- }
- protected virtual void Dispose(bool disposing)
- {
- if (disposing)
- {
- Stop();
- DeviceDisplay.Current.MainDisplayInfoChanged -= MainDisplayInfoChangedAsync;
-
- if (_cameraStateObserver is not null)
- {
- _cameraController?.ZoomState.RemoveObserver(_cameraStateObserver);
- _currentCameraInfo?.CameraState.RemoveObserver(_cameraStateObserver);
- }
- _cameraController?.ClearImageAnalysisAnalyzer();
- _barcodeView?.RemoveAllViews();
- _relativeLayout?.RemoveAllViews();
-
- _barcodeView?.Dispose();
- _relativeLayout?.Dispose();
- _imageView?.Dispose();
- _previewView?.Dispose();
- _cameraController?.Dispose();
- _currentCameraInfo?.Dispose();
- _cameraStateObserver?.Dispose();
- _barcodeAnalyzer?.Dispose();
- _analyzerExecutor?.Dispose();
- }
- }
- }
|