Issue 548, delete() before close() on FileConnection
[zxing.git] / rim / src / com / google / zxing / client / rim / Camera.java
1 /*\r
2  * Copyright 2008 ZXing authors\r
3  *\r
4  * Licensed under the Apache License, Version 2.0 (the "License");\r
5  * you may not use this file except in compliance with the License.\r
6  * You may obtain a copy of the License at\r
7  *\r
8  *      http://www.apache.org/licenses/LICENSE-2.0\r
9  *\r
10  * Unless required by applicable law or agreed to in writing, software\r
11  * distributed under the License is distributed on an "AS IS" BASIS,\r
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
13  * See the License for the specific language governing permissions and\r
14  * limitations under the License.\r
15  */\r
16 \r
17 package com.google.zxing.client.rim;\r
18 \r
19 import com.google.zxing.client.rim.util.Log;\r
20 import net.rim.blackberry.api.invoke.CameraArguments;\r
21 import net.rim.blackberry.api.invoke.Invoke;\r
22 import net.rim.device.api.system.Characters;\r
23 import net.rim.device.api.system.EventInjector;\r
24 import net.rim.device.api.ui.UiApplication;\r
25 \r
26 /**\r
27  * Singleton used to control access to the camera.\r
28  * Unfortunatly, the Camera API only allows invoking the camera.\r
29  * \r
30  * Note: This code still contains experimental code to determine and set the camera resolution by\r
31  * using system level key events, but didn't not function reliably and is not used.\r
32  *\r
33  * This code was contributed by LifeMarks.\r
34  *\r
35  * @author Matt York (matt@lifemarks.mobi)\r
36  */\r
37 final class Camera {\r
38 \r
39   /** milliseconds to wait before starting key strokes */\r
40   private static final int INITIALIZATION_TIME_MS = 500; // simulator seems to need >= 500\r
41   private static final int KEY_PAUSE_TIME_MS = 100; // simulator seems to need >= 100\r
42 \r
43   private static Camera instance;\r
44 \r
45   /** Attempting to set camera resolution is disabled. */\r
46   private final boolean setResolution = false;\r
47 \r
48   private Camera() {\r
49   }\r
50 \r
51   /**\r
52    * Returns the single instance of the camera.\r
53    */\r
54   static Camera getInstance() {\r
55     if (instance == null) {\r
56       instance = new Camera();\r
57     }\r
58     return instance;\r
59   }\r
60 \r
61   /**\r
62    * Starts the blackberry camera application.\r
63    */\r
64   void invoke() {\r
65     Invoke.invokeApplication(Invoke.APP_TYPE_CAMERA, new CameraArguments());\r
66     if (setResolution) {\r
67       sleep(INITIALIZATION_TIME_MS);\r
68       setMinResolution();\r
69     }\r
70   }\r
71 \r
72   /**\r
73    * Exits the blackberry camera application.\r
74    */\r
75   void exit() {\r
76     if (setResolution) {\r
77       setMaxResolution(); // for now, we dont know the original resolution setting. Assume it was max res.\r
78       sleep(KEY_PAUSE_TIME_MS);\r
79     }\r
80     sleep(3000); // this sleep is needed for the esc to be processed(3000 originally)\r
81     UiApplication app = UiApplication.getUiApplication();\r
82     if (app != null) {\r
83       Log.info("active app: " + app.getClass().getName());\r
84       if (app.isForeground()) {\r
85         Log.info("Lifemarks is the foreground app.");\r
86       } else {\r
87         Log.info("Lifemarks is not the foreground app. Attempt to close camera.");\r
88         keyUpAndDown(Characters.ESCAPE); // need two (no timeout in between esc key presses seems to work best)\r
89         keyUpAndDown(Characters.ESCAPE);\r
90       }\r
91     } else {\r
92       Log.error("??? app is null ???");\r
93     }\r
94   }\r
95 \r
96   /**\r
97    * Sets the camera resolution to it's minimum.\r
98    * Note: currently disabled.\r
99    */\r
100   private static void setMaxResolution() {\r
101     Log.info("Setting resolution to max.");\r
102     accessResolutionMenuAfterSave();\r
103     sleep(KEY_PAUSE_TIME_MS);\r
104     keyUpAndDown(Characters.CONTROL_DOWN);\r
105     sleep(KEY_PAUSE_TIME_MS);\r
106     keyUpAndDown(Characters.CONTROL_DOWN); // min res\r
107     sleep(KEY_PAUSE_TIME_MS);\r
108     trackBallClick(); // out of res menu\r
109     sleep(KEY_PAUSE_TIME_MS);\r
110     trackBallClick(); // into res menu\r
111     sleep(KEY_PAUSE_TIME_MS);\r
112     keyUpAndDown(Characters.CONTROL_UP);\r
113     sleep(KEY_PAUSE_TIME_MS);\r
114     keyUpAndDown(Characters.CONTROL_UP); // max res\r
115     sleep(KEY_PAUSE_TIME_MS);\r
116     trackBallClick(); // out of res menu\r
117     sleep(KEY_PAUSE_TIME_MS);\r
118     keyUpAndDown(Characters.ESCAPE); // out of options\r
119     sleep(KEY_PAUSE_TIME_MS);\r
120     trackBallClick(); // yes to changes, even if there werent really any!\r
121     Log.info("Finished setting resolution to max.");\r
122   }\r
123 \r
124   /**\r
125    * Sets the camera resolution to it's maximum.\r
126    * Note: currently disabled.\r
127    */\r
128   private static void setMinResolution() {\r
129     Log.info("Setting resolution to min.");\r
130     accessResolutionMenu();\r
131     sleep(KEY_PAUSE_TIME_MS);\r
132     keyUpAndDown(Characters.CONTROL_UP);\r
133     sleep(KEY_PAUSE_TIME_MS);\r
134     keyUpAndDown(Characters.CONTROL_UP); // max res\r
135     sleep(KEY_PAUSE_TIME_MS);\r
136     trackBallClick(); // out of res menu\r
137     sleep(KEY_PAUSE_TIME_MS);\r
138     trackBallClick(); // into res menu\r
139     sleep(KEY_PAUSE_TIME_MS);\r
140     keyUpAndDown(Characters.CONTROL_DOWN);\r
141     sleep(KEY_PAUSE_TIME_MS);\r
142     keyUpAndDown(Characters.CONTROL_DOWN); // min res\r
143     sleep(KEY_PAUSE_TIME_MS);\r
144     trackBallClick(); // out of res menu\r
145     sleep(KEY_PAUSE_TIME_MS);\r
146     keyUpAndDown(Characters.ESCAPE); // out of options\r
147     trackBallClick(); // yes to changes, even if there werent really any!\r
148   }\r
149 \r
150   private static void accessResolutionMenu() {\r
151     keyUpAndDown(Characters.CONTROL_MENU);\r
152     sleep(KEY_PAUSE_TIME_MS);\r
153     keyUpAndDown(Characters.CONTROL_DOWN);\r
154     sleep(KEY_PAUSE_TIME_MS);\r
155     trackBallClick();\r
156     sleep(KEY_PAUSE_TIME_MS);\r
157     keyUpAndDown(Characters.CONTROL_DOWN);\r
158     sleep(KEY_PAUSE_TIME_MS);\r
159     keyUpAndDown(Characters.CONTROL_DOWN);\r
160     sleep(KEY_PAUSE_TIME_MS);\r
161     trackBallClick();\r
162   }\r
163 \r
164   private static void accessResolutionMenuAfterSave() {\r
165     keyUpAndDown(Characters.CONTROL_MENU);\r
166     keyUpAndDown(Characters.CONTROL_DOWN, 6, 0); // seems to be down 6 items on bb and 4 on simulator\r
167     trackBallClick();\r
168     keyUpAndDown(Characters.CONTROL_DOWN);\r
169     keyUpAndDown(Characters.CONTROL_DOWN);\r
170     trackBallClick();\r
171   }\r
172 \r
173   /**\r
174    * Puts the current thread to sleep for a given amount of time.\r
175    */\r
176   private static void sleep(int time) {\r
177     try {\r
178       Thread.sleep(time);\r
179     } catch (InterruptedException ie) {\r
180       // continue\r
181     }\r
182   }\r
183 \r
184 \r
185   private static void trackBallClick() {\r
186     EventInjector.invokeEvent(\r
187             new EventInjector.NavigationEvent(EventInjector.NavigationEvent.NAVIGATION_CLICK, 0, 0, 1));\r
188     EventInjector.invokeEvent(\r
189             new EventInjector.NavigationEvent(EventInjector.NavigationEvent.NAVIGATION_UNCLICK, 0, 0, 1));\r
190   }\r
191 \r
192   /**\r
193    * Sends system level key events a given number of times with the given delay between them.\r
194    */\r
195   private static void keyUpAndDown(char character, int times, int delay) {\r
196     for (int i = 0; i < times; i++) {\r
197       keyUpAndDown(character);\r
198       if (delay > 0) {\r
199         sleep(delay);\r
200       }\r
201     }\r
202   }\r
203 \r
204   /**\r
205    * Sends one system level key event.\r
206    */\r
207   private static void keyUpAndDown(char character) {\r
208     EventInjector.invokeEvent(new EventInjector.KeyEvent(EventInjector.KeyEvent.KEY_DOWN, character, 0, 1));\r
209     EventInjector.invokeEvent(new EventInjector.KeyEvent(EventInjector.KeyEvent.KEY_UP, character, 0, 1));\r
210   }\r
211 \r
212 }\r
213 \r