Saturday, October 15, 2011

QR code scanning in blackberry


import java.util.Hashtable;
import java.util.Vector;

import net.rim.blackberry.api.browser.Browser;
import net.rim.blackberry.api.browser.BrowserSession;
import net.rim.device.api.barcodelib.BarcodeBitmap;
import net.rim.device.api.barcodelib.BarcodeDecoder;
import net.rim.device.api.barcodelib.BarcodeDecoderListener;
import net.rim.device.api.barcodelib.BarcodeScanner;
import net.rim.device.api.command.Command;
import net.rim.device.api.command.CommandHandler;
import net.rim.device.api.command.ReadOnlyCommandMetadata;
import net.rim.device.api.system.Bitmap;
import net.rim.device.api.system.KeyListener;
import net.rim.device.api.ui.Field;
import net.rim.device.api.ui.FieldChangeListener;
import net.rim.device.api.ui.Keypad;
import net.rim.device.api.ui.UiApplication;
import net.rim.device.api.ui.XYEdges;
import net.rim.device.api.ui.component.BitmapField;
import net.rim.device.api.ui.component.ButtonField;
import net.rim.device.api.ui.component.Dialog;
import net.rim.device.api.ui.component.EditField;
import net.rim.device.api.ui.component.LabelField;
import net.rim.device.api.ui.container.FullScreen;
import net.rim.device.api.ui.container.MainScreen;
import net.rim.device.api.ui.decor.BorderFactory;
import net.rim.device.api.ui.toolbar.ToolbarButtonField;
import net.rim.device.api.ui.toolbar.ToolbarManager;
import net.rim.device.api.util.StringProvider;

import com.google.zxing.BarcodeFormat;
import com.google.zxing.DecodeHintType;
import com.google.zxing.common.ByteMatrix;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
import com.google.zxing.qrcode.encoder.Encoder;
import com.google.zxing.qrcode.encoder.QRCode;

