1/*
2 * Copyright (C) 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
17package com.google.zxing.client.android;
18
19import com.google.zxing.Result;
20import com.google.zxing.client.android.camera.CameraManager;
21
22import android.app.Activity;
23import android.content.Intent;
24import android.graphics.Bitmap;
25import android.net.Uri;
26import android.os.Bundle;
27import android.os.Handler;
28import android.os.Message;
29import android.util.Log;
30
31/**
32 * This class handles all the messaging which comprises the state machine for capture.
33 *
34 * @author dswitkin@google.com (Daniel Switkin)
35 */
36public final class CaptureActivityHandler extends Handler {
37
38  private static final String TAG = CaptureActivityHandler.class.getSimpleName();
39
40  private final CaptureActivity activity;
41  private final DecodeThread decodeThread;
42  private State state;
43  private final CameraManager cameraManager;
44
45  private enum State {
46    PREVIEW,
47    SUCCESS,
48    DONE
49  }
50
51  CaptureActivityHandler(CaptureActivity activity,
52                         String characterSet,
53                         CameraManager cameraManager) {
54    this.activity = activity;
55    decodeThread = new DecodeThread(activity, characterSet,
56        new ViewfinderResultPointCallback(activity.getViewfinderView()));
57    decodeThread.start();
58    state = State.SUCCESS;
59
60    // Start ourselves capturing previews and decoding.
61    this.cameraManager = cameraManager;
62    cameraManager.startPreview();
63    restartPreviewAndDecode();
64  }
65
66  @Override
67  public void handleMessage(Message message) {
68    if (message.what == R.id.auto_focus) {
69      //Log.d(TAG, "Got auto-focus message");
70      // When one auto focus pass finishes, start another. This is the closest thing to
71      // continuous AF. It does seem to hunt a bit, but I'm not sure what else to do.
72      if (state == State.PREVIEW) {
73        cameraManager.requestAutoFocus(this, R.id.auto_focus);
74      }
75    } else if (message.what == R.id.restart_preview) {
76      Log.d(TAG, "Got restart preview message");
77      restartPreviewAndDecode();
78    } else if (message.what == R.id.decode_succeeded) {
79      Log.d(TAG, "Got decode succeeded message");
80      state = State.SUCCESS;
81      Bundle bundle = message.getData();
82      Bitmap barcode = bundle == null ? null :
83          (Bitmap) bundle.getParcelable(DecodeThread.BARCODE_BITMAP);
84      activity.handleDecode((Result) message.obj, barcode);
85    } else if (message.what == R.id.decode_failed) {
86      // We're decoding as fast as possible, so when one decode fails, start another.
87      state = State.PREVIEW;
88      cameraManager.requestPreviewFrame(decodeThread.getHandler(), R.id.decode);
89    } else if (message.what == R.id.return_scan_result) {
90      Log.d(TAG, "Got return scan result message");
91      activity.setResult(Activity.RESULT_OK, (Intent) message.obj);
92      activity.finish();
93    } else if (message.what == R.id.launch_product_query) {
94      Log.d(TAG, "Got product query message");
95      String url = (String) message.obj;
96      Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
97      intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
98      activity.startActivity(intent);
99    }
100  }
101
102  public void quitSynchronously() {
103    state = State.DONE;
104    cameraManager.stopPreview();
105    Message quit = Message.obtain(decodeThread.getHandler(), R.id.quit);
106    quit.sendToTarget();
107    try {
108      // Wait at most half a second; should be enough time, and onPause() will timeout quickly
109      decodeThread.join(500L);
110    } catch (InterruptedException e) {
111      // continue
112    }
113
114    // Be absolutely sure we don't send any queued up messages
115    removeMessages(R.id.decode_succeeded);
116    removeMessages(R.id.decode_failed);
117  }
118
119  private void restartPreviewAndDecode() {
120    if (state == State.SUCCESS) {
121      state = State.PREVIEW;
122      cameraManager.requestPreviewFrame(decodeThread.getHandler(), R.id.decode);
123      cameraManager.requestAutoFocus(this, R.id.auto_focus);
124      activity.drawViewfinder();
125    }
126  }
127
128}
129