/* * Copyright (C) 2008 ZXing authors * Copyright 2011 Robert Theis * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package edu.sfsu.cs.orange.ocr; import android.os.Handler; import android.os.Message; import android.util.Log; import android.view.Gravity; import android.widget.Toast; import com.v.mypersonaltrainer.R; import edu.sfsu.cs.orange.ocr.camera.CameraManager; /** * This class handles all the messaging which comprises the state machine for capture. * * The code for this class was adapted from the ZXing project: http://code.google.com/p/zxing/ */ final class CaptureActivityHandler extends Handler { private static final String TAG = CaptureActivityHandler.class.getSimpleName(); private final CaptureActivity activity; private final DecodeThread decodeThread; private static State state; private final CameraManager cameraManager; private enum State { PREVIEW, PREVIEW_PAUSED, CONTINUOUS, CONTINUOUS_PAUSED, SUCCESS, DONE } CaptureActivityHandler(CaptureActivity activity, CameraManager cameraManager, boolean isContinuousModeActive) { this.activity = activity; this.cameraManager = cameraManager; // Start ourselves capturing previews (and decoding if using continuous recognition mode). cameraManager.startPreview(); decodeThread = new DecodeThread(activity); decodeThread.start(); if (isContinuousModeActive) { state = State.CONTINUOUS; // Show the shutter and torch buttons activity.setButtonVisibility(true); // Display a "be patient" message while first recognition request is running activity.setStatusViewForContinuous(); restartOcrPreviewAndDecode(); } else { state = State.SUCCESS; // Show the shutter and torch buttons activity.setButtonVisibility(true); restartOcrPreview(); } } @Override public void handleMessage(Message message) { switch (message.what) { case R.id.restart_preview: restartOcrPreview(); break; case R.id.ocr_continuous_decode_failed: DecodeHandler.resetDecodeState(); try { activity.handleOcrContinuousDecode((OcrResultFailure) message.obj); } catch (NullPointerException e) { Log.w(TAG, "got bad OcrResultFailure", e); } if (state == State.CONTINUOUS) { restartOcrPreviewAndDecode(); } break; case R.id.ocr_continuous_decode_succeeded: DecodeHandler.resetDecodeState(); try { activity.handleOcrContinuousDecode((OcrResult) message.obj); } catch (NullPointerException e) { // Continue } if (state == State.CONTINUOUS) { restartOcrPreviewAndDecode(); } break; case R.id.ocr_decode_succeeded: state = State.SUCCESS; activity.setShutterButtonClickable(true); activity.handleOcrDecode((OcrResult) message.obj); break; case R.id.ocr_decode_failed: state = State.PREVIEW; activity.setShutterButtonClickable(true); Toast toast = Toast.makeText(activity.getBaseContext(), "OCR failed. Please try again.", Toast.LENGTH_SHORT); toast.setGravity(Gravity.TOP, 0, 0); toast.show(); break; } } void stop() { // TODO See if this should be done by sending a quit message to decodeHandler as is done // below in quitSynchronously(). Log.d(TAG, "Setting state to CONTINUOUS_PAUSED."); state = State.CONTINUOUS_PAUSED; removeMessages(R.id.ocr_continuous_decode); removeMessages(R.id.ocr_decode); removeMessages(R.id.ocr_continuous_decode_failed); removeMessages(R.id.ocr_continuous_decode_succeeded); // TODO are these removeMessages() calls doing anything? // Freeze the view displayed to the user. // CameraManager.get().stopPreview(); } void resetState() { //Log.d(TAG, "in restart()"); if (state == State.CONTINUOUS_PAUSED) { Log.d(TAG, "Setting state to CONTINUOUS"); state = State.CONTINUOUS; restartOcrPreviewAndDecode(); } } void quitSynchronously() { state = State.DONE; if (cameraManager != null) { cameraManager.stopPreview(); } //Message quit = Message.obtain(decodeThread.getHandler(), R.id.quit); try { //quit.sendToTarget(); // This always gives "sending message to a Handler on a dead thread" // Wait at most half a second; should be enough time, and onPause() will timeout quickly decodeThread.join(500L); } catch (InterruptedException e) { Log.w(TAG, "Caught InterruptedException in quitSyncronously()", e); // continue } catch (RuntimeException e) { Log.w(TAG, "Caught RuntimeException in quitSyncronously()", e); // continue } catch (Exception e) { Log.w(TAG, "Caught unknown Exception in quitSynchronously()", e); } // Be absolutely sure we don't send any queued up messages removeMessages(R.id.ocr_continuous_decode); removeMessages(R.id.ocr_decode); } /** * Start the preview, but don't try to OCR anything until the user presses the shutter button. */ private void restartOcrPreview() { // Display the shutter and torch buttons activity.setButtonVisibility(true); if (state == State.SUCCESS) { state = State.PREVIEW; // Draw the viewfinder. activity.drawViewfinder(); } } /** * Send a decode request for realtime OCR mode */ private void restartOcrPreviewAndDecode() { // Continue capturing camera frames cameraManager.startPreview(); // Continue requesting decode of images cameraManager.requestOcrDecode(decodeThread.getHandler(), R.id.ocr_continuous_decode); activity.drawViewfinder(); } /** * Request OCR on the current preview frame. */ private void ocrDecode() { state = State.PREVIEW_PAUSED; cameraManager.requestOcrDecode(decodeThread.getHandler(), R.id.ocr_decode); } /** * Request OCR when the hardware shutter button is clicked. */ void hardwareShutterButtonClick() { // Ensure that we're not in continuous recognition mode if (state == State.PREVIEW) { ocrDecode(); } } /** * Request OCR when the on-screen shutter button is clicked. */ void shutterButtonClick() { // Disable further clicks on this button until OCR request is finished activity.setShutterButtonClickable(false); ocrDecode(); } }