public class BarcodeAPISample extends UiApplication {

//This controls how big barcode we will display is to be
private static final int BARCODE_WIDTH = 300;

// This is the app itself
private static BarcodeAPISample _app;

// Errors will be logged here
private LabelField _logField;

// The main screen which holds the toolbar and displayed barcode
private MainScreen _mainScreen;

// The barcode is displayed here
private BitmapField _barcodeField;
// The text stored here is converted into a barcode by the user
private EditField _barcodeTextField;

// This controls the scanning of barcodes
private BarcodeScanner _scanner;

// This screen is where the viewfinderf or the barcode scanner is displayed
private FullScreen _barcodeScreen;

public BarcodeAPISample() {
// New screen
_mainScreen = new MainScreen();

// Create the log field so it can be used in this constructor
_logField = new LabelField("Log: ");

// Create the place-holder for the barcode image and add it to the main
// screen
_barcodeField = new BitmapField(new Bitmap(BARCODE_WIDTH, BARCODE_WIDTH), Field.FIELD_HCENTER);
_barcodeField.setBorder(BorderFactory.createBevelBorder(new XYEdges(2, 2, 2, 2)));
_mainScreen.add(_barcodeField);

// Create and add the field to store the barcode contents
_barcodeTextField = new EditField("Barcode text: ", "http://devblog.blackberry.com");
_mainScreen.add(_barcodeTextField);

ButtonField d=new ButtonField("Display");
d.setChangeListener(new FieldChangeListener() {

public void fieldChanged(Field field, int context) {
// TODO Auto-generated method stub
displayBarcode();
}
});

ButtonField s=new ButtonField("scan");
s.setChangeListener(new FieldChangeListener() {

public void fieldChanged(Field field, int context) {
// TODO Auto-generated method stub
scanBarcode();
}
});

_mainScreen.add(d);
_mainScreen.add(s);

// Add "display barcode" and "scan barcode" toolbar buttons
/**
* This is a quick example of the new (in 6.0)
* net.rim.device.api.command package and the
* net.rim.device.api.ui.toolbar package. All it does is invoke the
* displayBarcode() or scanBarcode() method when you click the
* corresponding button. For more details on this package, see the
* JavaDocs or elsewhere in the Developer Resource Center
*/
ToolbarManager toolbar = new ToolbarManager();

ToolbarButtonField displayBarcodeToolbarButtonField = new ToolbarButtonField(new StringProvider("Display"));
displayBarcodeToolbarButtonField.setCommand(new Command(new CommandHandler() {
public void execute(ReadOnlyCommandMetadata arg0, Object arg1) {
displayBarcode();
}
}));
toolbar.add(displayBarcodeToolbarButtonField);

ToolbarButtonField scanBarcodeToolbarButtonField = new ToolbarButtonField(new StringProvider("Scan"));
scanBarcodeToolbarButtonField.setCommand(new Command(new CommandHandler() {
public void execute(ReadOnlyCommandMetadata arg0, Object arg1) {
scanBarcode();

}
}));
toolbar.add(scanBarcodeToolbarButtonField);

_mainScreen.setToolbar(toolbar);

// Add the log field to the bottom
_mainScreen.add(_logField);

pushScreen(_mainScreen);
}

// Simply create the the app and enter the event dispatcher
public static void main(String[] args) {
_app = new BarcodeAPISample();
_app.enterEventDispatcher();

}

/**
* displayBarcode
* <p>
* This method will take the text in the _barcodeTextField, convert it into
* a QRCode and display it on the main screen. It could be easily modified
* to use a different barcode format or to get the text from somewhere else.
*/
private void displayBarcode() {
try {
QRCode qrCode = new QRCode();

// This encodes the text with a low level (%7) of error correction
Encoder.encode(_barcodeTextField.getText(), ErrorCorrectionLevel.L, qrCode);

// From there we get the actual data matrix and convert it into a
// bitmap
ByteMatrix barcode = qrCode.getMatrix();
Bitmap bitmap = BarcodeBitmap.createBitmap(barcode, BARCODE_WIDTH);

_barcodeField.setBitmap(bitmap);

} catch (Exception e) {
log("Exception: " + e);
}
}

private void scanBarcode() {
// If we haven't scanned before, we will set up our barcode scanner
if (_barcodeScreen == null) {

// First we create a hashtable to hold all of the hints that we can
// give the API about how we want to scan a barcode to improve speed
// and accuracy.
Hashtable hints = new Hashtable();

// The first thing going in is a list of formats. We could look for
// more than one at a time, but it's much slower.
Vector formats = new Vector();
formats.addElement(BarcodeFormat.QR_CODE);
hints.put(DecodeHintType.POSSIBLE_FORMATS, formats);

// We will also use the "TRY_HARDER" flag to make sure we get an
// accurate scan
hints.put(DecodeHintType.TRY_HARDER, Boolean.TRUE);

// We create a new decoder using those hints
BarcodeDecoder decoder = new BarcodeDecoder(hints);

// Finally we can create the actual scanner with a decoder and a
// listener that will handle the data stored in the barcode. We put
// that in our view screen to handle the display.
try {
_scanner = new BarcodeScanner(decoder, new MyBarcodeDecoderListener());
_barcodeScreen = new MyBarcodeScannerViewScreen(_scanner);

} catch (Exception e) {
log("Could not initialize barcode scanner: " + e);
return;
}
}

// If we get here, all the barcode scanning infrastructure should be set
// up, so all we have to do is start the scan and display the viewfinder
try {
_scanner.startScan();
_app.pushScreen(_barcodeScreen);
} catch (Exception e) {
log("Could not start scan: " + e);
}

}

/***
* MyBarcodeDecoderListener
* <p>
* This BarcodeDecoverListener implementation tries to open any data encoded
* in a barcode in the browser.
*
* @author PBernhardt
*
**/
private class MyBarcodeDecoderListener implements BarcodeDecoderListener {

public void barcodeDecoded(final String rawText) {

// First pop the viewfinder screen off of the stack so we can see
// the main app
_app.invokeLater(new Runnable() {
public void run() {
_app.popScreen(_barcodeScreen);

}
});

// We will use a StringBuffer to create our message as every String
// concatenation creates a new Object
final StringBuffer message = new StringBuffer("Would you like to open the browser pointing to \"");
message.append(rawText);
message.append("\"?");
log(message.toString());
_barcodeScreen.invalidate();

// Prompt the user to open the browser pointing at the URL we
// scanned
_app.invokeLater(new Runnable() {
public void run() {
if (Dialog.ask(Dialog.D_YES_NO, message.toString()) == Dialog.YES) {

// Get the default sessionBrowserSession
BrowserSession browserSession = Browser.getDefaultSession();
// Launch the URL
browserSession.displayPage(rawText);
}
}
});
}

}

/***
* MyBarcodeScannerViewScreen
* <p>
* This view screen is simply an extension of MainScreen that will hold our
* scanner's viewfinder, and handle cleanly stopping the scan if the user
* decides they want to abort via the back button.
*
* @author PBernhardt
*
*/
private class MyBarcodeScannerViewScreen extends MainScreen {

public MyBarcodeScannerViewScreen(BarcodeScanner scanner) {
super();
try {
// Get the viewfinder and add it to the screen
_scanner.getVideoControl().setDisplayFullScreen(true);
Field viewFinder = _scanner.getViewfinder();
this.add(viewFinder);

// Create and add our key listener to the screen
this.addKeyListener(new MyKeyListener());

} catch (Exception e) {
log("Error creating view screen: " + e);
}

}

/***
* MyKeyListener
* <p>
* This KeyListener will stop the current scan cleanly when the back
* button is pressed, and then pop the viewfinder off the stack.
*
* @author PBernhardt
*
*/
private class MyKeyListener implements KeyListener {

public boolean keyDown(int keycode, int time) {

// First convert the keycode into an actual key event, taking
// modifiers into account
int key = Keypad.key(keycode);

// From there we can compare against the escape key constant. If
// we get it, we stop the scan and pop this screen off the stack
if (key == Keypad.KEY_ESCAPE) {
try {
_scanner.stopScan();
} catch (Exception e) {
log("Error stopping scan: " + e);
}
_app.invokeLater(new Runnable() {
public void run() {
_app.popScreen(_barcodeScreen);

}
});

return true;

}
// Otherwise, we'll return false so as not to consume the
// keyDown event
return false;
}

// We will only act on the keyDown event
public boolean keyChar(char key, int status, int time) {
return false;
}

public boolean keyRepeat(int keycode, int time) {
return false;
}

public boolean keyStatus(int keycode, int time) {
return false;
}

public boolean keyUp(int keycode, int time) {
return false;
}

}
}

/***
* log
* <p>
* Writes a message to an edit field for debug purposes. Also sends to
* STDOUT.
* <p>
*
* @param msg
*            - The String to log
*/
public void log(final String msg) {
invokeLater(new Runnable() {
public void run() {
_logField.setText(_logField.getText() + "\n" + msg);
System.out.println(msg);
}
});
}
}

No comments:

Post a Comment