Skip to content
Snippets Groups Projects
Commit 3e6ba2a8 authored by Vitaliy Vashchenko's avatar Vitaliy Vashchenko
Browse files

Merge branch 'feature-qr-code-ios' into feature-qr-code-android

parents bfa9a399 c5bbcaeb
Branches
No related merge requests found
......@@ -188,16 +188,15 @@ public class UserMenu extends AbstractMenu {
final UserMenuQrCodeSelectBoxItemGroup qrCodeSync = new UserMenuQrCodeSelectBoxItemGroup() {
@Override
public void performAction() {
//Close if qr code scanner is active
if(Tablexia.getQRCodeScanner().isCameraPreviewActive()) return;
//TODO Draw the magnifier and open the camera
//showSyncQrDialog() //probably ?
Tablexia.getQRCodeScanner().setQRCodeListener(new QRCodeScanner.QRCodeListener() {
@Override
public void onCodeScanned(String data) {
public void onCodeScanned(final String data) {
Tablexia.getQRCodeScanner().disableScanning();
Tablexia.getQRCodeScanner().stopCameraPreview();
Tablexia.getQRCodeScanner().removeQRCodeListener();
Pattern pattern = Pattern.compile(CODE_REGEX);
Matcher matcher = pattern.matcher(data);
......@@ -205,6 +204,9 @@ public class UserMenu extends AbstractMenu {
String uuid = matcher.group(1);
runSyncWork(uuid);
}
Tablexia.getQRCodeScanner().stopCameraPreview();
Tablexia.getQRCodeScanner().removeQRCodeListener();
}
});
......
package cz.nic.tablexia.util.ui;
import com.badlogic.gdx.Gdx;
import cz.nic.tablexia.util.Log;
/**
* Created by drahomir on 10/5/16.
*/
......@@ -10,6 +14,7 @@ public abstract class QRCodeScanner {
private QRCodeListener listener;
private boolean scanningEnabled = false;
private boolean cameraPreviewActive = false;
public void enableScanning() {
scanningEnabled = true;
......@@ -23,6 +28,10 @@ public abstract class QRCodeScanner {
return scanningEnabled;
}
public boolean isCameraPreviewActive() {
return cameraPreviewActive;
}
public void setQRCodeListener(QRCodeListener listener) {
this.listener = listener;
}
......@@ -31,15 +40,44 @@ public abstract class QRCodeScanner {
this.listener = null;
}
public synchronized void onCodeScanned(String data) {
public synchronized void onCodeScanned(final String data) {
if(!isScanningEnabled()) return;
if(listener != null) {
listener.onCodeScanned(data);
Gdx.app.postRunnable(new Runnable() {
@Override
public void run() { listener.onCodeScanned(data); }
});
}
}
public void startCameraPreview() {
if(isCameraPreviewActive()) {
Log.info(getClass(), "Camera preview is already active. Cannot start it again!");
return;
}
Log.info(getClass(), "Starting Camera Preview!");
cameraPreviewActive = true;
onCameraPreviewStarted();
}
public void stopCameraPreview() {
if(!isCameraPreviewActive()) {
Log.info(getClass(), "Camera preview is not running. Cannot stop it!");
return;
}
Log.info(getClass(), "Stopping Camera Preview");
onCameraPreviewStopped();
cameraPreviewActive = false;
}
/* ABSTRACT METHODS */
public abstract boolean isCameraAccessible();
public abstract void startCameraPreview();
public abstract void stopCameraPreview();
public abstract void onCameraPreviewStarted();
public abstract void onCameraPreviewStopped();
}
......@@ -13,22 +13,25 @@ import org.robovm.apple.avfoundation.AVCaptureOutput;
import org.robovm.apple.avfoundation.AVCaptureSession;
import org.robovm.apple.avfoundation.AVCaptureVideoOrientation;
import org.robovm.apple.avfoundation.AVCaptureVideoPreviewLayer;
import org.robovm.apple.avfoundation.AVLayerVideoGravity;
import org.robovm.apple.avfoundation.AVMediaType;
import org.robovm.apple.avfoundation.AVMetadataObject;
import org.robovm.apple.avfoundation.AVMetadataObjectType;
import org.robovm.apple.dispatch.DispatchQueue;
import org.robovm.apple.dispatch.DispatchQueueAttr;
import org.robovm.apple.foundation.NSArray;
import org.robovm.apple.foundation.NSErrorException;
import org.robovm.apple.uikit.UIApplication;
import org.robovm.apple.uikit.UIInterfaceOrientation;
import org.robovm.apple.uikit.UIView;
import org.robovm.apple.uikit.UIViewController;
import java.util.Arrays;
import cz.nic.tablexia.util.ui.QRCodeScanner;
/**
* Created by drahomir on 10/5/16.
*/
public class IOSQRCodeScanner extends QRCodeScanner {
private static final String DISPATCH_QUEUE_NAME = "qrCodeQueue";
private class CaptureMetadataOutputDelegate extends AVCaptureMetadataOutputObjectsDelegateAdapter{
private IOSQRCodeScanner qrCodeScanner;
......@@ -39,14 +42,14 @@ public class IOSQRCodeScanner extends QRCodeScanner {
@Override
public void didOutputMetadataObjects(AVCaptureOutput captureOutput, NSArray<AVMetadataObject> metadataObjects, AVCaptureConnection connection) {
if(!isScanningEnabled()) return;
if(metadataObjects != null && metadataObjects.size() > 0) {
AVMetadataObject data = metadataObjects.get(0);
if(data.getType() == AVMetadataObjectType.QRCode) {
//Found QR Code TODO - change data.toString()
qrCodeScanner.onCodeScanned(data.toString());
}
metadataObjects.dispose();
}
}
}
......@@ -59,13 +62,12 @@ public class IOSQRCodeScanner extends QRCodeScanner {
private CaptureMetadataOutputDelegate captureDelegate;
private UIViewController cameraPreviewViewController;
private UIView cameraPreviewView;
private AVCaptureVideoPreviewLayer videoPreviewLayer;
private DispatchQueue dispatchQueue;
private boolean cameraPreviewRunning = false;
private void initializeCameraDevice() {
if(cameraDevice != null) return;
......@@ -86,12 +88,22 @@ public class IOSQRCodeScanner extends QRCodeScanner {
return cameraDevice != null;
}
@Override
public void startCameraPreview() {
if(cameraPreviewRunning) return;
private AVCaptureVideoOrientation getOrientationForCameraPreviewLayer() {
switch (UIApplication.getSharedApplication().getStatusBarOrientation()) {
case LandscapeLeft: return AVCaptureVideoOrientation.LandscapeLeft;
case LandscapeRight: return AVCaptureVideoOrientation.LandscapeRight;
case Portrait: return AVCaptureVideoOrientation.Portrait;
case PortraitUpsideDown: return AVCaptureVideoOrientation.PortraitUpsideDown;
default: return AVCaptureVideoOrientation.LandscapeLeft;
}
}
cameraPreviewRunning = true;
private void updateViewPreviewLayerOrientation() {
if(videoPreviewLayer != null ) videoPreviewLayer.getConnection().setVideoOrientation(getOrientationForCameraPreviewLayer());
}
@Override
public void onCameraPreviewStarted() {
captureSession = new AVCaptureSession();
initializeCameraDevice();
......@@ -104,8 +116,9 @@ public class IOSQRCodeScanner extends QRCodeScanner {
e.printStackTrace();
}
dispatchQueue = DispatchQueue.create(DISPATCH_QUEUE_NAME, DispatchQueueAttr.Serial());
captureMetadataOutput = new AVCaptureMetadataOutput();
dispatchQueue = DispatchQueue.getMainQueue();
captureDelegate = new CaptureMetadataOutputDelegate();
captureMetadataOutput.setMetadataObjectsDelegate(captureDelegate, dispatchQueue);
......@@ -114,61 +127,73 @@ public class IOSQRCodeScanner extends QRCodeScanner {
IOSApplication iosApplication = (IOSApplication) Gdx.app;
cameraPreviewViewController = new UIViewController() {
@Override
public void viewWillLayoutSubviews() {
super.viewWillLayoutSubviews();
updateViewPreviewLayerOrientation();
}
@Override
public void willAnimateRotation(UIInterfaceOrientation uiInterfaceOrientation, double v) {
//Unforunately this method is deprecated and there isnt binding in RoboVM for these replacements...
// - willTransitionToTraitCollection:withTransitionCoordinator:
// - viewWillTransitionToSize:withTransitionCoordinator:
super.willAnimateRotation(uiInterfaceOrientation, v);
updateViewPreviewLayerOrientation();
}
};
cameraPreviewView = new UIView();
cameraPreviewView.setBounds(iosApplication.getUIViewController().getView().getBounds());
cameraPreviewView.setCenter(iosApplication.getUIViewController().getView().getCenter());
cameraPreviewViewController.setView(cameraPreviewView);
videoPreviewLayer = new AVCaptureVideoPreviewLayer(captureSession);
//TODO - Change orientation on device rotate
videoPreviewLayer.getConnection().setVideoOrientation(AVCaptureVideoOrientation.LandscapeLeft);
videoPreviewLayer.setVideoGravity(AVLayerVideoGravity.ResizeAspectFill);
videoPreviewLayer.getConnection().setVideoOrientation(getOrientationForCameraPreviewLayer());
videoPreviewLayer.setFrame(cameraPreviewView.getBounds());
//Prevents java objects to get GCed unless captureSession ObjC object gets deallocated!
cameraDevice.addStrongRef(captureDeviceInput);
captureDeviceInput.addStrongRef(captureDelegate);
captureMetadataOutput.addStrongRef(captureDelegate);
captureDelegate.addStrongRef(captureSession);
videoPreviewLayer.addStrongRef(captureSession);
cameraPreviewView.getLayer().addSublayer(videoPreviewLayer);
iosApplication.getUIViewController().addChildViewController(cameraPreviewViewController);
iosApplication.getUIViewController().getView().addSubview(cameraPreviewView);
if(!captureSession.isRunning()) captureSession.startRunning();
}
@Override
public void stopCameraPreview() {
if(!cameraPreviewRunning) return;
cameraPreviewRunning = false;
public void onCameraPreviewStopped() {
captureSession.stopRunning();
captureSession.removeInput(captureDeviceInput);
captureSession.removeOutput(captureMetadataOutput);
captureDeviceInput.removeStrongRef(captureDelegate);
captureDeviceInput.release();
captureDeviceInput.dispose();
captureDeviceInput = null;
captureMetadataOutput.removeStrongRef(captureDelegate);
captureMetadataOutput.release();
captureMetadataOutput.dispose();
captureMetadataOutput = null;
captureDelegate.removeStrongRef(captureSession);
captureDelegate.release();
captureDelegate.dispose();
captureDelegate = null;
videoPreviewLayer.removeStrongRef(captureSession);
videoPreviewLayer.removeFromSuperlayer();
videoPreviewLayer.dispose();
videoPreviewLayer = null;
cameraPreviewViewController.removeFromParentViewController();
cameraPreviewViewController.dispose();
cameraPreviewViewController = null;
cameraPreviewView.removeFromSuperview();
cameraPreviewView.release();
cameraPreviewView.dispose();
cameraPreviewView = null;
captureSession.release();
captureSession.dispose();
captureSession = null;
dispatchQueue = null;
}
}
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment