2 * Copyright (C) 2014 ZXing authors
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 package cz.cvut.fel.dce.barcodescanner;
19 import android.hardware.Camera;
20 import android.os.Handler;
21 import android.os.Looper;
22 import android.os.Message;
23 import android.util.Log;
25 import com.google.zxing.BarcodeFormat;
26 import com.google.zxing.BinaryBitmap;
27 import com.google.zxing.DecodeHintType;
28 import com.google.zxing.MultiFormatReader;
29 import com.google.zxing.PlanarYUVLuminanceSource;
30 import com.google.zxing.ReaderException;
31 import com.google.zxing.Result;
32 import com.google.zxing.common.HybridBinarizer;
34 import java.util.Arrays;
35 import java.util.EnumMap;
37 import java.util.concurrent.CountDownLatch;
42 final class DecodeRunnable implements Runnable, Camera.PreviewCallback {
44 private static final String TAG = DecodeRunnable.class.getSimpleName();
46 private final CaptureActivity activity;
47 private final Camera camera;
48 private final int height;
49 private final int width;
50 private final byte[] previewBuffer;
51 private boolean running;
52 private Handler handler;
53 private final CountDownLatch handlerInitLatch;
55 DecodeRunnable(CaptureActivity activity, Camera camera) {
56 this.activity = activity;
58 Camera.Parameters parameters = camera.getParameters();
59 Camera.Size previewSize = parameters.getPreviewSize();
60 height = previewSize.height;
61 width = previewSize.width;
62 previewBuffer = new byte[(height * width * 3) / 2];
64 handlerInitLatch = new CountDownLatch(1);
67 private Handler getHandler() {
69 handlerInitLatch.await();
70 } catch (InterruptedException ie) {
80 handler = new DecodeHandler();
81 handlerInitLatch.countDown();
85 void startScanning() {
86 getHandler().obtainMessage(R.id.decode_start).sendToTarget();
90 getHandler().obtainMessage(R.id.quit).sendToTarget();
94 public void onPreviewFrame(byte[] data, Camera camera) {
96 getHandler().obtainMessage(R.id.decode, data).sendToTarget();
100 private final class DecodeHandler extends Handler {
102 private final Map<DecodeHintType,Object> hints;
105 hints = new EnumMap<>(DecodeHintType.class);
106 hints.put(DecodeHintType.POSSIBLE_FORMATS,
107 Arrays.asList(BarcodeFormat.AZTEC, BarcodeFormat.QR_CODE, BarcodeFormat.DATA_MATRIX));
111 public void handleMessage(Message message) {
115 switch (message.what) {
116 case R.id.decode_start:
117 camera.setPreviewCallbackWithBuffer(DecodeRunnable.this);
118 camera.addCallbackBuffer(previewBuffer);
121 decode((byte[]) message.obj);
123 case R.id.decode_succeeded:
124 final Result result = (Result) message.obj;
125 activity.runOnUiThread(new Runnable() {
128 activity.setResult(result);
132 case R.id.decode_failed:
133 camera.addCallbackBuffer(previewBuffer);
137 Looper.myLooper().quit();
142 private void decode(byte[] data) {
143 Result rawResult = null;
145 int subtendedWidth = width / CameraConfigurationManager.ZOOM;
146 int subtendedHeight = height / CameraConfigurationManager.ZOOM;
147 int excessWidth = width - subtendedWidth;
148 int excessHeight = height - subtendedHeight;
150 //long start = System.currentTimeMillis();
151 PlanarYUVLuminanceSource source =
152 new PlanarYUVLuminanceSource(data,
154 excessWidth / 2, excessHeight / 2,
155 subtendedWidth, subtendedHeight,
157 BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source));
159 rawResult = new MultiFormatReader().decode(bitmap, hints);
160 } catch (ReaderException re) {
164 //long end = System.currentTimeMillis();
165 //Log.i(TAG, "Decode in " + (end - start));
166 Handler handler = getHandler();
168 if (rawResult == null) {
169 message = handler.obtainMessage(R.id.decode_failed);
171 Log.i(TAG, "Decode succeeded: " + rawResult.getText());
172 message = handler.obtainMessage(R.id.decode_succeeded, rawResult);
174 message.sendToTarget();