Merged revisions 321,327,330,332,334,342-343,352-353,355-358,361-363,365,372 via...
[zxing.git] / android / src / com / google / zxing / client / android / CameraThread.java
1 /*
2  * Copyright (C) 2008 Google Inc.
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       public void handleMessage(Message message) {
61         switch (message.what) {
62           case R.id.preview:
63             if (state == State.PREVIEW) {
64               surfaceView.capturePreviewAndDraw();
65             }
66             break;
67           case R.id.save:
68             state = State.SAVE;
69             Message save = Message.obtain(decodeThread.handler, R.id.save);
70             save.sendToTarget();
71             break;
72           case R.id.restart_preview:
73             restartPreviewAndDecode();
74             break;
75           case R.id.quit:
76             state = State.DONE;
77             Message quit = Message.obtain(decodeThread.handler, R.id.quit);
78             quit.sendToTarget();
79             try {
80               decodeThread.join();
81             } catch (InterruptedException e) {
82             }
83             Looper.myLooper().quit();
84             break;
85           case R.id.decode_started:
86             // Since the decoder is done with the camera, continue fetching preview frames.
87             state = State.PREVIEW;
88             break;
89           case R.id.decode_succeeded:
90             state = State.DONE;
91             // Message.copyFrom() did not work as expected, hence this workaround.
92             Message success = Message.obtain(activityHandler, R.id.decode_succeeded, message.obj);
93             success.arg1 = message.arg1;
94             success.sendToTarget();
95             break;
96           case R.id.decode_failed:
97             // We're decoding as fast as possible, so when one fails, start another.
98             startDecode();
99             break;
100           case R.id.save_succeeded:
101             // TODO: Put up a non-blocking status message
102             restartPreviewAndDecode();
103             break;
104           case R.id.save_failed:
105             // TODO: Put up a blocking error message
106             restartPreviewAndDecode();
107             break;
108         }
109
110         if (state == State.PREVIEW) {
111           Message preview = Message.obtain(handler, R.id.preview);
112           preview.sendToTarget();
113         }
114       }
115     };
116     decodeThread.setCameraThreadHandler(handler);
117
118     // Start ourselves capturing previews
119     restartPreviewAndDecode();
120     Looper.loop();
121   }
122
123   public void quitSynchronously() {
124     Message quit = Message.obtain(handler, R.id.quit);
125     quit.sendToTarget();
126     try {
127       join();
128     } catch (InterruptedException e) {
129     }
130   }
131
132   public void setDecodeAllMode() {
133     Message message = Message.obtain(decodeThread.handler, R.id.set_decode_all_mode);
134     message.sendToTarget();
135   }
136
137   public void setDecode1DMode() {
138     Message message = Message.obtain(decodeThread.handler, R.id.set_decode_1D_mode);
139     message.sendToTarget();
140   }
141
142   public void setDecodeQRMode() {
143     Message message = Message.obtain(decodeThread.handler, R.id.set_decode_QR_mode);
144     message.sendToTarget();
145   }
146
147   public void toggleTracing() {
148     Message message = Message.obtain(decodeThread.handler, R.id.toggle_tracing);
149     message.sendToTarget();
150   }
151
152   /**
153    * Start a decode if possible, but not now if the DecodeThread is in the middle of saving.
154    */
155   private void startDecode() {
156     if (state != State.SAVE) {
157       state = State.DECODE;
158       Message decode = Message.obtain(decodeThread.handler, R.id.decode);
159       decode.sendToTarget();
160     }
161   }
162
163   /**
164    * Take one preview to update the screen, then do a decode and continue previews.
165    */
166   private void restartPreviewAndDecode() {
167     state = State.PREVIEW;
168     surfaceView.capturePreviewAndDraw();
169     startDecode();
170   }
171
172 }