diff --git a/android/ZBar.java b/android/ZBar.java
new file mode 100644
index 0000000..519fd60
--- /dev/null
+++ b/android/ZBar.java
@@ -0,0 +1,76 @@
+package org.cloudsky.cordovaPlugins;
+
+import org.apache.cordova.CordovaInterface;
+import org.apache.cordova.CordovaPlugin;
+import org.apache.cordova.CallbackContext;
+import org.apache.cordova.PluginResult;
+import org.json.JSONArray;
+import org.json.JSONException;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.content.Context;
+
+import org.cloudsky.cordovaPlugins.ZBarScannerActivity;
+
+public class ZBar extends CordovaPlugin {
+
+ // Configuration ---------------------------------------------------
+
+ private static int SCAN_CODE = 1;
+
+
+ // State -----------------------------------------------------------
+
+ private boolean isInProgress = false;
+ private CallbackContext scanCallbackContext;
+
+
+ // Plugin API ------------------------------------------------------
+
+ @Override
+ public boolean execute (String action, JSONArray args, CallbackContext callbackContext)
+ throws JSONException
+ {
+ if(action.equals("scan")) {
+ if(isInProgress) {
+ callbackContext.error("A scan is already in progress!");
+ } else {
+ isInProgress = true;
+ scanCallbackContext = callbackContext;
+ Context appCtx = cordova.getActivity().getApplicationContext();
+ Intent scanIntent = new Intent(appCtx, ZBarScannerActivity.class);
+ cordova.startActivityForResult(this, scanIntent, SCAN_CODE);
+ }
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+
+ // External results handler ----------------------------------------
+
+ @Override
+ public void onActivityResult (int requestCode, int resultCode, Intent result)
+ {
+ if(requestCode == SCAN_CODE) {
+ switch(resultCode) {
+ case Activity.RESULT_OK:
+ String barcodeValue = result.getStringExtra(ZBarScannerActivity.EXTRA_QRVALUE);
+ scanCallbackContext.success(barcodeValue);
+ break;
+ case Activity.RESULT_CANCELED:
+ scanCallbackContext.error("cancelled");
+ break;
+ case ZBarScannerActivity.RESULT_ERROR:
+ scanCallbackContext.error("Scan failed due to an error");
+ break;
+ default:
+ scanCallbackContext.error("Unknown error");
+ }
+ isInProgress = false;
+ scanCallbackContext = null;
+ }
+ }
+}
diff --git a/android/ZBarScannerActivity.java b/android/ZBarScannerActivity.java
new file mode 100644
index 0000000..a972d85
--- /dev/null
+++ b/android/ZBarScannerActivity.java
@@ -0,0 +1,295 @@
+package org.cloudsky.cordovaPlugins;
+
+import java.io.IOException;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.content.res.Resources;
+import android.hardware.Camera;
+import android.hardware.Camera.PreviewCallback;
+import android.hardware.Camera.AutoFocusCallback;
+import android.os.Bundle;
+import android.os.Handler;
+import android.view.Gravity;
+import android.view.SurfaceHolder;
+import android.view.SurfaceView;
+import android.view.ViewGroup;
+import android.widget.FrameLayout;
+import android.widget.Toast;
+
+import net.sourceforge.zbar.ImageScanner;
+import net.sourceforge.zbar.Image;
+import net.sourceforge.zbar.Symbol;
+import net.sourceforge.zbar.SymbolSet;
+import net.sourceforge.zbar.Config;
+
+public class ZBarScannerActivity extends Activity
+implements SurfaceHolder.Callback {
+
+ // Config ----------------------------------------------------------
+
+ private static int autoFocusInterval = 500; // Interval between AFcallback and next AF attempt.
+
+ // Public Constants ------------------------------------------------
+
+ public static final String EXTRA_QRVALUE = "qrValue";
+ public static final int RESULT_ERROR = RESULT_FIRST_USER + 1;
+
+ // State -----------------------------------------------------------
+
+ private Camera camera;
+ private Handler autoFocusHandler;
+ private SurfaceView scannerSurface;
+ private SurfaceHolder holder;
+ private ImageScanner scanner;
+ private int surfW, surfH;
+
+ // For retrieving R.* resources, from the actual app package
+ // (we can't use actual.application.package.R.* in our code as we
+ // don't know the applciation package name when writing this plugin).
+ private String package_name;
+ private Resources resources;
+
+ // Static initialisers (class) -------------------------------------
+
+ static {
+ // Needed by ZBar??
+ System.loadLibrary("iconv");
+ }
+
+ // Activity Lifecycle ----------------------------------------------
+
+ @Override
+ public void onCreate (Bundle savedInstanceState)
+ {
+ super.onCreate(savedInstanceState);
+
+ // Initiate instance variables
+ autoFocusHandler = new Handler();
+ scanner = new ImageScanner();
+ scanner.setConfig(0, Config.X_DENSITY, 3);
+ scanner.setConfig(0, Config.Y_DENSITY, 3);
+
+ // Set content view
+ setContentView(getResourceId("layout/cszbarscanner"));
+
+ // Create preview SurfaceView
+ scannerSurface = new SurfaceView (this) {
+ @Override
+ public void onSizeChanged (int w, int h, int oldW, int oldH) {
+ surfW = w;
+ surfH = h;
+ matchSurfaceToPreviewRatio();
+ }
+ };
+ scannerSurface.setLayoutParams(new FrameLayout.LayoutParams(
+ ViewGroup.LayoutParams.MATCH_PARENT,
+ ViewGroup.LayoutParams.MATCH_PARENT,
+ Gravity.CENTER
+ ));
+ scannerSurface.getHolder().addCallback(this);
+
+ // Add preview SurfaceView to the screen
+ ((FrameLayout) findViewById(getResourceId("id/csZbarScannerView"))).addView(scannerSurface);
+ findViewById(getResourceId("id/csZbarScannerTitle")).bringToFront();
+ findViewById(getResourceId("id/csZbarScannerInstructions")).bringToFront();
+ }
+
+ @Override
+ public void onResume ()
+ {
+ super.onResume();
+
+ try {
+ camera = Camera.open();
+ } catch (Exception e){
+ die("Error: Could not open the camera.");
+ return;
+ }
+
+ tryStartPreview();
+ }
+
+ @Override
+ public void onPause ()
+ {
+ releaseCamera();
+ super.onPause();
+ }
+
+ @Override
+ public void onDestroy ()
+ {
+ scanner.destroy();
+ super.onDestroy();
+ }
+
+ // Event handlers --------------------------------------------------
+
+ @Override
+ public void onBackPressed ()
+ {
+ setResult(RESULT_CANCELED);
+ super.onBackPressed();
+ }
+
+ // SurfaceHolder.Callback implementation ---------------------------
+
+ @Override
+ public void surfaceCreated (SurfaceHolder hld)
+ {
+ tryStopPreview();
+ holder = hld;
+ tryStartPreview();
+ }
+
+ @Override
+ public void surfaceDestroyed (SurfaceHolder holder)
+ {
+ // No surface == no preview == no point being in this Activity.
+ die("The camera surface was destroyed");
+ }
+
+ @Override
+ public void surfaceChanged (SurfaceHolder hld, int fmt, int w, int h)
+ {
+ // Sanity check - holder must have a surface...
+ if(hld.getSurface() == null) die("There is no camera surface");
+
+ surfW = w;
+ surfH = h;
+ matchSurfaceToPreviewRatio();
+
+ tryStopPreview();
+ holder = hld;
+ tryStartPreview();
+ }
+
+ // Continuously auto-focus -----------------------------------------
+
+ private AutoFocusCallback autoFocusCb = new AutoFocusCallback()
+ {
+ public void onAutoFocus(boolean success, Camera camera) {
+ autoFocusHandler.postDelayed(doAutoFocus, autoFocusInterval);
+ }
+ };
+
+ private Runnable doAutoFocus = new Runnable()
+ {
+ public void run() {
+ if(camera != null) camera.autoFocus(autoFocusCb);
+ }
+ };
+
+ // Camera callbacks ------------------------------------------------
+
+ // Receives frames from the camera and checks for barcodes.
+ private PreviewCallback previewCb = new PreviewCallback()
+ {
+ public void onPreviewFrame(byte[] data, Camera camera) {
+ Camera.Parameters parameters = camera.getParameters();
+ Camera.Size size = parameters.getPreviewSize();
+
+ Image barcode = new Image(size.width, size.height, "Y800");
+ barcode.setData(data);
+
+ if (scanner.scanImage(barcode) != 0) {
+ String qrValue = "";
+
+ SymbolSet syms = scanner.getResults();
+ for (Symbol sym : syms) {
+ qrValue = sym.getData();
+
+ // Return 1st found QR code value to the calling Activity.
+ Intent result = new Intent ();
+ result.putExtra(EXTRA_QRVALUE, qrValue);
+ setResult(Activity.RESULT_OK, result);
+ finish();
+ }
+
+ }
+ }
+ };
+
+ // Misc ------------------------------------------------------------
+
+ // finish() due to error
+ private void die (String msg)
+ {
+ setResult(RESULT_ERROR);
+ finish();
+ }
+
+ private int getResourceId (String typeAndName)
+ {
+ if(package_name == null) package_name = getApplication().getPackageName();
+ if(resources == null) resources = getApplication().getResources();
+ return resources.getIdentifier(typeAndName, null, package_name);
+ }
+
+ // Release the camera resources and state.
+ private void releaseCamera ()
+ {
+ if (camera != null) {
+ autoFocusHandler.removeCallbacks(doAutoFocus);
+ camera.setPreviewCallback(null);
+ camera.release();
+ camera = null;
+ }
+ }
+
+ // Match the aspect ratio of the preview SurfaceView with the camera's preview aspect ratio,
+ // so that the displayed preview is not stretched/squashed.
+ private void matchSurfaceToPreviewRatio () {
+ if(camera == null) return;
+ if(surfW == 0 || surfH == 0) return;
+
+ // Resize SurfaceView to match camera preview ratio (avoid stretching).
+ Camera.Parameters params = camera.getParameters();
+ Camera.Size size = params.getPreviewSize();
+ float previewRatio = (float) size.height / size.width; // swap h and w as the preview is rotated 90 degrees
+ float surfaceRatio = (float) surfW / surfH;
+
+ if(previewRatio > surfaceRatio) {
+ scannerSurface.setLayoutParams(new FrameLayout.LayoutParams(
+ surfW,
+ Math.round((float) surfW / previewRatio),
+ Gravity.CENTER
+ ));
+ } else if(previewRatio < surfaceRatio) {
+ scannerSurface.setLayoutParams(new FrameLayout.LayoutParams(
+ Math.round((float) surfH * previewRatio),
+ surfH,
+ Gravity.CENTER
+ ));
+ }
+ }
+
+ // Stop the camera preview safely.
+ private void tryStopPreview () {
+ // Stop camera preview before making changes.
+ try {
+ camera.stopPreview();
+ } catch (Exception e){
+ // Preview was not running. Ignore the error.
+ }
+ }
+
+ // Start the camera preview if possible.
+ // If start is attempted but fails, exit with error message.
+ private void tryStartPreview () {
+ if(holder != null) {
+ try {
+ // 90 degrees rotation for Portrait orientation Activity.
+ camera.setDisplayOrientation(90);
+
+ camera.setPreviewDisplay(holder);
+ camera.setPreviewCallback(previewCb);
+ camera.startPreview();
+ camera.autoFocus(autoFocusCb);
+ } catch (IOException e) {
+ die("Could not start camera preview: " + e.getMessage());
+ }
+ }
+ }
+}
diff --git a/android/libs/armeabi-v7a/libiconv.so b/android/libs/armeabi-v7a/libiconv.so
new file mode 100644
index 0000000..2bcbb70
Binary files /dev/null and b/android/libs/armeabi-v7a/libiconv.so differ
diff --git a/android/libs/armeabi-v7a/libzbarjni.so b/android/libs/armeabi-v7a/libzbarjni.so
new file mode 100644
index 0000000..2693dbb
Binary files /dev/null and b/android/libs/armeabi-v7a/libzbarjni.so differ
diff --git a/android/libs/armeabi/libiconv.so b/android/libs/armeabi/libiconv.so
new file mode 100644
index 0000000..9c7150d
Binary files /dev/null and b/android/libs/armeabi/libiconv.so differ
diff --git a/android/libs/armeabi/libzbarjni.so b/android/libs/armeabi/libzbarjni.so
new file mode 100644
index 0000000..3d4a8ac
Binary files /dev/null and b/android/libs/armeabi/libzbarjni.so differ
diff --git a/android/libs/x86/libiconv.so b/android/libs/x86/libiconv.so
new file mode 100644
index 0000000..6ab43e5
Binary files /dev/null and b/android/libs/x86/libiconv.so differ
diff --git a/android/libs/x86/libzbarjni.so b/android/libs/x86/libzbarjni.so
new file mode 100644
index 0000000..d64f517
Binary files /dev/null and b/android/libs/x86/libzbarjni.so differ
diff --git a/android/libs/zbar.jar b/android/libs/zbar.jar
new file mode 100644
index 0000000..7d50b95
Binary files /dev/null and b/android/libs/zbar.jar differ
diff --git a/android/res/layout/cszbarscanner.xml b/android/res/layout/cszbarscanner.xml
new file mode 100644
index 0000000..cd98afe
--- /dev/null
+++ b/android/res/layout/cszbarscanner.xml
@@ -0,0 +1,38 @@
+
+
+
+
+
+
+
+
diff --git a/plugin.xml b/plugin.xml
new file mode 100644
index 0000000..1e33ca8
--- /dev/null
+++ b/plugin.xml
@@ -0,0 +1,58 @@
+
+
+
+
+
+
+
+ ZBar barcode scanner
+ TJ Woon (tj@cloudsky.org)
+ Plugin to integrate with the ZBar barcode scanning library.
+ Apache 2.0
+ cszbar,zbar,barcode,qr,qr code,scanner
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Scan QR Code
+ Please point your camera at the QR code.
+ #ffffff
+ #88000000
+ #000000
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/www/zBar.js b/www/zBar.js
new file mode 100644
index 0000000..c46e40f
--- /dev/null
+++ b/www/zBar.js
@@ -0,0 +1,16 @@
+var argscheck = require('cordova/argscheck'),
+ exec = require('cordova/exec');
+
+function ZBar () {};
+
+ZBar.prototype = {
+
+ scan: function (params, success, failure)
+ {
+ argscheck.checkArgs('*fF', 'CsZBar.scan', arguments);
+ exec(success, failure, 'CsZBar', 'scan', [params]);
+ },
+
+};
+
+module.exports = new ZBar;