Skip to content
This repository has been archived by the owner on Feb 2, 2021. It is now read-only.

Commit

Permalink
Merge pull request #14 from rebuy-de/async_camera_open
Browse files Browse the repository at this point in the history
Async camera open
  • Loading branch information
omares committed Mar 24, 2015
2 parents 28458a4 + f71d13b commit 18db09d
Show file tree
Hide file tree
Showing 18 changed files with 271 additions and 198 deletions.
190 changes: 75 additions & 115 deletions Rb.Forms.Barcode.Droid/BarcodeScannerRenderer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,74 +5,96 @@

using Rb.Forms.Barcode.Pcl;
using Rb.Forms.Barcode.Pcl.Logger;
using Rb.Forms.Barcode.Pcl.Extensions;
using Rb.Forms.Barcode.Droid;
using Rb.Forms.Barcode.Droid.Camera;
using Rb.Forms.Barcode.Droid.Decoder;
using Rb.Forms.Barcode.Droid.Logger;

using Android.Views;
using System.Threading.Tasks;
using Rb.Forms.Barcode.Droid.View;

[assembly: ExportRenderer(typeof(BarcodeScanner), typeof(BarcodeScannerRenderer))]
namespace Rb.Forms.Barcode.Droid
{
public class BarcodeScannerRenderer : ViewRenderer<BarcodeScanner, SurfaceView>, ISurfaceHolderCallback, ILog
{
private readonly CameraControl cameraControl = CameraControl.Instance;
private readonly ScannerCamera scannerCamera = ScannerCamera.Instance;
private readonly BarcodeDecoder barcodeDecoder = new BarcodeDecoder();
private ViewStates currentVisibility;
private static bool reuseCamera;

private AutoFocusCallback autoFocus;
private PreviewFrameCallback previewFrameCallback;
private CameraService scannerService;

/// <summary>
/// Checks the surface for validity so its safe to work with it.
/// </summary>
/// <value><c>true</c> if this instance has valid surface; otherwise, <c>false</c>.</value>
private bool HasValidSurface {
get {
return Control.Holder.Surface.IsValid;
}
}

private ViewStates Visibility { get; set; }

/// <summary>
/// Indicates that the currently open camera should be reused to prevent unexpected camera shutdowns.
/// </summary>
/// <value><c>true</c> if keep camera; otherwise, <c>false</c>.</value>
private static bool KeepCamera { get; set; }

public static void Init()
{
}

public void SurfaceCreated(ISurfaceHolder holder)
public async void SurfaceCreated(ISurfaceHolder holder)
{
this.Debug("SurfaceCreated");

if (!Element.IsEnabled) {
return;
}

this.Debug("SurfaceCreated");
if (!HasValidSurface) {
return;
}

if (cameraControl.CameraOpen) {
BarcodeScannerRenderer.reuseCamera = true;
haltPreview();
if (scannerCamera.CameraOpen) {
BarcodeScannerRenderer.KeepCamera = true;
scannerService.HaltPreview();
}

openCamera();
await Task.Run(() => scannerService.OpenCamera(holder));
}

public void SurfaceChanged(ISurfaceHolder holder, global::Android.Graphics.Format format, int width, int height)
{
this.Debug("SurfaceChanged");

if (!Element.IsEnabled) {
return;
}

this.Debug("SurfaceChanged");
if (!scannerCamera.CameraOpen) {
return;
}

try {
if (currentVisibility != ViewStates.Gone) {
startPreview();
}
} catch (Exception ex) {
this.Debug("Unable to start preview.");
this.Debug(ex.ToString());
if (!HasValidSurface) {
return;
}

Element.PreviewActive = true;
}

public void SurfaceDestroyed(ISurfaceHolder holder)
{
this.Debug("SurfaceDestroyed");

if (!BarcodeScannerRenderer.reuseCamera) {
haltPreview();
releaseCamera();
if (BarcodeScannerRenderer.KeepCamera) {
return;
}

Element.IsEnabled = false;
}

protected override void OnElementChanged(ElementChangedEventArgs<BarcodeScanner> e)
Expand All @@ -81,17 +103,28 @@ protected override void OnElementChanged(ElementChangedEventArgs<BarcodeScanner>

base.OnElementChanged(e);

if (Control == null) {
var surfaceView = new SurfaceView(Context);
surfaceView.Holder.AddCallback(this);
SetNativeControl(surfaceView);

autoFocus = new AutoFocusCallback(cameraControl);
previewFrameCallback = new PreviewFrameCallback(barcodeDecoder, Element);
if (Control != null) {
return;
}

var surfaceView = new SurfaceView(Context);
surfaceView.Holder.AddCallback(this);
SetNativeControl(surfaceView);

scannerService = new CameraService(Element, scannerCamera);
previewFrameCallback = new PreviewFrameCallback(barcodeDecoder, Element);

Element.CameraOpened += (sender, args) => {
Element.BarcodeDecoder = true;
};

Element.CameraReleased += (sender, args) => {
Element.BarcodeDecoder = false;
BarcodeScannerRenderer.KeepCamera = false;
};
}

protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
protected async override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
{
base.OnElementPropertyChanged(sender, e);

Expand All @@ -101,14 +134,12 @@ protected override void OnElementPropertyChanged(object sender, PropertyChangedE
{
this.Debug("Enabled [{0}]", Element.IsEnabled);

if (Element.IsEnabled) {
openCamera();
startPreview();
if (Element.IsEnabled && HasValidSurface) {
await Task.Run(() => scannerService.OpenCamera(Control.Holder));
}

if (!Element.IsEnabled) {
haltPreview();
releaseCamera();
scannerService.ReleaseCamera();
}
}

Expand All @@ -117,11 +148,11 @@ protected override void OnElementPropertyChanged(object sender, PropertyChangedE
this.Debug("ScannerActive [{0}]", Element.PreviewActive);

if (Element.PreviewActive) {
startPreview();
await Task.Run(() => scannerService.StartPreview(previewFrameCallback));
}

if (!Element.PreviewActive) {
haltPreview();
scannerService.HaltPreview();
}
}

Expand All @@ -145,97 +176,26 @@ protected override void OnVisibilityChanged(global::Android.Views.View view, Vie

this.Debug("OnVisibilityChanged [{0}]", visibility.ToString());

if (currentVisibility == visibility) {
if (Visibility == visibility) {
return;
}

if (visibility == ViewStates.Visible) {
startPreview();
if (visibility == ViewStates.Gone && !BarcodeScannerRenderer.KeepCamera) {
Element.PreviewActive = false;
}

if (visibility == ViewStates.Gone && !BarcodeScannerRenderer.reuseCamera) {
haltPreview();
}

currentVisibility = visibility;
Visibility = visibility;
}

protected override void Dispose(bool disposing)
{
this.Debug("Disposing");

if (disposing) {
this.Debug("Disposing");
BarcodeScannerRenderer.reuseCamera = false;
BarcodeScannerRenderer.KeepCamera = false;
}

base.Dispose(disposing);
}

private void openCamera()
{
/**
* When switching apps the surface seems not to be valid.
* Simply do nothing and let the follow up event fix it.
*/
if (!Control.Holder.Surface.IsValid) {
return;
}

barcodeDecoder.RefreshToken();
Element.BarcodeDecoder = true;

try {
cameraControl.OpenCamera();
cameraControl.AssignPreview(Control.Holder);

Element.OnCameraOpened();
} catch (Exception ex) {
this.Debug("Unable to open camera");
this.Debug(ex.ToString());
}
}

private void releaseCamera()
{
try {
barcodeDecoder.CancelDecoding();
Element.BarcodeDecoder = false;

cameraControl.ReleaseCamera();
autoFocus.Enabled = false;

BarcodeScannerRenderer.reuseCamera = false;
Element.OnCameraReleased();
} catch (Exception ex) {
this.Debug("Unable to release camera");
this.Debug(ex.ToString());
}
}

private void startPreview()
{
/**
* When switching apps the surface seems not to be valid.
* Simply do nothing and let the follow up event fix it.
*/
if (!Control.Holder.Surface.IsValid) {
return;
}

cameraControl.StartPreview(previewFrameCallback);

if (cameraControl.AutoFocusMode) {
cameraControl.AutoFocus(autoFocus);
}

Element.PreviewActive = true;
}

private void haltPreview()
{
autoFocus.Enabled = false;
cameraControl.HaltPreview();

Element.PreviewActive = false;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,10 @@
#pragma warning disable 618
namespace Rb.Forms.Barcode.Droid.Camera
{
public class CameraControl : ILog
public class ScannerCamera : ILog
{
private AndroidCamera camera;
private bool previewState = false;
private static readonly CameraControl instance = new CameraControl();
private static readonly ScannerCamera instance = new ScannerCamera();
private readonly CameraConfigurator configurator = new CameraConfigurator();

public bool CameraOpen {
Expand All @@ -28,13 +27,13 @@ public bool AutoFocusMode {
}
}

static CameraControl()
static ScannerCamera()
{}

private CameraControl()
private ScannerCamera()
{}

public static CameraControl Instance
public static ScannerCamera Instance
{
get
{
Expand All @@ -59,7 +58,6 @@ public void AssignPreview(ISurfaceHolder holder)
this.Debug("AssignPreview");
try {
camera.SetPreviewDisplay(holder);
previewState = false;
} catch (Exception ex) {
this.Debug(ex.Message);
this.Debug(ex.StackTrace.ToString());
Expand All @@ -76,42 +74,30 @@ public void ReleaseCamera()

public void StartPreview(AndroidCamera.IPreviewCallback previewCallback)
{
if (previewState) {
return;
}

this.Debug("StartPreview");

camera.StopPreview();

configurator.Configure(camera);

camera.SetDisplayOrientation(90);
camera.SetPreviewCallback(previewCallback);

camera.CancelAutoFocus();
camera.StartPreview();

previewState = true;
}

public void HaltPreview()
{
if (!previewState) {
return;
}

this.Debug("HaltPreview");

camera.CancelAutoFocus();

camera.StopPreview();
camera.SetPreviewCallback(null);
previewState = false;
}

public void AutoFocus(AndroidCamera.IAutoFocusCallback previewCallback)
{
camera.CancelAutoFocus();

if (CameraOpen) {
camera.AutoFocus(previewCallback);
}
Expand Down
Loading

0 comments on commit 18db09d

Please sign in to comment.