public Task <MobileResult> Scan(Context context, MobileBarcodeScanningOptions options)
        {
            var ctx = GetContext(context);

            var task = Task.Factory.StartNew(() => {
                var waitScanResetEvent = new System.Threading.ManualResetEvent(false);

                var scanIntent = new Intent(ctx, typeof(ZxingActivity));

                scanIntent.AddFlags(ActivityFlags.NewTask);

                ZxingActivity.UseCustomOverlayView = this.UseCustomOverlay;
                ZxingActivity.CustomOverlayView    = this.CustomOverlay;
                ZxingActivity.ScanningOptions      = options;
                ZxingActivity.ScanContinuously     = false;
                ZxingActivity.TopText    = TopText;
                ZxingActivity.BottomText = BottomText;

                MobileResult scanResult = null;

                ZxingActivity.CanceledHandler = () =>
                {
                    waitScanResetEvent.Set();
                };

                ZxingActivity.ScanCompletedHandler = (MobileResult result) =>
                {
                    scanResult = result;
                    waitScanResetEvent.Set();
                };

                ctx.StartActivity(scanIntent);

                waitScanResetEvent.WaitOne();

                return(scanResult);
            });

            return(task);
        }
        bool SetupCaptureSession()
        {
            var availableResolutions = new List <CameraResolution> ();

            var consideredResolutions = new Dictionary <NSString, CameraResolution> {
                { AVCaptureSession.Preset352x288, new CameraResolution   {
                      Width = 352, Height = 288
                  } },
                { AVCaptureSession.PresetMedium, new CameraResolution    {
                      Width = 480, Height = 360
                  } },                                                                                      //480x360
                { AVCaptureSession.Preset640x480, new CameraResolution   {
                      Width = 640, Height = 480
                  } },
                { AVCaptureSession.Preset1280x720, new CameraResolution  {
                      Width = 1280, Height = 720
                  } },
                { AVCaptureSession.Preset1920x1080, new CameraResolution {
                      Width = 1920, Height = 1080
                  } }
            };

            // configure the capture session for low resolution, change this if your code
            // can cope with more data or volume
            session = new AVCaptureSession()
            {
                SessionPreset = AVCaptureSession.Preset640x480
            };

            // create a device input and attach it to the session
//			var captureDevice = AVCaptureDevice.DefaultDeviceWithMediaType (AVMediaType.Video);
            AVCaptureDevice captureDevice = null;
            var             devices       = AVCaptureDevice.DevicesWithMediaType(AVMediaType.Video);

            foreach (var device in devices)
            {
                captureDevice = device;
                if (ScanningOptions.UseFrontCameraIfAvailable.HasValue &&
                    ScanningOptions.UseFrontCameraIfAvailable.Value &&
                    device.Position == AVCaptureDevicePosition.Front)
                {
                    break;                     //Front camera successfully set
                }
                else if (device.Position == AVCaptureDevicePosition.Back && (!ScanningOptions.UseFrontCameraIfAvailable.HasValue || !ScanningOptions.UseFrontCameraIfAvailable.Value))
                {
                    break;                     //Back camera succesfully set
                }
            }
            if (captureDevice == null)
            {
                Console.WriteLine("No captureDevice - this won't work on the simulator, try a physical device");
                if (overlayView != null)
                {
                    this.AddSubview(overlayView);
                    this.BringSubviewToFront(overlayView);
                }
                return(false);
            }

            CameraResolution resolution = null;

            // Find resolution
            // Go through the resolutions we can even consider
            foreach (var cr in consideredResolutions)
            {
                // Now check to make sure our selected device supports the resolution
                // so we can add it to the list to pick from
                if (captureDevice.SupportsAVCaptureSessionPreset(cr.Key))
                {
                    availableResolutions.Add(cr.Value);
                }
            }

            resolution = ScanningOptions.GetResolution(availableResolutions);

            // See if the user selected a resolution
            if (resolution != null)
            {
                // Now get the preset string from the resolution chosen
                var preset = (from c in consideredResolutions
                              where c.Value.Width == resolution.Width &&
                              c.Value.Height == resolution.Height
                              select c.Key).FirstOrDefault();

                // If we found a matching preset, let's set it on the session
                if (!string.IsNullOrEmpty(preset))
                {
                    session.SessionPreset = preset;
                }
            }

            var input = AVCaptureDeviceInput.FromDevice(captureDevice);

            if (input == null)
            {
                Console.WriteLine("No input - this won't work on the simulator, try a physical device");
                if (overlayView != null)
                {
                    this.AddSubview(overlayView);
                    this.BringSubviewToFront(overlayView);
                }
                return(false);
            }
            else
            {
                session.AddInput(input);
            }


            foundResult = false;
            //Detect barcodes with built in avcapture stuff
            AVCaptureMetadataOutput metadataOutput = new AVCaptureMetadataOutput();

            captureDelegate = new CaptureDelegate(metaDataObjects =>
            {
                if (!analyzing)
                {
                    return;
                }

                //Console.WriteLine("Found MetaData Objects");

                var msSinceLastPreview = (DateTime.UtcNow - lastAnalysis).TotalMilliseconds;

                if (msSinceLastPreview < ScanningOptions.DelayBetweenAnalyzingFrames ||
                    (wasScanned && msSinceLastPreview < ScanningOptions.DelayBetweenContinuousScans) ||
                    working)
                //|| CancelTokenSource.IsCancellationRequested)
                {
                    return;
                }

                try {
                    working      = true;
                    wasScanned   = false;
                    lastAnalysis = DateTime.UtcNow;

                    var mdo = metaDataObjects.FirstOrDefault();

                    var readableObj = mdo as AVMetadataMachineReadableCodeObject;

                    if (readableObj == null)
                    {
                        return;
                    }

                    wasScanned = true;

                    var zxingFormat = ZXingBarcodeFormatFromAVCaptureBarcodeFormat(readableObj.Type.ToString());

                    var rs = new ZXing.Result(readableObj.StringValue, null, null, zxingFormat);
                    var resultWithSource = new MobileResult(rs, null);
                    resultCallback(resultWithSource);
                } finally {
                    working = false;
                }
            });

            metadataOutput.SetDelegate(captureDelegate, DispatchQueue.MainQueue);
            session.AddOutput(metadataOutput);

            //Setup barcode formats
            if (ScanningOptions.PossibleFormats != null && ScanningOptions.PossibleFormats.Count > 0)
            {
                #if __UNIFIED__
                var formats = AVMetadataObjectType.None;

                foreach (var f in ScanningOptions.PossibleFormats)
                {
                    formats |= AVCaptureBarcodeFormatFromZXingBarcodeFormat(f);
                }

                formats &= ~AVMetadataObjectType.None;

                metadataOutput.MetadataObjectTypes = formats;
                #else
                var formats = new List <string> ();

                foreach (var f in ScanningOptions.PossibleFormats)
                {
                    formats.AddRange(AVCaptureBarcodeFormatFromZXingBarcodeFormat(f));
                }

                metadataOutput.MetadataObjectTypes = (from f in formats.Distinct() select new NSString(f)).ToArray();
                #endif
            }
            else
            {
                metadataOutput.MetadataObjectTypes = metadataOutput.AvailableMetadataObjectTypes;
            }



            previewLayer = new AVCaptureVideoPreviewLayer(session);

            // //Framerate set here (15 fps)
            //          if (previewLayer.RespondsToSelector(new Selector("connection")))
            //          {
            //  if (UIDevice.CurrentDevice.CheckSystemVersion (7, 0))
            //  {
            //      var perf1 = PerformanceCounter.Start ();

            //      NSError lockForConfigErr = null;

            //      captureDevice.LockForConfiguration (out lockForConfigErr);
            //      if (lockForConfigErr == null)
            //      {
            //          captureDevice.ActiveVideoMinFrameDuration = new CMTime (1, 10);
            //          captureDevice.UnlockForConfiguration ();
            //      }

            //      PerformanceCounter.Stop (perf1, "PERF: ActiveVideoMinFrameDuration Took {0} ms");
            //  }
            //              else
            //                  previewLayer.Connection.VideoMinFrameDuration = new CMTime(1, 10);
            //          }

                        #if __UNIFIED__
            previewLayer.VideoGravity = AVLayerVideoGravity.ResizeAspectFill;
                        #else
            previewLayer.LayerVideoGravity = AVLayerVideoGravity.ResizeAspectFill;
                        #endif
            previewLayer.Frame    = new CGRect(0, 0, this.Frame.Width, this.Frame.Height);
            previewLayer.Position = new CGPoint(this.Layer.Bounds.Width / 2, (this.Layer.Bounds.Height / 2));

            layerView = new UIView(new CGRect(0, 0, this.Frame.Width, this.Frame.Height));
            layerView.AutoresizingMask = UIViewAutoresizing.FlexibleWidth | UIViewAutoresizing.FlexibleHeight;
            layerView.Layer.AddSublayer(previewLayer);

            this.AddSubview(layerView);

            ResizePreview(UIApplication.SharedApplication.StatusBarOrientation);

            if (overlayView != null)
            {
                this.AddSubview(overlayView);
                this.BringSubviewToFront(overlayView);

                //overlayView.LayoutSubviews ();
            }

            session.StartRunning();

            Console.WriteLine("RUNNING!!!");



            //output.AlwaysDiscardsLateVideoFrames = true;


            Console.WriteLine("SetupCamera Finished");

            //session.AddOutput (output);
            //session.StartRunning ();


            if (captureDevice.IsFocusModeSupported(AVCaptureFocusMode.ContinuousAutoFocus))
            {
                NSError err = null;
                if (captureDevice.LockForConfiguration(out err))
                {
                    if (captureDevice.IsFocusModeSupported(AVCaptureFocusMode.ContinuousAutoFocus))
                    {
                        captureDevice.FocusMode = AVCaptureFocusMode.ContinuousAutoFocus;
                    }
                    else if (captureDevice.IsFocusModeSupported(AVCaptureFocusMode.AutoFocus))
                    {
                        captureDevice.FocusMode = AVCaptureFocusMode.AutoFocus;
                    }

                    if (captureDevice.IsExposureModeSupported(AVCaptureExposureMode.ContinuousAutoExposure))
                    {
                        captureDevice.ExposureMode = AVCaptureExposureMode.ContinuousAutoExposure;
                    }
                    else if (captureDevice.IsExposureModeSupported(AVCaptureExposureMode.AutoExpose))
                    {
                        captureDevice.ExposureMode = AVCaptureExposureMode.AutoExpose;
                    }

                    if (captureDevice.IsWhiteBalanceModeSupported(AVCaptureWhiteBalanceMode.ContinuousAutoWhiteBalance))
                    {
                        captureDevice.WhiteBalanceMode = AVCaptureWhiteBalanceMode.ContinuousAutoWhiteBalance;
                    }
                    else if (captureDevice.IsWhiteBalanceModeSupported(AVCaptureWhiteBalanceMode.AutoWhiteBalance))
                    {
                        captureDevice.WhiteBalanceMode = AVCaptureWhiteBalanceMode.AutoWhiteBalance;
                    }

                    if (UIDevice.CurrentDevice.CheckSystemVersion(7, 0) && captureDevice.AutoFocusRangeRestrictionSupported)
                    {
                        captureDevice.AutoFocusRangeRestriction = AVCaptureAutoFocusRangeRestriction.Near;
                    }

                    if (captureDevice.FocusPointOfInterestSupported)
                    {
                        captureDevice.FocusPointOfInterest = new CGPoint(0.5f, 0.5f);
                    }

                    if (captureDevice.ExposurePointOfInterestSupported)
                    {
                        captureDevice.ExposurePointOfInterest = new CGPoint(0.5f, 0.5f);
                    }

                    captureDevice.UnlockForConfiguration();
                }
                else
                {
                    Console.WriteLine("Failed to Lock for Config: " + err.Description);
                }
            }

            return(true);
        }
        public async Task StartScanningAsync(Action <MobileResult> scanCallback, MobileBarcodeScanningOptions options = null)
        {
            if (stopping)
            {
                return;
            }

            displayRequest.RequestActive();

            isAnalyzing     = true;
            ScanCallback    = scanCallback;
            ScanningOptions = options ?? MobileBarcodeScanningOptions.Default;

            topText.Text    = TopText ?? string.Empty;
            bottomText.Text = BottomText ?? string.Empty;

            if (UseCustomOverlay)
            {
                gridCustomOverlay.Children.Clear();
                if (CustomOverlay != null)
                {
                    gridCustomOverlay.Children.Add(CustomOverlay);
                }

                gridCustomOverlay.Visibility  = Visibility.Visible;
                gridDefaultOverlay.Visibility = Visibility.Collapsed;
            }
            else
            {
                gridCustomOverlay.Visibility  = Visibility.Collapsed;
                gridDefaultOverlay.Visibility = Visibility.Visible;
            }

            // Find which device to use
            var preferredCamera = await GetFilteredCameraOrDefaultAsync(ScanningOptions);

            if (preferredCamera == null)
            {
                System.Diagnostics.Debug.WriteLine("No camera available");
                isMediaCaptureInitialized = false;
                return;
            }

            if (preferredCamera.EnclosureLocation == null || preferredCamera.EnclosureLocation.Panel == Windows.Devices.Enumeration.Panel.Unknown)
            {
                // No information on the location of the camera, assume it's an external camera, not integrated on the device.
                externalCamera = true;
            }
            else
            {
                // Camera is fixed on the device.
                externalCamera = false;

                // Only mirror the preview if the camera is on the front panel.
                mirroringPreview = preferredCamera.EnclosureLocation.Panel == Windows.Devices.Enumeration.Panel.Front;
            }

            mediaCapture = new MediaCapture();

            // Initialize the capture with the settings above
            try
            {
                await mediaCapture.InitializeAsync(new MediaCaptureInitializationSettings
                {
                    StreamingCaptureMode = StreamingCaptureMode.Video,
                    VideoDeviceId        = preferredCamera.Id
                });

                isMediaCaptureInitialized = true;
            }
            catch (UnauthorizedAccessException)
            {
                System.Diagnostics.Debug.WriteLine("Denied access to the camera");
            }
            catch (Exception ex)
            {
                System.Diagnostics.Debug.WriteLine("Exception when init MediaCapture: {0}", ex);
            }

            if (!isMediaCaptureInitialized)
            {
                return;
            }

            // Set the capture element's source to show it in the UI
            captureElement.Source        = mediaCapture;
            captureElement.FlowDirection = mirroringPreview ? FlowDirection.RightToLeft : FlowDirection.LeftToRight;

            // Start the preview
            await mediaCapture.StartPreviewAsync();

            // Get all the available resolutions for preview
            var availableProperties  = mediaCapture.VideoDeviceController.GetAvailableMediaStreamProperties(MediaStreamType.VideoPreview);
            var availableResolutions = new List <CameraResolution>();

            foreach (var ap in availableProperties)
            {
                var vp = (VideoEncodingProperties)ap;
                System.Diagnostics.Debug.WriteLine("Camera Preview Resolution: {0}x{1}", vp.Width, vp.Height);
                availableResolutions.Add(new CameraResolution {
                    Width = (int)vp.Width, Height = (int)vp.Height
                });
            }
            CameraResolution previewResolution = null;

            if (ScanningOptions.CameraResolutionSelector != null)
            {
                previewResolution = ScanningOptions.CameraResolutionSelector(availableResolutions);
            }

            // If the user did not specify a resolution, let's try and find a suitable one
            if (previewResolution == null)
            {
                // Loop through all supported sizes
                foreach (var sps in availableResolutions)
                {
                    // Find one that's >= 640x360 but <= 1000x1000
                    // This will likely pick the *smallest* size in that range, which should be fine
                    if (sps.Width >= 640 && sps.Width <= 1000 && sps.Height >= 360 && sps.Height <= 1000)
                    {
                        previewResolution = new CameraResolution
                        {
                            Width  = sps.Width,
                            Height = sps.Height
                        };
                        break;
                    }
                }
            }

            if (previewResolution == null)
            {
                previewResolution = availableResolutions.LastOrDefault();
            }

            if (previewResolution == null)
            {
                System.Diagnostics.Debug.WriteLine("No preview resolution available. Camera may be in use by another application.");
                return;
            }

            MobileBarcodeScanner.Log("Using Preview Resolution: {0}x{1}", previewResolution.Width, previewResolution.Height);

            // Find the matching property based on the selection, again
            var chosenProp = availableProperties.FirstOrDefault(ap => ((VideoEncodingProperties)ap).Width == previewResolution.Width && ((VideoEncodingProperties)ap).Height == previewResolution.Height);

            // Pass in the requested preview size properties
            // so we can set them at the same time as the preview rotation
            // to save an additional set property call
            await SetPreviewRotationAsync(chosenProp);

            // *after* the preview is setup, set this so that the UI layout happens
            // otherwise the preview gets stuck in a funny place on screen
            captureElement.Stretch = Stretch.UniformToFill;

            await SetupAutoFocus();

            var zxing = ScanningOptions.BuildBarcodeReader();

            timerPreview = new Timer(async(state) => {
                var delay = ScanningOptions.DelayBetweenAnalyzingFrames;

                if (stopping || processing || !isAnalyzing ||
                    (mediaCapture == null || mediaCapture.CameraStreamState != Windows.Media.Devices.CameraStreamState.Streaming))
                {
                    timerPreview.Change(delay, Timeout.Infinite);
                    return;
                }

                processing = true;

                SoftwareBitmapLuminanceSource luminanceSource = null;

                try
                {
                    // Get preview
                    var frame = await mediaCapture.GetPreviewFrameAsync(videoFrame);

                    // Create our luminance source
                    luminanceSource = new SoftwareBitmapLuminanceSource(frame.SoftwareBitmap);
                } catch (Exception ex)
                {
                    MobileBarcodeScanner.Log("GetPreviewFrame Failed: {0}", ex);
                }

                ZXing.Result result = null;

                try
                {
                    // Try decoding the image
                    if (luminanceSource != null)
                    {
                        result = zxing.Decode(luminanceSource);
                    }
                }
                catch (Exception ex)
                {
                    MobileBarcodeScanner.Log("Warning: zxing.Decode Failed: {0}", ex);
                }

                // Check if a result was found
                if (result != null && !string.IsNullOrEmpty(result.Text))
                {
                    if (!ContinuousScanning)
                    {
                        delay = Timeout.Infinite;
                        await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, async() => { await StopScanningAsync(); });
                    }
                    else
                    {
                        delay = ScanningOptions.DelayBetweenContinuousScans;
                    }

                    LastScanResult = new MobileResult(result);
                    ScanCallback(LastScanResult);
                }

                processing = false;

                timerPreview.Change(delay, Timeout.Infinite);
            }, null, ScanningOptions.InitialDelayBeforeAnalyzingFrames, Timeout.Infinite);
        }
        public Task <MobileResult> Scan(MobileBarcodeScanningOptions options, bool useAVCaptureEngine)
        {
            return(Task.Factory.StartNew(() => {
                try
                {
                    scanResultResetEvent.Reset();

                    MobileResult result = null;

                    Version sv = new Version(0, 0, 0);
                    Version.TryParse(UIDevice.CurrentDevice.SystemVersion, out sv);

                    var is7orgreater = sv.Major >= 7;
                    var allRequestedFormatsSupported = true;

                    if (useAVCaptureEngine)
                    {
                        allRequestedFormatsSupported = AVCaptureScannerView.SupportsAllRequestedBarcodeFormats(options.PossibleFormats);
                    }

                    this.appController.InvokeOnMainThread(() => {
                        if (useAVCaptureEngine && is7orgreater && allRequestedFormatsSupported)
                        {
                            viewController = new AVCaptureScannerViewController(options, this);
                        }
                        else
                        {
                            if (useAVCaptureEngine && !is7orgreater)
                            {
                                Console.WriteLine("Not iOS 7 or greater, cannot use AVCapture for barcode decoding, using ZXing instead");
                            }
                            else if (useAVCaptureEngine && !allRequestedFormatsSupported)
                            {
                                Console.WriteLine("Not all requested barcode formats were supported by AVCapture, using ZXing instead");
                            }

                            viewController = new ZXing.Mobile.ZXingScannerViewController(options, this);
                        }

                        viewController.OnScannedResult += barcodeResult => {
                            ((UIViewController)viewController).InvokeOnMainThread(() => {
                                viewController.Cancel();

                                // Handle error situation that occurs when user manually closes scanner in the same moment that a QR code is detected
                                try {
                                    ((UIViewController)viewController).DismissViewController(true, () => {
                                        result = barcodeResult;
                                        scanResultResetEvent.Set();
                                    });
                                } catch (ObjectDisposedException) {
                                    // In all likelihood, iOS has decided to close the scanner at this point. But just in case it executes the
                                    // post-scan code instead, set the result so we will not get a NullReferenceException.
                                    result = barcodeResult;
                                    scanResultResetEvent.Set();
                                }
                            });
                        };

                        appController.PresentViewController((UIViewController)viewController, true, null);
                    });

                    scanResultResetEvent.WaitOne();
                    ((UIViewController)viewController).Dispose();

                    return result;
                }
                catch (Exception ex)
                {
                    Console.WriteLine(ex);
                    return null;
                }
            }));
        }