mirror of
https://github.com/zxing/zxing.git
synced 2024-11-09 20:44:03 -08:00
Initial checkin of RIM client from LifeMarks, after initial refactorings and style changes, etc. May still need work.
git-svn-id: https://zxing.googlecode.com/svn/trunk@546 59b500cc-1b3d-0410-9834-0bbf25fbcc57
This commit is contained in:
parent
3a1d1f1850
commit
c58ae8b68d
4
AUTHORS
4
AUTHORS
|
@ -8,7 +8,9 @@ Christian Brunschen (Google)
|
|||
Daniel Switkin (Google)
|
||||
David Albert (Bug Labs)
|
||||
John Connolly (Bug Labs)
|
||||
Joseph Wain (Google)
|
||||
Matthew Schulkind (Google)
|
||||
Matt York (LifeMarks)
|
||||
Paul Hackenberger
|
||||
Sean Owen (Google)
|
||||
Vince Francis
|
||||
Vince Francis (LifeMarks)
|
||||
|
|
67
rim/src/com/google/zxing/client/rim/AboutScreen.java
Normal file
67
rim/src/com/google/zxing/client/rim/AboutScreen.java
Normal file
|
@ -0,0 +1,67 @@
|
|||
/*
|
||||
* Copyright 2008 ZXing authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.google.zxing.client.rim;
|
||||
|
||||
import net.rim.device.api.ui.Field;
|
||||
import net.rim.device.api.ui.FieldChangeListener;
|
||||
import net.rim.device.api.ui.Manager;
|
||||
import net.rim.device.api.ui.Screen;
|
||||
import net.rim.device.api.ui.Ui;
|
||||
import net.rim.device.api.ui.UiEngine;
|
||||
import net.rim.device.api.ui.DrawStyle;
|
||||
import net.rim.device.api.ui.component.ButtonField;
|
||||
import net.rim.device.api.ui.component.LabelField;
|
||||
import net.rim.device.api.ui.container.MainScreen;
|
||||
import net.rim.device.api.ui.container.VerticalFieldManager;
|
||||
|
||||
/**
|
||||
* The screen used to display the application 'about' information.
|
||||
*
|
||||
* This code was contributed by LifeMarks.
|
||||
*
|
||||
* @author Matt York (matt@lifemarks.mobi)
|
||||
*/
|
||||
final class AboutScreen extends MainScreen {
|
||||
|
||||
AboutScreen() {
|
||||
setTitle(new LabelField("ZXing - About", DrawStyle.ELLIPSIS | USE_ALL_WIDTH));
|
||||
Manager vfm = new VerticalFieldManager(FIELD_HCENTER);
|
||||
Field title = new LabelField("ZXing - BlackBerry Client", FIELD_HCENTER);
|
||||
Field uri = new LabelField("http://code.google.com/p/zxing/", FIELD_HCENTER);
|
||||
vfm.add(title);
|
||||
vfm.add(uri);
|
||||
Field okButton = new ButtonField("OK", FIELD_HCENTER | ButtonField.CONSUME_CLICK);
|
||||
okButton.setChangeListener(new ButtonListener(this));
|
||||
vfm.add(okButton);
|
||||
add(vfm);
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to close the screen when the ok button is pressed.
|
||||
*/
|
||||
private static class ButtonListener implements FieldChangeListener {
|
||||
private final Screen screen;
|
||||
private ButtonListener(Screen screen) {
|
||||
this.screen = screen;
|
||||
}
|
||||
public void fieldChanged(Field field, int context) {
|
||||
UiEngine ui = Ui.getUiEngine();
|
||||
ui.popScreen(screen);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,67 @@
|
|||
/*
|
||||
* Copyright 2008 ZXing authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.google.zxing.client.rim;
|
||||
|
||||
import com.google.zxing.client.rim.util.Log;
|
||||
import net.rim.device.api.applicationcontrol.ApplicationPermissions;
|
||||
import net.rim.device.api.applicationcontrol.ApplicationPermissionsManager;
|
||||
|
||||
/**
|
||||
* Requests the necessary permissions for the application.
|
||||
*
|
||||
* This code was contributed by LifeMarks.
|
||||
*
|
||||
* @author Matt York (matt@lifemarks.mobi)
|
||||
*/
|
||||
final class AppPermissionsManager {
|
||||
|
||||
private static final ApplicationPermissionsManager apm = ApplicationPermissionsManager.getInstance();
|
||||
|
||||
private AppPermissionsManager() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Requests the required application permissions. Currently the required permissions are
|
||||
* event injection (sending system level key strokes to other running applications) and
|
||||
* accessing files (accessing the file when a qrcode image is saved to the file system).
|
||||
*/
|
||||
static void setPermissions() {
|
||||
setPermission(ApplicationPermissions.PERMISSION_EVENT_INJECTOR);
|
||||
setPermission(ApplicationPermissions.PERMISSION_FILE_API);
|
||||
}
|
||||
|
||||
private static boolean setPermission(int permission) {
|
||||
boolean updatedPermissions = false;
|
||||
ApplicationPermissions ap = apm.getApplicationPermissions();
|
||||
if (ap.containsPermissionKey(permission)) {
|
||||
int eventInjectorPermission = ap.getPermission(permission);
|
||||
Log.info("permission (" + permission + "): " + eventInjectorPermission);
|
||||
if (eventInjectorPermission != ApplicationPermissions.VALUE_ALLOW) {
|
||||
Log.info("Setting permission to VALUE_ALLOW.");
|
||||
ap.addPermission(permission);
|
||||
updatedPermissions = apm.invokePermissionsRequest(ap);
|
||||
}
|
||||
} else {
|
||||
Log.info("Setting permission (" + permission + ") to VALUE_ALLOW.");
|
||||
ap.addPermission(permission);
|
||||
updatedPermissions = apm.invokePermissionsRequest(ap);
|
||||
}
|
||||
Log.info("updatedPermissions: " + updatedPermissions);
|
||||
return updatedPermissions;
|
||||
}
|
||||
|
||||
}
|
213
rim/src/com/google/zxing/client/rim/Camera.java
Normal file
213
rim/src/com/google/zxing/client/rim/Camera.java
Normal file
|
@ -0,0 +1,213 @@
|
|||
/*
|
||||
* Copyright 2008 ZXing authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.google.zxing.client.rim;
|
||||
|
||||
import com.google.zxing.client.rim.util.Log;
|
||||
import net.rim.blackberry.api.invoke.CameraArguments;
|
||||
import net.rim.blackberry.api.invoke.Invoke;
|
||||
import net.rim.device.api.system.Characters;
|
||||
import net.rim.device.api.system.EventInjector;
|
||||
import net.rim.device.api.ui.UiApplication;
|
||||
|
||||
/**
|
||||
* Singleton used to control access to the camera.
|
||||
* Unfortunatly, the Camera API only allows invoking the camera.
|
||||
*
|
||||
* Note: This code still contains experimental code to determine and set the camera resolution by
|
||||
* using system level key events, but didn't not function reliably and is not used.
|
||||
*
|
||||
* This code was contributed by LifeMarks.
|
||||
*
|
||||
* @author Matt York (matt@lifemarks.mobi)
|
||||
*/
|
||||
final class Camera {
|
||||
|
||||
/** milliseconds to wait before starting key strokes */
|
||||
private static final int INITIALIZATION_TIME_MS = 500; // simulator seems to need >= 500
|
||||
private static final int KEY_PAUSE_TIME_MS = 100; // simulator seems to need >= 100
|
||||
|
||||
private static Camera instance;
|
||||
|
||||
/** Attempting to set camera resolution is disabled. */
|
||||
private final boolean setResolution = false;
|
||||
|
||||
private Camera() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the single instance of the camera.
|
||||
*/
|
||||
static Camera getInstance() {
|
||||
if (instance == null) {
|
||||
instance = new Camera();
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts the blackberry camera application.
|
||||
*/
|
||||
void invoke() {
|
||||
Invoke.invokeApplication(Invoke.APP_TYPE_CAMERA, new CameraArguments());
|
||||
if (setResolution) {
|
||||
sleep(INITIALIZATION_TIME_MS);
|
||||
setMinResolution();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Exits the blackberry camera application.
|
||||
*/
|
||||
void exit() {
|
||||
if (setResolution) {
|
||||
setMaxResolution(); // for now, we dont know the original resolution setting. Assume it was max res.
|
||||
sleep(KEY_PAUSE_TIME_MS);
|
||||
}
|
||||
sleep(3000); // this sleep is needed for the esc to be processed(3000 originally)
|
||||
UiApplication app = UiApplication.getUiApplication();
|
||||
if (app != null) {
|
||||
Log.info("active app: " + app.getClass().getName());
|
||||
if (app.isForeground()) {
|
||||
Log.info("Lifemarks is the foreground app.");
|
||||
} else {
|
||||
Log.info("Lifemarks is not the foreground app. Attempt to close camera.");
|
||||
keyUpAndDown(Characters.ESCAPE); // need two (no timeout in between esc key presses seems to work best)
|
||||
keyUpAndDown(Characters.ESCAPE);
|
||||
}
|
||||
} else {
|
||||
Log.error("??? app is null ???");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the camera resolution to it's minimum.
|
||||
* Note: currently disabled.
|
||||
*/
|
||||
private static void setMaxResolution() {
|
||||
Log.info("Setting resolution to max.");
|
||||
accessResolutionMenuAfterSave();
|
||||
sleep(KEY_PAUSE_TIME_MS);
|
||||
keyUpAndDown(Characters.CONTROL_DOWN);
|
||||
sleep(KEY_PAUSE_TIME_MS);
|
||||
keyUpAndDown(Characters.CONTROL_DOWN); // min res
|
||||
sleep(KEY_PAUSE_TIME_MS);
|
||||
trackBallClick(); // out of res menu
|
||||
sleep(KEY_PAUSE_TIME_MS);
|
||||
trackBallClick(); // into res menu
|
||||
sleep(KEY_PAUSE_TIME_MS);
|
||||
keyUpAndDown(Characters.CONTROL_UP);
|
||||
sleep(KEY_PAUSE_TIME_MS);
|
||||
keyUpAndDown(Characters.CONTROL_UP); // max res
|
||||
sleep(KEY_PAUSE_TIME_MS);
|
||||
trackBallClick(); // out of res menu
|
||||
sleep(KEY_PAUSE_TIME_MS);
|
||||
keyUpAndDown(Characters.ESCAPE); // out of options
|
||||
sleep(KEY_PAUSE_TIME_MS);
|
||||
trackBallClick(); // yes to changes, even if there werent really any!
|
||||
Log.info("Finished setting resolution to max.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the camera resolution to it's maximum.
|
||||
* Note: currently disabled.
|
||||
*/
|
||||
private static void setMinResolution() {
|
||||
Log.info("Setting resolution to min.");
|
||||
accessResolutionMenu();
|
||||
sleep(KEY_PAUSE_TIME_MS);
|
||||
keyUpAndDown(Characters.CONTROL_UP);
|
||||
sleep(KEY_PAUSE_TIME_MS);
|
||||
keyUpAndDown(Characters.CONTROL_UP); // max res
|
||||
sleep(KEY_PAUSE_TIME_MS);
|
||||
trackBallClick(); // out of res menu
|
||||
sleep(KEY_PAUSE_TIME_MS);
|
||||
trackBallClick(); // into res menu
|
||||
sleep(KEY_PAUSE_TIME_MS);
|
||||
keyUpAndDown(Characters.CONTROL_DOWN);
|
||||
sleep(KEY_PAUSE_TIME_MS);
|
||||
keyUpAndDown(Characters.CONTROL_DOWN); // min res
|
||||
sleep(KEY_PAUSE_TIME_MS);
|
||||
trackBallClick(); // out of res menu
|
||||
sleep(KEY_PAUSE_TIME_MS);
|
||||
keyUpAndDown(Characters.ESCAPE); // out of options
|
||||
trackBallClick(); // yes to changes, even if there werent really any!
|
||||
}
|
||||
|
||||
private static void accessResolutionMenu() {
|
||||
keyUpAndDown(Characters.CONTROL_MENU);
|
||||
sleep(KEY_PAUSE_TIME_MS);
|
||||
keyUpAndDown(Characters.CONTROL_DOWN);
|
||||
sleep(KEY_PAUSE_TIME_MS);
|
||||
trackBallClick();
|
||||
sleep(KEY_PAUSE_TIME_MS);
|
||||
keyUpAndDown(Characters.CONTROL_DOWN);
|
||||
sleep(KEY_PAUSE_TIME_MS);
|
||||
keyUpAndDown(Characters.CONTROL_DOWN);
|
||||
sleep(KEY_PAUSE_TIME_MS);
|
||||
trackBallClick();
|
||||
}
|
||||
|
||||
private static void accessResolutionMenuAfterSave() {
|
||||
keyUpAndDown(Characters.CONTROL_MENU);
|
||||
keyUpAndDown(Characters.CONTROL_DOWN, 6, 0); // seems to be down 6 items on bb and 4 on simulator
|
||||
trackBallClick();
|
||||
keyUpAndDown(Characters.CONTROL_DOWN);
|
||||
keyUpAndDown(Characters.CONTROL_DOWN);
|
||||
trackBallClick();
|
||||
}
|
||||
|
||||
/**
|
||||
* Puts the current thread to sleep for a given amount of time.
|
||||
*/
|
||||
private static void sleep(int time) {
|
||||
try {
|
||||
Thread.sleep(time);
|
||||
} catch (InterruptedException ie) {
|
||||
// continue
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static void trackBallClick() {
|
||||
EventInjector.invokeEvent(
|
||||
new EventInjector.NavigationEvent(EventInjector.NavigationEvent.NAVIGATION_CLICK, 0, 0, 1));
|
||||
EventInjector.invokeEvent(
|
||||
new EventInjector.NavigationEvent(EventInjector.NavigationEvent.NAVIGATION_UNCLICK, 0, 0, 1));
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends system level key events a given number of times with the given delay between them.
|
||||
*/
|
||||
private static void keyUpAndDown(char character, int times, int delay) {
|
||||
for (int i = 0; i < times; i++) {
|
||||
keyUpAndDown(character);
|
||||
if (delay > 0) {
|
||||
sleep(delay);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends one system level key event.
|
||||
*/
|
||||
private static void keyUpAndDown(char character) {
|
||||
EventInjector.invokeEvent(new EventInjector.KeyEvent(EventInjector.KeyEvent.KEY_DOWN, character, 0, 1));
|
||||
EventInjector.invokeEvent(new EventInjector.KeyEvent(EventInjector.KeyEvent.KEY_UP, character, 0, 1));
|
||||
}
|
||||
|
||||
}
|
||||
|
65
rim/src/com/google/zxing/client/rim/HelpScreen.java
Normal file
65
rim/src/com/google/zxing/client/rim/HelpScreen.java
Normal file
|
@ -0,0 +1,65 @@
|
|||
/*
|
||||
* Copyright 2008 ZXing authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.google.zxing.client.rim;
|
||||
|
||||
import net.rim.device.api.ui.DrawStyle;
|
||||
import net.rim.device.api.ui.Field;
|
||||
import net.rim.device.api.ui.FieldChangeListener;
|
||||
import net.rim.device.api.ui.Screen;
|
||||
import net.rim.device.api.ui.Ui;
|
||||
import net.rim.device.api.ui.UiEngine;
|
||||
import net.rim.device.api.ui.Manager;
|
||||
import net.rim.device.api.ui.component.ButtonField;
|
||||
import net.rim.device.api.ui.component.LabelField;
|
||||
import net.rim.device.api.ui.container.MainScreen;
|
||||
import net.rim.device.api.ui.container.VerticalFieldManager;
|
||||
|
||||
/**
|
||||
* The screen used to display the application help information.
|
||||
*
|
||||
* This code was contributed by LifeMarks.
|
||||
*
|
||||
* @author Matt York (matt@lifemarks.mobi)
|
||||
*/
|
||||
final class HelpScreen extends MainScreen {
|
||||
|
||||
HelpScreen() {
|
||||
setTitle(new LabelField("ZXing - Help", DrawStyle.ELLIPSIS | USE_ALL_WIDTH));
|
||||
Manager vfm = new VerticalFieldManager(FIELD_HCENTER);
|
||||
Field aboutText = new LabelField("help info...", FIELD_HCENTER);
|
||||
vfm.add(aboutText);
|
||||
Field okButton = new ButtonField("OK", FIELD_HCENTER | ButtonField.CONSUME_CLICK);
|
||||
okButton.setChangeListener(new ButtonListener(this));
|
||||
vfm.add(okButton);
|
||||
add(vfm);
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes the screen when the OK button is pressed.
|
||||
*/
|
||||
private static class ButtonListener implements FieldChangeListener {
|
||||
private final Screen screen;
|
||||
private ButtonListener(Screen screen) {
|
||||
this.screen = screen;
|
||||
}
|
||||
public void fieldChanged(Field field, int context) {
|
||||
UiEngine ui = Ui.getUiEngine();
|
||||
ui.popScreen(screen);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
81
rim/src/com/google/zxing/client/rim/HistoryScreen.java
Normal file
81
rim/src/com/google/zxing/client/rim/HistoryScreen.java
Normal file
|
@ -0,0 +1,81 @@
|
|||
/*
|
||||
* Copyright 2008 ZXing authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.google.zxing.client.rim;
|
||||
|
||||
import com.google.zxing.client.rim.persistence.history.DecodeHistory;
|
||||
import com.google.zxing.client.rim.persistence.history.DecodeHistoryItem;
|
||||
import com.google.zxing.client.rim.util.Log;
|
||||
import net.rim.blackberry.api.browser.Browser;
|
||||
import net.rim.blackberry.api.browser.BrowserSession;
|
||||
import net.rim.device.api.ui.DrawStyle;
|
||||
import net.rim.device.api.ui.Field;
|
||||
import net.rim.device.api.ui.FieldChangeListener;
|
||||
import net.rim.device.api.ui.Manager;
|
||||
import net.rim.device.api.ui.FieldLabelProvider;
|
||||
import net.rim.device.api.ui.component.ButtonField;
|
||||
import net.rim.device.api.ui.component.LabelField;
|
||||
import net.rim.device.api.ui.container.MainScreen;
|
||||
import net.rim.device.api.ui.container.VerticalFieldManager;
|
||||
|
||||
/**
|
||||
* The screen used to display the qrcode decoding history.
|
||||
*
|
||||
* This code was contributed by LifeMarks.
|
||||
*
|
||||
* @author Matt York (matt@lifemarks.mobi)
|
||||
*/
|
||||
final class HistoryScreen extends MainScreen {
|
||||
|
||||
HistoryScreen() {
|
||||
setTitle(new LabelField("ZXing - History", DrawStyle.ELLIPSIS | USE_ALL_WIDTH));
|
||||
Manager vfm = new VerticalFieldManager(FIELD_HCENTER | VERTICAL_SCROLL);
|
||||
Log.debug("Num history items: " + DecodeHistory.getInstance().getNumItems());
|
||||
DecodeHistory history = DecodeHistory.getInstance();
|
||||
FieldChangeListener itemListener = new ButtonListener();
|
||||
for (int i = 0; i < history.getNumItems(); i++) {
|
||||
DecodeHistoryItem item = history.getItemAt(i);
|
||||
Field labelButton = new ButtonField(item.getURI(), FIELD_HCENTER | ButtonField.CONSUME_CLICK);
|
||||
labelButton.setChangeListener(itemListener);
|
||||
vfm.add(labelButton);
|
||||
}
|
||||
|
||||
Field okButton = new ButtonField("OK", FIELD_HCENTER | ButtonField.CONSUME_CLICK);
|
||||
okButton.setChangeListener(itemListener);
|
||||
add(vfm);
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes the screen when the OK button is pressed.
|
||||
*/
|
||||
private static class ButtonListener implements FieldChangeListener {
|
||||
public void fieldChanged(Field field, int context) {
|
||||
if (field instanceof ButtonField) {
|
||||
BrowserSession browserSession = Browser.getDefaultSession();
|
||||
browserSession.displayPage(((FieldLabelProvider) field).getLabel());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Overriding this method removes the save changes prompt
|
||||
*/
|
||||
public boolean onSavePrompt() {
|
||||
setDirty(false);
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
|
@ -16,35 +16,36 @@
|
|||
|
||||
package com.google.zxing.client.rim;
|
||||
|
||||
import com.google.zxing.client.rim.util.Log;
|
||||
import net.rim.device.api.io.file.FileSystemJournal;
|
||||
import net.rim.device.api.io.file.FileSystemJournalEntry;
|
||||
import net.rim.device.api.io.file.FileSystemJournalListener;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* @author Sean Owen (srowen@google.com)
|
||||
* The listener that is fired when an image file is added to the file system.
|
||||
*
|
||||
* This code was contributed by LifeMarks.
|
||||
*
|
||||
* @author Matt York (matt@lifemarks.mobi)
|
||||
*/
|
||||
final class ImageCapturedJournalListener implements FileSystemJournalListener {
|
||||
final class QRCapturedJournalListener implements FileSystemJournalListener {
|
||||
|
||||
private final ZXingMainScreen screen;
|
||||
private long lastUSN;
|
||||
private final ZXingLMMainScreen screen;
|
||||
|
||||
ImageCapturedJournalListener(ZXingMainScreen screen) {
|
||||
QRCapturedJournalListener(ZXingLMMainScreen screen) {
|
||||
this.screen = screen;
|
||||
}
|
||||
|
||||
public void fileJournalChanged() {
|
||||
long nextUSN = FileSystemJournal.getNextUSN();
|
||||
for (long lookUSN = nextUSN - 1; lookUSN >= lastUSN; --lookUSN) {
|
||||
FileSystemJournalEntry entry = FileSystemJournal.getEntry(lookUSN);
|
||||
if (entry == null) {
|
||||
break;
|
||||
}
|
||||
if (entry.getEvent() == FileSystemJournalEntry.FILE_ADDED) {
|
||||
screen.handleFile(entry.getPath());
|
||||
}
|
||||
long lookUSN = FileSystemJournal.getNextUSN() - 1; // the last file added to the filesystem
|
||||
Log.debug("lookUSN: " + lookUSN);
|
||||
FileSystemJournalEntry entry = FileSystemJournal.getEntry(lookUSN);
|
||||
if (entry != null && entry.getEvent() == FileSystemJournalEntry.FILE_ADDED) {
|
||||
Log.info("Got file: " + entry.getPath() + " @: " + new Date());
|
||||
screen.imageSaved(entry.getPath());
|
||||
}
|
||||
lastUSN = nextUSN;
|
||||
}
|
||||
|
||||
|
||||
}
|
104
rim/src/com/google/zxing/client/rim/SettingsScreen.java
Normal file
104
rim/src/com/google/zxing/client/rim/SettingsScreen.java
Normal file
|
@ -0,0 +1,104 @@
|
|||
/*
|
||||
* Copyright 2008 ZXing authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.google.zxing.client.rim;
|
||||
|
||||
import com.google.zxing.client.rim.persistence.AppSettings;
|
||||
import com.google.zxing.client.rim.persistence.history.DecodeHistory;
|
||||
import com.google.zxing.client.rim.util.Log;
|
||||
import net.rim.device.api.ui.Field;
|
||||
import net.rim.device.api.ui.FieldChangeListener;
|
||||
import net.rim.device.api.ui.Manager;
|
||||
import net.rim.device.api.ui.Screen;
|
||||
import net.rim.device.api.ui.Ui;
|
||||
import net.rim.device.api.ui.UiEngine;
|
||||
import net.rim.device.api.ui.DrawStyle;
|
||||
import net.rim.device.api.ui.component.ButtonField;
|
||||
import net.rim.device.api.ui.component.CheckboxField;
|
||||
import net.rim.device.api.ui.component.LabelField;
|
||||
import net.rim.device.api.ui.container.MainScreen;
|
||||
import net.rim.device.api.ui.container.VerticalFieldManager;
|
||||
|
||||
/**
|
||||
* Screen used to change application settings.
|
||||
*
|
||||
* This code was contributed by LifeMarks.
|
||||
*
|
||||
* @author Matt York (matt@lifemarks.mobi)
|
||||
*/
|
||||
final class SettingsScreen extends MainScreen {
|
||||
|
||||
private boolean changes;
|
||||
private final AppSettings settings;
|
||||
private final CheckboxField camResMsgCheckBox;
|
||||
|
||||
SettingsScreen() {
|
||||
setTitle(new LabelField("ZXing - Settings", DrawStyle.ELLIPSIS | USE_ALL_WIDTH));
|
||||
Manager vfm = new VerticalFieldManager(FIELD_HCENTER);
|
||||
|
||||
settings = AppSettings.getInstance();
|
||||
Boolean cameraResMsgSetting = settings.getBooleanItem(AppSettings.SETTING_CAM_RES_MSG);
|
||||
boolean cameraResMsgSettingBool = (cameraResMsgSetting != null) && cameraResMsgSetting.booleanValue();
|
||||
// 0
|
||||
camResMsgCheckBox = new CheckboxField("Don't show camera resolution message", cameraResMsgSettingBool);
|
||||
camResMsgCheckBox.setChangeListener(new ButtonListener(this));
|
||||
vfm.add(camResMsgCheckBox);
|
||||
|
||||
// 1
|
||||
Field clearHistoryButton = new ButtonField("Clear History",FIELD_HCENTER | ButtonField.CONSUME_CLICK);
|
||||
clearHistoryButton.setChangeListener(new ButtonListener(this));
|
||||
vfm.add(clearHistoryButton);
|
||||
|
||||
// 2
|
||||
Field okButton = new ButtonField("OK", FIELD_HCENTER | ButtonField.CONSUME_CLICK);
|
||||
okButton.setChangeListener(new ButtonListener(this));
|
||||
vfm.add(okButton);
|
||||
|
||||
add(vfm);
|
||||
}
|
||||
|
||||
/**
|
||||
* Listens for button clicks and executes the appropriate action.
|
||||
*/
|
||||
private final class ButtonListener implements FieldChangeListener {
|
||||
private final Screen screen;
|
||||
private ButtonListener(Screen screen) {
|
||||
this.screen = screen;
|
||||
}
|
||||
public void fieldChanged(Field field, int context) {
|
||||
Log.debug("Field: " + field.getIndex() + " , context: " + context);
|
||||
switch (field.getIndex()) {
|
||||
case 0:
|
||||
settings.addItem(AppSettings.SETTING_CAM_RES_MSG,
|
||||
(camResMsgCheckBox.getChecked()) ? Boolean.TRUE : Boolean.FALSE);
|
||||
changes = true;
|
||||
break;
|
||||
case 1:
|
||||
// TODO confirm
|
||||
DecodeHistory.getInstance().clear();
|
||||
DecodeHistory.getInstance().persist();
|
||||
case 2: //ok
|
||||
if (changes) {
|
||||
AppSettings.getInstance().persist();
|
||||
}
|
||||
UiEngine ui = Ui.getUiEngine();
|
||||
ui.popScreen(screen);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
331
rim/src/com/google/zxing/client/rim/ZXingLMMainScreen.java
Normal file
331
rim/src/com/google/zxing/client/rim/ZXingLMMainScreen.java
Normal file
|
@ -0,0 +1,331 @@
|
|||
/*
|
||||
* Copyright 2008 ZXing authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.google.zxing.client.rim;
|
||||
|
||||
import com.google.zxing.DecodeHintType;
|
||||
import com.google.zxing.MonochromeBitmapSource;
|
||||
import com.google.zxing.MultiFormatReader;
|
||||
import com.google.zxing.Reader;
|
||||
import com.google.zxing.ReaderException;
|
||||
import com.google.zxing.Result;
|
||||
import com.google.zxing.client.j2me.LCDUIImageMonochromeBitmapSource;
|
||||
import com.google.zxing.client.rim.persistence.AppSettings;
|
||||
import com.google.zxing.client.rim.persistence.history.DecodeHistory;
|
||||
import com.google.zxing.client.rim.persistence.history.DecodeHistoryItem;
|
||||
import com.google.zxing.client.rim.util.Log;
|
||||
import com.google.zxing.client.rim.util.ReasonableTimer;
|
||||
import com.google.zxing.client.rim.util.URLDecoder;
|
||||
import net.rim.blackberry.api.browser.Browser;
|
||||
import net.rim.blackberry.api.browser.BrowserSession;
|
||||
import net.rim.device.api.ui.DrawStyle;
|
||||
import net.rim.device.api.ui.Field;
|
||||
import net.rim.device.api.ui.FieldChangeListener;
|
||||
import net.rim.device.api.ui.Manager;
|
||||
import net.rim.device.api.ui.UiApplication;
|
||||
import net.rim.device.api.ui.component.ButtonField;
|
||||
import net.rim.device.api.ui.component.Dialog;
|
||||
import net.rim.device.api.ui.component.LabelField;
|
||||
import net.rim.device.api.ui.container.DialogFieldManager;
|
||||
import net.rim.device.api.ui.container.MainScreen;
|
||||
import net.rim.device.api.ui.container.PopupScreen;
|
||||
import net.rim.device.api.ui.container.VerticalFieldManager;
|
||||
|
||||
import javax.microedition.io.Connector;
|
||||
import javax.microedition.io.file.FileConnection;
|
||||
import javax.microedition.lcdui.Image;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.Hashtable;
|
||||
|
||||
/**
|
||||
* The main appication menu screen.
|
||||
*
|
||||
* This code was contributed by LifeMarks.
|
||||
*
|
||||
* @author Matt York (matt@lifemarks.mobi)
|
||||
*/
|
||||
final class ZXingLMMainScreen extends MainScreen {
|
||||
|
||||
private final ZXingUiApplication app;
|
||||
private final QRCapturedJournalListener imageListener;
|
||||
private PopupScreen popup;
|
||||
private final Reader reader;
|
||||
private final Hashtable readerHints;
|
||||
|
||||
ZXingLMMainScreen() {
|
||||
super(DEFAULT_MENU | DEFAULT_CLOSE);
|
||||
setTitle(new LabelField("ZXing", DrawStyle.ELLIPSIS | USE_ALL_WIDTH));
|
||||
setChangeListener(null);
|
||||
|
||||
Manager vfm = new VerticalFieldManager(USE_ALL_WIDTH);
|
||||
FieldChangeListener buttonListener = new ButtonListener();
|
||||
|
||||
//0
|
||||
Field snapButton = new ButtonField("Snap", FIELD_HCENTER | ButtonField.CONSUME_CLICK | USE_ALL_WIDTH);
|
||||
snapButton.setChangeListener(buttonListener);
|
||||
vfm.add(snapButton);
|
||||
|
||||
//1
|
||||
Field historyButton = new ButtonField("History", FIELD_HCENTER | ButtonField.CONSUME_CLICK);
|
||||
historyButton.setChangeListener(buttonListener);
|
||||
vfm.add(historyButton);
|
||||
|
||||
//2
|
||||
Field settingsButton = new ButtonField("Settings", FIELD_HCENTER | ButtonField.CONSUME_CLICK);
|
||||
settingsButton.setChangeListener(buttonListener);
|
||||
vfm.add(settingsButton);
|
||||
|
||||
//3
|
||||
Field aboutButton = new ButtonField("About", FIELD_HCENTER | ButtonField.CONSUME_CLICK);
|
||||
aboutButton.setChangeListener(buttonListener);
|
||||
vfm.add(aboutButton);
|
||||
|
||||
//4
|
||||
Field helpButton = new ButtonField("Help", FIELD_HCENTER | ButtonField.CONSUME_CLICK);
|
||||
helpButton.setChangeListener(buttonListener);
|
||||
vfm.add(helpButton);
|
||||
|
||||
vfm.setChangeListener(null);
|
||||
add(vfm);
|
||||
|
||||
|
||||
app = (ZXingUiApplication) UiApplication.getUiApplication();
|
||||
imageListener = new QRCapturedJournalListener(this);
|
||||
|
||||
reader = new MultiFormatReader();
|
||||
readerHints = new Hashtable(1);
|
||||
readerHints.put(DecodeHintType.TRY_HARDER, Boolean.TRUE);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Handles the newly created file. If the file is a jpg image, from the camera, the images is assumed to be
|
||||
* a qrcode and decoding is attempted.
|
||||
*/
|
||||
void imageSaved(String imagePath) {
|
||||
Log.info("Image saved: " + imagePath);
|
||||
app.removeFileSystemJournalListener(imageListener);
|
||||
if (imagePath.endsWith(".jpg") && imagePath.indexOf("IMG") >= 0) // a blackberry camera image file
|
||||
{
|
||||
Log.info("imageSaved - Got file: " + imagePath);
|
||||
Camera.getInstance().exit();
|
||||
Log.info("camera exit finished");
|
||||
app.requestForeground();
|
||||
|
||||
DialogFieldManager manager = new DialogFieldManager();
|
||||
popup = new PopupScreen(manager);
|
||||
manager.addCustomField(new LabelField("Decoding image..."));
|
||||
|
||||
app.pushScreen(popup); // original
|
||||
Log.info("started progress screen.");
|
||||
|
||||
Runnable fct = new FileConnectionThread(imagePath);
|
||||
Log.info("Starting file connection thread.");
|
||||
app.invokeLater(fct);
|
||||
Log.info("Finished file connection thread.");
|
||||
} else {
|
||||
Log.error("Failed to locate camera image.");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes the application and persists all required data.
|
||||
*/
|
||||
public void close() {
|
||||
app.removeFileSystemJournalListener(imageListener);
|
||||
DecodeHistory.getInstance().persist();
|
||||
super.close();
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is overriden to remove the 'save changes' dialog when exiting.
|
||||
*/
|
||||
public boolean onSavePrompt() {
|
||||
setDirty(false);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Listens for selected buttons and starts the required screen.
|
||||
*/
|
||||
private final class ButtonListener implements FieldChangeListener {
|
||||
public void fieldChanged(Field field, int context) {
|
||||
Log.debug("*** fieldChanged: " + field.getIndex());
|
||||
switch (field.getIndex()) {
|
||||
case 0: // snap
|
||||
try {
|
||||
app.addFileSystemJournalListener(imageListener);
|
||||
Camera.getInstance().invoke(); // start camera
|
||||
return;
|
||||
}
|
||||
catch (Exception e) {
|
||||
Log.error("!!! Problem invoking camera.!!!: " + e);
|
||||
}
|
||||
break;
|
||||
case 1: // history
|
||||
app.pushScreen(new HistoryScreen());
|
||||
break;
|
||||
case 2: // settings
|
||||
app.pushScreen(new SettingsScreen());
|
||||
break;
|
||||
case 3: //about
|
||||
app.pushScreen(new AboutScreen());
|
||||
break;
|
||||
case 4: //help
|
||||
app.pushScreen(new HelpScreen());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Thread that decodes the newly created image. If the image is successfully decoded and the data is a URL,
|
||||
* the browser is invoked and pointed to the given URL.
|
||||
*/
|
||||
private final class FileConnectionThread implements Runnable {
|
||||
|
||||
private final String imagePath;
|
||||
|
||||
private FileConnectionThread(String imagePath) {
|
||||
this.imagePath = imagePath;
|
||||
}
|
||||
|
||||
public void run() {
|
||||
FileConnection file = null;
|
||||
InputStream is = null;
|
||||
Image capturedImage = null;
|
||||
try {
|
||||
file = (FileConnection) Connector.open("file://" + imagePath, Connector.READ_WRITE);
|
||||
is = file.openInputStream();
|
||||
capturedImage = Image.createImage(is);
|
||||
} catch (IOException e) {
|
||||
Log.error("Problem creating image: " + e);
|
||||
removeProgressBar();
|
||||
invalidate();
|
||||
showMessage("An error occured processing the image.");
|
||||
return;
|
||||
} finally {
|
||||
if (is != null) {
|
||||
try {
|
||||
is.close();
|
||||
} catch (IOException ioe) {
|
||||
}
|
||||
}
|
||||
if (file != null && file.exists()) {
|
||||
if (file.isOpen()) {
|
||||
//file.close();
|
||||
}
|
||||
//file.delete();
|
||||
Log.info("Deleted image file.");
|
||||
}
|
||||
}
|
||||
|
||||
if (capturedImage != null) {
|
||||
Log.info("Got image...");
|
||||
MonochromeBitmapSource source = new LCDUIImageMonochromeBitmapSource(capturedImage);
|
||||
Result result;
|
||||
ReasonableTimer decodingTimer = null;
|
||||
try {
|
||||
decodingTimer = new ReasonableTimer();
|
||||
Log.info("Attempting to decode image...");
|
||||
result = reader.decode(source, readerHints);
|
||||
decodingTimer.finished();
|
||||
} catch (ReaderException e) {
|
||||
Log.error("Could not decode image: " + e);
|
||||
decodingTimer.finished();
|
||||
removeProgressBar();
|
||||
invalidate();
|
||||
boolean showResolutionMsg =
|
||||
!AppSettings.getInstance().getBooleanItem(AppSettings.SETTING_CAM_RES_MSG).booleanValue();
|
||||
if (showResolutionMsg) {
|
||||
showMessage("A QR Code was not found in the image. " +
|
||||
"We detected that the decoding process took quite a while. " +
|
||||
"It will be much faster if you decrease your camera's resolution (640x480).");
|
||||
} else {
|
||||
showMessage("A QR Code was not found in the image.");
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (result != null) {
|
||||
String resultText = result.getText();
|
||||
Log.info("result: " + resultText);
|
||||
if (isURI(resultText)) {
|
||||
resultText = URLDecoder.decode(resultText);
|
||||
removeProgressBar();
|
||||
invalidate();
|
||||
if (!decodingTimer.wasResonableTime() &&
|
||||
!AppSettings.getInstance().getBooleanItem(AppSettings.SETTING_CAM_RES_MSG).booleanValue()) {
|
||||
showMessage("We detected that the decoding process took quite a while. " +
|
||||
"It will be much faster if you decrease your camera's resolution (640x480).");
|
||||
}
|
||||
DecodeHistory.getInstance().addHistoryItem(new DecodeHistoryItem(resultText));
|
||||
invokeBrowser(resultText);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
removeProgressBar();
|
||||
invalidate();
|
||||
showMessage("A QR Code was not found in the image.");
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
removeProgressBar();
|
||||
invalidate();
|
||||
}
|
||||
|
||||
/**
|
||||
* Quick check to see if the result of decoding the qr code was a valid uri.
|
||||
*/
|
||||
private boolean isURI(String uri) {
|
||||
return uri.startsWith("http://");
|
||||
}
|
||||
|
||||
/**
|
||||
* Invokes the web browser and browses to the given uri.
|
||||
*/
|
||||
private void invokeBrowser(String uri) {
|
||||
BrowserSession browserSession = Browser.getDefaultSession();
|
||||
browserSession.displayPage(uri);
|
||||
}
|
||||
|
||||
/**
|
||||
* Syncronized version of removing progress dialog.
|
||||
* NOTE: All methods accessing the gui that are in seperate threads should syncronize on app.getEventLock()
|
||||
*/
|
||||
private void removeProgressBar() {
|
||||
synchronized (app.getAppEventLock()) {
|
||||
if (popup != null) {
|
||||
app.popScreen(popup);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Syncronized version of showing a message dialog.
|
||||
* NOTE: All methods accessing the gui that are in seperate threads should syncronize on app.getEventLock()
|
||||
*/
|
||||
private void showMessage(String message) {
|
||||
synchronized (app.getAppEventLock()) {
|
||||
Dialog.alert(message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -1,129 +0,0 @@
|
|||
/*
|
||||
* Copyright 2008 ZXing authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.google.zxing.client.rim;
|
||||
|
||||
import com.google.zxing.MonochromeBitmapSource;
|
||||
import com.google.zxing.MultiFormatReader;
|
||||
import com.google.zxing.Reader;
|
||||
import com.google.zxing.ReaderException;
|
||||
import com.google.zxing.Result;
|
||||
import com.google.zxing.client.j2me.LCDUIImageMonochromeBitmapSource;
|
||||
import net.rim.blackberry.api.invoke.CameraArguments;
|
||||
import net.rim.blackberry.api.invoke.Invoke;
|
||||
import net.rim.device.api.system.Characters;
|
||||
import net.rim.device.api.system.EventInjector;
|
||||
import net.rim.device.api.ui.UiApplication;
|
||||
import net.rim.device.api.ui.component.Dialog;
|
||||
import net.rim.device.api.ui.component.LabelField;
|
||||
import net.rim.device.api.ui.container.MainScreen;
|
||||
|
||||
import javax.microedition.io.Connector;
|
||||
import javax.microedition.io.file.FileConnection;
|
||||
import javax.microedition.lcdui.Image;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
/**
|
||||
* @author Sean Owen (srowen@google.com)
|
||||
*/
|
||||
final class ZXingMainScreen extends MainScreen {
|
||||
|
||||
private final ZXingUIApp app;
|
||||
private final ImageCapturedJournalListener captureListener;
|
||||
|
||||
ZXingMainScreen() {
|
||||
setTitle("ZXing Barcode Reader");
|
||||
add(new LabelField("UNDER CONSTRUCTION"));
|
||||
add(new LabelField("1. Press 'Enter' at right to launch the Camera application"));
|
||||
add(new LabelField("2. Configure Camera to capture 640x480 image"));
|
||||
add(new LabelField("3. Take a picture of a barcode"));
|
||||
add(new LabelField("4. If not returned to this application to see result, close Camera application"));
|
||||
app = (ZXingUIApp) UiApplication.getUiApplication();
|
||||
captureListener = new ImageCapturedJournalListener(this);
|
||||
app.addFileSystemJournalListener(captureListener);
|
||||
}
|
||||
|
||||
public boolean keyChar(char c, int status, int time) {
|
||||
if (c == Characters.ENTER) {
|
||||
Invoke.invokeApplication(Invoke.APP_TYPE_CAMERA, new CameraArguments());
|
||||
return true;
|
||||
} else {
|
||||
return super.keyChar(c, status, time);
|
||||
}
|
||||
}
|
||||
|
||||
public void close() {
|
||||
app.removeFileSystemJournalListener(captureListener);
|
||||
super.close();
|
||||
}
|
||||
|
||||
private void showMessage(String msg) {
|
||||
synchronized (app.getAppEventLock()) {
|
||||
Dialog.alert(msg);
|
||||
}
|
||||
}
|
||||
|
||||
void handleFile(String path) {
|
||||
if (path.endsWith(".jpg") && path.indexOf("IMG") >= 0) {
|
||||
// Get out of camera app
|
||||
EventInjector.invokeEvent(new EventInjector.KeyEvent(EventInjector.KeyEvent.KEY_DOWN, Characters.ESCAPE, 0, 1));
|
||||
EventInjector.invokeEvent(new EventInjector.KeyEvent(EventInjector.KeyEvent.KEY_UP, Characters.ESCAPE, 0, 1));
|
||||
// Try to come to foreground for good measure
|
||||
app.requestForeground();
|
||||
try {
|
||||
FileConnection file = null;
|
||||
InputStream is = null;
|
||||
Image capturedImage;
|
||||
try {
|
||||
file = (FileConnection) Connector.open("file://" + path);
|
||||
is = file.openInputStream();
|
||||
capturedImage = Image.createImage(is);
|
||||
} finally {
|
||||
if (is != null) {
|
||||
try {
|
||||
is.close();
|
||||
} catch (IOException ioe) {
|
||||
// continue
|
||||
}
|
||||
}
|
||||
if (file != null) {
|
||||
try {
|
||||
file.close();
|
||||
} catch (IOException ioe) {
|
||||
// continue
|
||||
}
|
||||
}
|
||||
}
|
||||
MonochromeBitmapSource source = new LCDUIImageMonochromeBitmapSource(capturedImage);
|
||||
Reader reader = new MultiFormatReader();
|
||||
Result result = reader.decode(source);
|
||||
// If decode was successful...
|
||||
try {
|
||||
file.delete();
|
||||
} catch (IOException ioe) {
|
||||
// continue
|
||||
}
|
||||
showMessage(result.getText());
|
||||
} catch (IOException ioe) {
|
||||
showMessage(ioe.getMessage());
|
||||
} catch (ReaderException re) {
|
||||
showMessage("Sorry, no barcode was found.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -16,19 +16,29 @@
|
|||
|
||||
package com.google.zxing.client.rim;
|
||||
|
||||
import com.google.zxing.client.rim.persistence.AppSettings;
|
||||
import com.google.zxing.client.rim.persistence.history.DecodeHistory;
|
||||
import net.rim.device.api.ui.UiApplication;
|
||||
|
||||
/**
|
||||
* @author Sean Owen (srowen@google.com)
|
||||
* Starts the application with the MenuScreen screen on the stack.
|
||||
* As well, the required permissions are requested and the history and app settings are initialized.
|
||||
*
|
||||
* This code was contributed by LifeMarks.
|
||||
*
|
||||
* @author Matt York (matt@lifemarks.mobi)
|
||||
*/
|
||||
public final class ZXingUIApp extends UiApplication {
|
||||
public final class ZXingUiApplication extends UiApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
new ZXingUIApp().enterEventDispatcher();
|
||||
private ZXingUiApplication() {
|
||||
pushScreen(new ZXingLMMainScreen());
|
||||
}
|
||||
|
||||
ZXingUIApp() {
|
||||
pushScreen(new ZXingMainScreen());
|
||||
public static void main(String[] args) {
|
||||
AppPermissionsManager.setPermissions();
|
||||
DecodeHistory.getInstance();
|
||||
AppSettings.getInstance();
|
||||
new ZXingUiApplication().enterEventDispatcher();
|
||||
}
|
||||
|
||||
}
|
100
rim/src/com/google/zxing/client/rim/persistence/AppSettings.java
Normal file
100
rim/src/com/google/zxing/client/rim/persistence/AppSettings.java
Normal file
|
@ -0,0 +1,100 @@
|
|||
/*
|
||||
* Copyright 2008 ZXing authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.google.zxing.client.rim.persistence;
|
||||
|
||||
import net.rim.device.api.system.PersistentObject;
|
||||
import net.rim.device.api.system.PersistentStore;
|
||||
|
||||
import java.util.Hashtable;
|
||||
|
||||
/**
|
||||
* Singleton object that represents the persistent application settings data.
|
||||
*
|
||||
* This code was contributed by LifeMarks.
|
||||
*
|
||||
* @author Matt York (matt@lifemarks.mobi)
|
||||
*/
|
||||
public final class AppSettings {
|
||||
|
||||
public static final String SETTING_CAM_RES_MSG = "setting_cam_res_msg";
|
||||
private static final long ID_LONG = 0x92ac4e8ac35b8aa0L;
|
||||
|
||||
private static AppSettings instance;
|
||||
|
||||
private final PersistentObject store;
|
||||
private final Hashtable settingsItems;
|
||||
|
||||
private AppSettings() {
|
||||
store = PersistentStore.getPersistentObject(ID_LONG);
|
||||
Hashtable temp = (Hashtable) store.getContents();
|
||||
settingsItems = temp == null ? new Hashtable() : temp;
|
||||
}
|
||||
|
||||
public static AppSettings getInstance() {
|
||||
if (instance == null) {
|
||||
instance = new AppSettings();
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a setting object.
|
||||
*/
|
||||
public void addItem(String itemName, Object itemValue) {
|
||||
settingsItems.put(itemName, itemValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all settings objects.
|
||||
*/
|
||||
public Hashtable getItems() {
|
||||
return settingsItems;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a particular settings object by name.
|
||||
*/
|
||||
Object getItem(String itemName) {
|
||||
return settingsItems.get(itemName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a particular boolean type settings object by name.
|
||||
*/
|
||||
public Boolean getBooleanItem(String itemName) {
|
||||
Object value = getItem(itemName);
|
||||
return value instanceof Boolean ? (Boolean) value : Boolean.FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of settings.
|
||||
*/
|
||||
public int getNumItems() {
|
||||
return settingsItems.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* Persists the settings to the device.
|
||||
*/
|
||||
public void persist() {
|
||||
synchronized (store) {
|
||||
store.setContents(settingsItems);
|
||||
store.commit();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,101 @@
|
|||
/*
|
||||
* Copyright 2008 ZXing authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.google.zxing.client.rim.persistence.history;
|
||||
|
||||
import net.rim.device.api.system.PersistentObject;
|
||||
import net.rim.device.api.system.PersistentStore;
|
||||
|
||||
import java.util.Vector;
|
||||
|
||||
/**
|
||||
* Singleton used to persist the history of qrcode URLs decoded by the client.
|
||||
*
|
||||
* This code was contributed by LifeMarks.
|
||||
*
|
||||
* @author Matt York (matt@lifemarks.mobi)
|
||||
*/
|
||||
public class DecodeHistory {
|
||||
|
||||
private static final long ID_LONG = 0xb7cc76147b48ad0dL;
|
||||
|
||||
private static DecodeHistory instance;
|
||||
|
||||
private final PersistentObject store;
|
||||
private final Vector historyItems;
|
||||
|
||||
private DecodeHistory() {
|
||||
store = PersistentStore.getPersistentObject(ID_LONG);
|
||||
Vector temp = (Vector) store.getContents();
|
||||
historyItems = temp == null ? new Vector() : temp;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the single instance of this class.
|
||||
*/
|
||||
public static DecodeHistory getInstance() {
|
||||
if (instance == null) {
|
||||
instance = new DecodeHistory();
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a history object.
|
||||
*/
|
||||
public void addHistoryItem(DecodeHistoryItem item) {
|
||||
historyItems.addElement(item);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all history objects.
|
||||
*/
|
||||
public Vector getItems() {
|
||||
return historyItems;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a particular history object at a given index.
|
||||
*/
|
||||
public DecodeHistoryItem getItemAt(int index) {
|
||||
return (DecodeHistoryItem) historyItems.elementAt(index);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of history objects.
|
||||
*/
|
||||
public int getNumItems() {
|
||||
return historyItems.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears the history.
|
||||
*/
|
||||
public void clear() {
|
||||
historyItems.setSize(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Persists the history to the device.
|
||||
*/
|
||||
public void persist() {
|
||||
synchronized (store) {
|
||||
store.setContents(historyItems);
|
||||
store.commit();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,60 @@
|
|||
/*
|
||||
* Copyright 2008 ZXing authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.google.zxing.client.rim.persistence.history;
|
||||
|
||||
import net.rim.device.api.util.Persistable;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* A single decoded history item that is stored by the decode history.
|
||||
*
|
||||
* This code was contributed by LifeMarks.
|
||||
*
|
||||
* @author Matt York (matt@lifemarks.mobi)
|
||||
*/
|
||||
public final class DecodeHistoryItem implements Persistable {
|
||||
|
||||
private String date;
|
||||
private String uri;
|
||||
|
||||
private DecodeHistoryItem() {
|
||||
date = new Date().toString();
|
||||
}
|
||||
|
||||
public DecodeHistoryItem(String uri) {
|
||||
this();
|
||||
this.uri = uri;
|
||||
}
|
||||
|
||||
public void setDate(String date) {
|
||||
this.date = date;
|
||||
}
|
||||
|
||||
public String getDate() {
|
||||
return date;
|
||||
}
|
||||
|
||||
public void setURI(String uri) {
|
||||
this.uri = uri;
|
||||
}
|
||||
|
||||
public String getURI() {
|
||||
return uri;
|
||||
}
|
||||
|
||||
}
|
83
rim/src/com/google/zxing/client/rim/util/Log.java
Normal file
83
rim/src/com/google/zxing/client/rim/util/Log.java
Normal file
|
@ -0,0 +1,83 @@
|
|||
/*
|
||||
* Copyright 2008 ZXing authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.google.zxing.client.rim.util;
|
||||
|
||||
import net.rim.device.api.system.EventLogger;
|
||||
|
||||
/**
|
||||
* Used to write logging messages. When debugging, System.out is used to write to the simulator.
|
||||
* When running on a real device, the EventLogger is used. To access the event log on a real device,
|
||||
* go to the home screen, hold down ALT and type lglg.
|
||||
*
|
||||
* This code was contributed by LifeMarks.
|
||||
*
|
||||
* @author Matt York (matt@lifemarks.mobi)
|
||||
*/
|
||||
public final class Log {
|
||||
|
||||
private static final String LOG_ID_STRING = "zxing";
|
||||
private static final long LOG_ID_LONG = 0x351e9b79fd52317L;
|
||||
|
||||
/** Used to determine if the log message should be set to System.out */
|
||||
private static final boolean logToSystemOut;
|
||||
|
||||
static {
|
||||
// Initializes the logger. Currently set to not log to System.out and log
|
||||
// at the INFO level.
|
||||
EventLogger.register(LOG_ID_LONG, LOG_ID_STRING, EventLogger.VIEWER_STRING);
|
||||
EventLogger.setMinimumLevel(EventLogger.DEBUG_INFO); // set this to change logging level message.
|
||||
logToSystemOut = false; // needs to be false for deployment to blackberry device and true for debuging on simulator.
|
||||
}
|
||||
|
||||
private Log() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Logs the given message at the debug level.
|
||||
*/
|
||||
public static void debug(String message) {
|
||||
EventLogger.logEvent(LOG_ID_LONG, message.getBytes(), EventLogger.DEBUG_INFO);
|
||||
logToSystemOut(message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Logs the given message at the info level.
|
||||
*/
|
||||
public static void info(String message) {
|
||||
EventLogger.logEvent(LOG_ID_LONG, message.getBytes(), EventLogger.INFORMATION);
|
||||
logToSystemOut(message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Logs the given message at the error level.
|
||||
*/
|
||||
public static void error(String message) {
|
||||
EventLogger.logEvent(LOG_ID_LONG, message.getBytes(), EventLogger.ERROR);
|
||||
logToSystemOut(message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Logs the given message to system.out.
|
||||
* This is useful when debugging on the simulator.
|
||||
*/
|
||||
private static void logToSystemOut(String message) {
|
||||
if (logToSystemOut) {
|
||||
System.out.println(message);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,75 @@
|
|||
/*
|
||||
* Copyright 2008 ZXing authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.google.zxing.client.rim.util;
|
||||
|
||||
/**
|
||||
* Used to determine if something happend within a specified amount of time.
|
||||
* For example, if a QR code was decoded in a resonable amount of time.
|
||||
* If not, perhaps the user should lower their camera resolution.
|
||||
*
|
||||
* This code was contributed by LifeMarks.
|
||||
*
|
||||
* @author Matt York (matt@lifemarks.mobi)
|
||||
*/
|
||||
public final class ReasonableTimer {
|
||||
|
||||
// 2000 too low for qr decoding
|
||||
private static final long DEF_RESONABLE_TIME = 2500; // in ms
|
||||
|
||||
private long reasonableTime;
|
||||
private final long startTime;
|
||||
private long finishTime;
|
||||
|
||||
public ReasonableTimer() {
|
||||
startTime = System.currentTimeMillis();
|
||||
reasonableTime = DEF_RESONABLE_TIME;
|
||||
}
|
||||
|
||||
public ReasonableTimer(long reasonableTime) {
|
||||
startTime = System.currentTimeMillis();
|
||||
this.reasonableTime = reasonableTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* Stops the timing.
|
||||
*/
|
||||
public void finished() {
|
||||
finishTime = System.currentTimeMillis();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the timer finished in a reasonable amount of time.
|
||||
*/
|
||||
public boolean wasResonableTime() {
|
||||
return finishTime - startTime <= reasonableTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the reasonable time to the given time
|
||||
*/
|
||||
public void setResonableTime(long reasonableTime) {
|
||||
this.reasonableTime = reasonableTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the reasonable time.
|
||||
*/
|
||||
public long getResonableTime() {
|
||||
return reasonableTime;
|
||||
}
|
||||
|
||||
}
|
84
rim/src/com/google/zxing/client/rim/util/URLDecoder.java
Normal file
84
rim/src/com/google/zxing/client/rim/util/URLDecoder.java
Normal file
|
@ -0,0 +1,84 @@
|
|||
/*
|
||||
* Copyright 2008 ZXing authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.google.zxing.client.rim.util;
|
||||
|
||||
import java.util.Enumeration;
|
||||
import java.util.Hashtable;
|
||||
|
||||
/**
|
||||
* Used to decode URL encoded characters.
|
||||
*
|
||||
* This code was contributed by LifeMarks.
|
||||
*
|
||||
* @author Matt York (matt@lifemarks.mobi)
|
||||
*/
|
||||
public final class URLDecoder {
|
||||
|
||||
private URLDecoder() {
|
||||
}
|
||||
|
||||
private static final Hashtable decodingMap;
|
||||
static {
|
||||
decodingMap = new Hashtable(37);
|
||||
decodingMap.put("%21", "!");
|
||||
decodingMap.put("%2A", "*");
|
||||
decodingMap.put("%2a", "*");
|
||||
decodingMap.put("%27", "'");
|
||||
decodingMap.put("%28", "(");
|
||||
decodingMap.put("%29", ")");
|
||||
decodingMap.put("%3B", ";");
|
||||
decodingMap.put("%3b", ";");
|
||||
decodingMap.put("%3A", ":");
|
||||
decodingMap.put("%3a", ":");
|
||||
decodingMap.put("%40", "@");
|
||||
decodingMap.put("%26", "&");
|
||||
decodingMap.put("%3D", "=");
|
||||
decodingMap.put("%3d", "=");
|
||||
decodingMap.put("%3B", "+");
|
||||
decodingMap.put("%3b", "+");
|
||||
decodingMap.put("%24", "$");
|
||||
decodingMap.put("%2C", "`");
|
||||
decodingMap.put("%2c", "`");
|
||||
decodingMap.put("%2F", "/");
|
||||
decodingMap.put("%2f", "/");
|
||||
decodingMap.put("%3F", "?");
|
||||
decodingMap.put("%3f", "?");
|
||||
decodingMap.put("%25", "%");
|
||||
decodingMap.put("%23", "#");
|
||||
decodingMap.put("%5B", "[");
|
||||
decodingMap.put("%5b", "[");
|
||||
decodingMap.put("%5D", "]");
|
||||
decodingMap.put("%5d", "]");
|
||||
}
|
||||
|
||||
public static String decode(String uri) {
|
||||
Log.info("Original uri: " + uri);
|
||||
if (uri.indexOf('%') >= 0) { // skip this if no encoded chars
|
||||
Enumeration keys = decodingMap.keys();
|
||||
while (keys.hasMoreElements()) {
|
||||
String encodedChar = (String) keys.nextElement();
|
||||
int encodedCharIndex = uri.indexOf(encodedChar);
|
||||
while (encodedCharIndex != -1) {
|
||||
uri = uri.substring(0, encodedCharIndex) + decodingMap.get(encodedChar) + uri.substring(encodedCharIndex + encodedChar.length());
|
||||
encodedCharIndex = uri.indexOf(encodedChar, encodedCharIndex);
|
||||
}
|
||||
}
|
||||
}
|
||||
Log.info("Final URI: " + uri);
|
||||
return uri;
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue