Standardize and update all copyright statements to name "ZXing authors" as suggested...
[zxing.git] / android / src / com / google / zxing / client / android / CameraThread.java
1 /*
2  * Copyright 2008 ZXing authors
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 package com.google.zxing.client.android;
18
19 import android.os.Handler;
20 import android.os.Looper;
21 import android.os.Message;
22
23 /**
24  * This thread continuously pulls preview frames from the camera and draws them to the screen. It
25  * also asks the DecodeThread to process as many images as it can keep up with, and coordinates with
26  * the main thread to display the results.
27  *
28  * @author dswitkin@google.com (Daniel Switkin)
29  */
30 final class CameraThread extends Thread {
31
32   public Handler handler;
33
34   private final CameraSurfaceView surfaceView;
35   private final Handler activityHandler;
36   private final DecodeThread decodeThread;
37   private State state;
38
39   private enum State {
40     PREVIEW,
41     DECODE,
42     SAVE,
43     DONE
44   }
45
46   CameraThread(BarcodeReaderCaptureActivity activity, CameraSurfaceView surfaceView,
47                CameraManager cameraManager, Handler activityHandler) {
48     this.surfaceView = surfaceView;
49     this.activityHandler = activityHandler;
50
51     decodeThread = new DecodeThread(activity, cameraManager);
52     decodeThread.start();
53     state = State.DONE;
54   }
55
56   @Override
57   public void run() {
58     Looper.prepare();
59     handler = new Handler() {
60       @Override
61       public void handleMessage(Message message) {
62         switch (message.what) {
63           case R.id.preview:
64             if (state == State.PREVIEW) {
65               surfaceView.capturePreviewAndDraw();
66             }
67             break;
68           case R.id.save:
69             state = State.SAVE;
70             Message save = Message.obtain(decodeThread.handler, R.id.save);
71             save.sendToTarget();
72             break;
73           case R.id.restart_preview:
74             restartPreviewAndDecode();
75             break;
76           case R.id.quit:
77             state = State.DONE;
78             Message quit = Message.obtain(decodeThread.handler, R.id.quit);
79             quit.sendToTarget();
80             try {
81               decodeThread.join();
82             } catch (InterruptedException e) {
83             }
84             Looper.myLooper().quit();
85             break;
86           case R.id.decode_started:
87             // Since the decoder is done with the camera, continue fetching preview frames.
88             state = State.PREVIEW;
89             break;
90           case R.id.decode_succeeded:
91             state = State.DONE;
92             // Message.copyFrom() did not work as expected, hence this workaround.
93             Message success = Message.obtain(activityHandler, R.id.decode_succeeded, message.obj);
94             success.arg1 = message.arg1;
95             success.sendToTarget();
96             break;
97           case R.id.decode_failed:
98             // We're decoding as fast as possible, so when one fails, start another.
99             startDecode();
100             break;
101           case R.id.save_succeeded:
102             // TODO: Put up a non-blocking status message
103             restartPreviewAndDecode();
104             break;
105           case R.id.save_failed:
106             // TODO: Put up a blocking error message
107             restartPreviewAndDecode();
108             break;
109         }
110
111         if (state == State.PREVIEW) {
112           Message preview = Message.obtain(handler, R.id.preview);
113           preview.sendToTarget();
114         }
115       }
116     };
117     decodeThread.setCameraThreadHandler(handler);
118
119     // Start ourselves capturing previews
120     restartPreviewAndDecode();
121     Looper.loop();
122   }
123
124   public void quitSynchronously() {
125     Message quit = Message.obtain(handler, R.id.quit);
126     quit.sendToTarget();
127     try {
128       join();
129     } catch (InterruptedException e) {
130     }
131   }
132
133   public void setDecodeAllMode() {
134     Message message = Message.obtain(decodeThread.handler, R.id.set_decode_all_mode);
135     message.sendToTarget();
136   }
137
138   public void setDecode1DMode() {
139     Message message = Message.obtain(decodeThread.handler, R.id.set_decode_1D_mode);
140     message.sendToTarget();
141   }
142
143   public void setDecodeQRMode() {
144     Message message = Message.obtain(decodeThread.handler, R.id.set_decode_QR_mode);
145     message.sendToTarget();
146   }
147
148   public void toggleTracing() {
149     Message message = Message.obtain(decodeThread.handler, R.id.toggle_tracing);
150     message.sendToTarget();
151   }
152
153   /**
154    * Start a decode if possible, but not now if the DecodeThread is in the middle of saving.
155    */
156   private void startDecode() {
157     if (state != State.SAVE) {
158       state = State.DECODE;
159       Message decode = Message.obtain(decodeThread.handler, R.id.decode);
160       decode.sendToTarget();
161     }
162   }
163
164   /**
165    * Take one preview to update the screen, then do a decode and continue previews.
166    */
167   private void restartPreviewAndDecode() {
168     state = State.PREVIEW;
169     surfaceView.capturePreviewAndDraw();
170     startDecode();
171   }
172
173 }