--- /dev/null
+/*\r
+ * Copyright 2008 ZXing authors\r
+ *\r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *\r
+ * http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+\r
+package com.google.zxing.client.rim;\r
+\r
+import com.google.zxing.client.rim.util.Log;\r
+import net.rim.blackberry.api.invoke.CameraArguments;\r
+import net.rim.blackberry.api.invoke.Invoke;\r
+import net.rim.device.api.system.Characters;\r
+import net.rim.device.api.system.EventInjector;\r
+import net.rim.device.api.ui.UiApplication;\r
+\r
+/**\r
+ * Singleton used to control access to the camera.\r
+ * Unfortunatly, the Camera API only allows invoking the camera.\r
+ * \r
+ * Note: This code still contains experimental code to determine and set the camera resolution by\r
+ * using system level key events, but didn't not function reliably and is not used.\r
+ *\r
+ * This code was contributed by LifeMarks.\r
+ *\r
+ * @author Matt York (matt@lifemarks.mobi)\r
+ */\r
+final class Camera {\r
+\r
+ /** milliseconds to wait before starting key strokes */\r
+ private static final int INITIALIZATION_TIME_MS = 500; // simulator seems to need >= 500\r
+ private static final int KEY_PAUSE_TIME_MS = 100; // simulator seems to need >= 100\r
+\r
+ private static Camera instance;\r
+\r
+ /** Attempting to set camera resolution is disabled. */\r
+ private final boolean setResolution = false;\r
+\r
+ private Camera() {\r
+ }\r
+\r
+ /**\r
+ * Returns the single instance of the camera.\r
+ */\r
+ static Camera getInstance() {\r
+ if (instance == null) {\r
+ instance = new Camera();\r
+ }\r
+ return instance;\r
+ }\r
+\r
+ /**\r
+ * Starts the blackberry camera application.\r
+ */\r
+ void invoke() {\r
+ Invoke.invokeApplication(Invoke.APP_TYPE_CAMERA, new CameraArguments());\r
+ if (setResolution) {\r
+ sleep(INITIALIZATION_TIME_MS);\r
+ setMinResolution();\r
+ }\r
+ }\r
+\r
+ /**\r
+ * Exits the blackberry camera application.\r
+ */\r
+ void exit() {\r
+ if (setResolution) {\r
+ setMaxResolution(); // for now, we dont know the original resolution setting. Assume it was max res.\r
+ sleep(KEY_PAUSE_TIME_MS);\r
+ }\r
+ sleep(3000); // this sleep is needed for the esc to be processed(3000 originally)\r
+ UiApplication app = UiApplication.getUiApplication();\r
+ if (app != null) {\r
+ Log.info("active app: " + app.getClass().getName());\r
+ if (app.isForeground()) {\r
+ Log.info("Lifemarks is the foreground app.");\r
+ } else {\r
+ Log.info("Lifemarks is not the foreground app. Attempt to close camera.");\r
+ keyUpAndDown(Characters.ESCAPE); // need two (no timeout in between esc key presses seems to work best)\r
+ keyUpAndDown(Characters.ESCAPE);\r
+ }\r
+ } else {\r
+ Log.error("??? app is null ???");\r
+ }\r
+ }\r
+\r
+ /**\r
+ * Sets the camera resolution to it's minimum.\r
+ * Note: currently disabled.\r
+ */\r
+ private static void setMaxResolution() {\r
+ Log.info("Setting resolution to max.");\r
+ accessResolutionMenuAfterSave();\r
+ sleep(KEY_PAUSE_TIME_MS);\r
+ keyUpAndDown(Characters.CONTROL_DOWN);\r
+ sleep(KEY_PAUSE_TIME_MS);\r
+ keyUpAndDown(Characters.CONTROL_DOWN); // min res\r
+ sleep(KEY_PAUSE_TIME_MS);\r
+ trackBallClick(); // out of res menu\r
+ sleep(KEY_PAUSE_TIME_MS);\r
+ trackBallClick(); // into res menu\r
+ sleep(KEY_PAUSE_TIME_MS);\r
+ keyUpAndDown(Characters.CONTROL_UP);\r
+ sleep(KEY_PAUSE_TIME_MS);\r
+ keyUpAndDown(Characters.CONTROL_UP); // max res\r
+ sleep(KEY_PAUSE_TIME_MS);\r
+ trackBallClick(); // out of res menu\r
+ sleep(KEY_PAUSE_TIME_MS);\r
+ keyUpAndDown(Characters.ESCAPE); // out of options\r
+ sleep(KEY_PAUSE_TIME_MS);\r
+ trackBallClick(); // yes to changes, even if there werent really any!\r
+ Log.info("Finished setting resolution to max.");\r
+ }\r
+\r
+ /**\r
+ * Sets the camera resolution to it's maximum.\r
+ * Note: currently disabled.\r
+ */\r
+ private static void setMinResolution() {\r
+ Log.info("Setting resolution to min.");\r
+ accessResolutionMenu();\r
+ sleep(KEY_PAUSE_TIME_MS);\r
+ keyUpAndDown(Characters.CONTROL_UP);\r
+ sleep(KEY_PAUSE_TIME_MS);\r
+ keyUpAndDown(Characters.CONTROL_UP); // max res\r
+ sleep(KEY_PAUSE_TIME_MS);\r
+ trackBallClick(); // out of res menu\r
+ sleep(KEY_PAUSE_TIME_MS);\r
+ trackBallClick(); // into res menu\r
+ sleep(KEY_PAUSE_TIME_MS);\r
+ keyUpAndDown(Characters.CONTROL_DOWN);\r
+ sleep(KEY_PAUSE_TIME_MS);\r
+ keyUpAndDown(Characters.CONTROL_DOWN); // min res\r
+ sleep(KEY_PAUSE_TIME_MS);\r
+ trackBallClick(); // out of res menu\r
+ sleep(KEY_PAUSE_TIME_MS);\r
+ keyUpAndDown(Characters.ESCAPE); // out of options\r
+ trackBallClick(); // yes to changes, even if there werent really any!\r
+ }\r
+\r
+ private static void accessResolutionMenu() {\r
+ keyUpAndDown(Characters.CONTROL_MENU);\r
+ sleep(KEY_PAUSE_TIME_MS);\r
+ keyUpAndDown(Characters.CONTROL_DOWN);\r
+ sleep(KEY_PAUSE_TIME_MS);\r
+ trackBallClick();\r
+ sleep(KEY_PAUSE_TIME_MS);\r
+ keyUpAndDown(Characters.CONTROL_DOWN);\r
+ sleep(KEY_PAUSE_TIME_MS);\r
+ keyUpAndDown(Characters.CONTROL_DOWN);\r
+ sleep(KEY_PAUSE_TIME_MS);\r
+ trackBallClick();\r
+ }\r
+\r
+ private static void accessResolutionMenuAfterSave() {\r
+ keyUpAndDown(Characters.CONTROL_MENU);\r
+ keyUpAndDown(Characters.CONTROL_DOWN, 6, 0); // seems to be down 6 items on bb and 4 on simulator\r
+ trackBallClick();\r
+ keyUpAndDown(Characters.CONTROL_DOWN);\r
+ keyUpAndDown(Characters.CONTROL_DOWN);\r
+ trackBallClick();\r
+ }\r
+\r
+ /**\r
+ * Puts the current thread to sleep for a given amount of time.\r
+ */\r
+ private static void sleep(int time) {\r
+ try {\r
+ Thread.sleep(time);\r
+ } catch (InterruptedException ie) {\r
+ // continue\r
+ }\r
+ }\r
+\r
+\r
+ private static void trackBallClick() {\r
+ EventInjector.invokeEvent(\r
+ new EventInjector.NavigationEvent(EventInjector.NavigationEvent.NAVIGATION_CLICK, 0, 0, 1));\r
+ EventInjector.invokeEvent(\r
+ new EventInjector.NavigationEvent(EventInjector.NavigationEvent.NAVIGATION_UNCLICK, 0, 0, 1));\r
+ }\r
+\r
+ /**\r
+ * Sends system level key events a given number of times with the given delay between them.\r
+ */\r
+ private static void keyUpAndDown(char character, int times, int delay) {\r
+ for (int i = 0; i < times; i++) {\r
+ keyUpAndDown(character);\r
+ if (delay > 0) {\r
+ sleep(delay);\r
+ }\r
+ }\r
+ }\r
+\r
+ /**\r
+ * Sends one system level key event.\r
+ */\r
+ private static void keyUpAndDown(char character) {\r
+ EventInjector.invokeEvent(new EventInjector.KeyEvent(EventInjector.KeyEvent.KEY_DOWN, character, 0, 1));\r
+ EventInjector.invokeEvent(new EventInjector.KeyEvent(EventInjector.KeyEvent.KEY_UP, character, 0, 1));\r
+ }\r
+\r
+}\r
+\r