17620644768ffc235607b3a94671e49518c18686fBryan Mawhinney/*
27620644768ffc235607b3a94671e49518c18686fBryan Mawhinney * Copyright (C) 2008 ZXing authors
37620644768ffc235607b3a94671e49518c18686fBryan Mawhinney *
47620644768ffc235607b3a94671e49518c18686fBryan Mawhinney * Licensed under the Apache License, Version 2.0 (the "License");
57620644768ffc235607b3a94671e49518c18686fBryan Mawhinney * you may not use this file except in compliance with the License.
67620644768ffc235607b3a94671e49518c18686fBryan Mawhinney * You may obtain a copy of the License at
77620644768ffc235607b3a94671e49518c18686fBryan Mawhinney *
87620644768ffc235607b3a94671e49518c18686fBryan Mawhinney *      http://www.apache.org/licenses/LICENSE-2.0
97620644768ffc235607b3a94671e49518c18686fBryan Mawhinney *
107620644768ffc235607b3a94671e49518c18686fBryan Mawhinney * Unless required by applicable law or agreed to in writing, software
117620644768ffc235607b3a94671e49518c18686fBryan Mawhinney * distributed under the License is distributed on an "AS IS" BASIS,
127620644768ffc235607b3a94671e49518c18686fBryan Mawhinney * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
137620644768ffc235607b3a94671e49518c18686fBryan Mawhinney * See the License for the specific language governing permissions and
147620644768ffc235607b3a94671e49518c18686fBryan Mawhinney * limitations under the License.
157620644768ffc235607b3a94671e49518c18686fBryan Mawhinney */
167620644768ffc235607b3a94671e49518c18686fBryan Mawhinney
177620644768ffc235607b3a94671e49518c18686fBryan Mawhinneypackage com.google.zxing.client.android;
187620644768ffc235607b3a94671e49518c18686fBryan Mawhinney
197620644768ffc235607b3a94671e49518c18686fBryan Mawhinneyimport com.google.zxing.Result;
207620644768ffc235607b3a94671e49518c18686fBryan Mawhinneyimport com.google.zxing.client.android.camera.CameraManager;
217620644768ffc235607b3a94671e49518c18686fBryan Mawhinney
227620644768ffc235607b3a94671e49518c18686fBryan Mawhinneyimport android.app.Activity;
237620644768ffc235607b3a94671e49518c18686fBryan Mawhinneyimport android.content.Intent;
247620644768ffc235607b3a94671e49518c18686fBryan Mawhinneyimport android.graphics.Bitmap;
257620644768ffc235607b3a94671e49518c18686fBryan Mawhinneyimport android.net.Uri;
267620644768ffc235607b3a94671e49518c18686fBryan Mawhinneyimport android.os.Bundle;
277620644768ffc235607b3a94671e49518c18686fBryan Mawhinneyimport android.os.Handler;
287620644768ffc235607b3a94671e49518c18686fBryan Mawhinneyimport android.os.Message;
297620644768ffc235607b3a94671e49518c18686fBryan Mawhinneyimport android.util.Log;
307620644768ffc235607b3a94671e49518c18686fBryan Mawhinney
317620644768ffc235607b3a94671e49518c18686fBryan Mawhinney/**
327620644768ffc235607b3a94671e49518c18686fBryan Mawhinney * This class handles all the messaging which comprises the state machine for capture.
337620644768ffc235607b3a94671e49518c18686fBryan Mawhinney *
347620644768ffc235607b3a94671e49518c18686fBryan Mawhinney * @author dswitkin@google.com (Daniel Switkin)
357620644768ffc235607b3a94671e49518c18686fBryan Mawhinney */
367620644768ffc235607b3a94671e49518c18686fBryan Mawhinneypublic final class CaptureActivityHandler extends Handler {
377620644768ffc235607b3a94671e49518c18686fBryan Mawhinney
387620644768ffc235607b3a94671e49518c18686fBryan Mawhinney  private static final String TAG = CaptureActivityHandler.class.getSimpleName();
397620644768ffc235607b3a94671e49518c18686fBryan Mawhinney
407620644768ffc235607b3a94671e49518c18686fBryan Mawhinney  private final CaptureActivity activity;
417620644768ffc235607b3a94671e49518c18686fBryan Mawhinney  private final DecodeThread decodeThread;
427620644768ffc235607b3a94671e49518c18686fBryan Mawhinney  private State state;
437620644768ffc235607b3a94671e49518c18686fBryan Mawhinney  private final CameraManager cameraManager;
447620644768ffc235607b3a94671e49518c18686fBryan Mawhinney
457620644768ffc235607b3a94671e49518c18686fBryan Mawhinney  private enum State {
467620644768ffc235607b3a94671e49518c18686fBryan Mawhinney    PREVIEW,
477620644768ffc235607b3a94671e49518c18686fBryan Mawhinney    SUCCESS,
487620644768ffc235607b3a94671e49518c18686fBryan Mawhinney    DONE
497620644768ffc235607b3a94671e49518c18686fBryan Mawhinney  }
507620644768ffc235607b3a94671e49518c18686fBryan Mawhinney
517620644768ffc235607b3a94671e49518c18686fBryan Mawhinney  CaptureActivityHandler(CaptureActivity activity,
527620644768ffc235607b3a94671e49518c18686fBryan Mawhinney                         String characterSet,
537620644768ffc235607b3a94671e49518c18686fBryan Mawhinney                         CameraManager cameraManager) {
547620644768ffc235607b3a94671e49518c18686fBryan Mawhinney    this.activity = activity;
557620644768ffc235607b3a94671e49518c18686fBryan Mawhinney    decodeThread = new DecodeThread(activity, characterSet,
567620644768ffc235607b3a94671e49518c18686fBryan Mawhinney        new ViewfinderResultPointCallback(activity.getViewfinderView()));
577620644768ffc235607b3a94671e49518c18686fBryan Mawhinney    decodeThread.start();
587620644768ffc235607b3a94671e49518c18686fBryan Mawhinney    state = State.SUCCESS;
597620644768ffc235607b3a94671e49518c18686fBryan Mawhinney
607620644768ffc235607b3a94671e49518c18686fBryan Mawhinney    // Start ourselves capturing previews and decoding.
617620644768ffc235607b3a94671e49518c18686fBryan Mawhinney    this.cameraManager = cameraManager;
627620644768ffc235607b3a94671e49518c18686fBryan Mawhinney    cameraManager.startPreview();
637620644768ffc235607b3a94671e49518c18686fBryan Mawhinney    restartPreviewAndDecode();
647620644768ffc235607b3a94671e49518c18686fBryan Mawhinney  }
657620644768ffc235607b3a94671e49518c18686fBryan Mawhinney
667620644768ffc235607b3a94671e49518c18686fBryan Mawhinney  @Override
677620644768ffc235607b3a94671e49518c18686fBryan Mawhinney  public void handleMessage(Message message) {
687620644768ffc235607b3a94671e49518c18686fBryan Mawhinney    if (message.what == R.id.auto_focus) {
697620644768ffc235607b3a94671e49518c18686fBryan Mawhinney      //Log.d(TAG, "Got auto-focus message");
707620644768ffc235607b3a94671e49518c18686fBryan Mawhinney      // When one auto focus pass finishes, start another. This is the closest thing to
717620644768ffc235607b3a94671e49518c18686fBryan Mawhinney      // continuous AF. It does seem to hunt a bit, but I'm not sure what else to do.
727620644768ffc235607b3a94671e49518c18686fBryan Mawhinney      if (state == State.PREVIEW) {
737620644768ffc235607b3a94671e49518c18686fBryan Mawhinney        cameraManager.requestAutoFocus(this, R.id.auto_focus);
747620644768ffc235607b3a94671e49518c18686fBryan Mawhinney      }
757620644768ffc235607b3a94671e49518c18686fBryan Mawhinney    } else if (message.what == R.id.restart_preview) {
767620644768ffc235607b3a94671e49518c18686fBryan Mawhinney      Log.d(TAG, "Got restart preview message");
777620644768ffc235607b3a94671e49518c18686fBryan Mawhinney      restartPreviewAndDecode();
787620644768ffc235607b3a94671e49518c18686fBryan Mawhinney    } else if (message.what == R.id.decode_succeeded) {
797620644768ffc235607b3a94671e49518c18686fBryan Mawhinney      Log.d(TAG, "Got decode succeeded message");
807620644768ffc235607b3a94671e49518c18686fBryan Mawhinney      state = State.SUCCESS;
817620644768ffc235607b3a94671e49518c18686fBryan Mawhinney      Bundle bundle = message.getData();
827620644768ffc235607b3a94671e49518c18686fBryan Mawhinney      Bitmap barcode = bundle == null ? null :
837620644768ffc235607b3a94671e49518c18686fBryan Mawhinney          (Bitmap) bundle.getParcelable(DecodeThread.BARCODE_BITMAP);
847620644768ffc235607b3a94671e49518c18686fBryan Mawhinney      activity.handleDecode((Result) message.obj, barcode);
857620644768ffc235607b3a94671e49518c18686fBryan Mawhinney    } else if (message.what == R.id.decode_failed) {
867620644768ffc235607b3a94671e49518c18686fBryan Mawhinney      // We're decoding as fast as possible, so when one decode fails, start another.
877620644768ffc235607b3a94671e49518c18686fBryan Mawhinney      state = State.PREVIEW;
887620644768ffc235607b3a94671e49518c18686fBryan Mawhinney      cameraManager.requestPreviewFrame(decodeThread.getHandler(), R.id.decode);
897620644768ffc235607b3a94671e49518c18686fBryan Mawhinney    } else if (message.what == R.id.return_scan_result) {
907620644768ffc235607b3a94671e49518c18686fBryan Mawhinney      Log.d(TAG, "Got return scan result message");
917620644768ffc235607b3a94671e49518c18686fBryan Mawhinney      activity.setResult(Activity.RESULT_OK, (Intent) message.obj);
927620644768ffc235607b3a94671e49518c18686fBryan Mawhinney      activity.finish();
937620644768ffc235607b3a94671e49518c18686fBryan Mawhinney    } else if (message.what == R.id.launch_product_query) {
947620644768ffc235607b3a94671e49518c18686fBryan Mawhinney      Log.d(TAG, "Got product query message");
957620644768ffc235607b3a94671e49518c18686fBryan Mawhinney      String url = (String) message.obj;
967620644768ffc235607b3a94671e49518c18686fBryan Mawhinney      Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
977620644768ffc235607b3a94671e49518c18686fBryan Mawhinney      intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
987620644768ffc235607b3a94671e49518c18686fBryan Mawhinney      activity.startActivity(intent);
997620644768ffc235607b3a94671e49518c18686fBryan Mawhinney    }
1007620644768ffc235607b3a94671e49518c18686fBryan Mawhinney  }
1017620644768ffc235607b3a94671e49518c18686fBryan Mawhinney
1027620644768ffc235607b3a94671e49518c18686fBryan Mawhinney  public void quitSynchronously() {
1037620644768ffc235607b3a94671e49518c18686fBryan Mawhinney    state = State.DONE;
1047620644768ffc235607b3a94671e49518c18686fBryan Mawhinney    cameraManager.stopPreview();
1057620644768ffc235607b3a94671e49518c18686fBryan Mawhinney    Message quit = Message.obtain(decodeThread.getHandler(), R.id.quit);
1067620644768ffc235607b3a94671e49518c18686fBryan Mawhinney    quit.sendToTarget();
1077620644768ffc235607b3a94671e49518c18686fBryan Mawhinney    try {
1087620644768ffc235607b3a94671e49518c18686fBryan Mawhinney      // Wait at most half a second; should be enough time, and onPause() will timeout quickly
1097620644768ffc235607b3a94671e49518c18686fBryan Mawhinney      decodeThread.join(500L);
1107620644768ffc235607b3a94671e49518c18686fBryan Mawhinney    } catch (InterruptedException e) {
1117620644768ffc235607b3a94671e49518c18686fBryan Mawhinney      // continue
1127620644768ffc235607b3a94671e49518c18686fBryan Mawhinney    }
1137620644768ffc235607b3a94671e49518c18686fBryan Mawhinney
1147620644768ffc235607b3a94671e49518c18686fBryan Mawhinney    // Be absolutely sure we don't send any queued up messages
1157620644768ffc235607b3a94671e49518c18686fBryan Mawhinney    removeMessages(R.id.decode_succeeded);
1167620644768ffc235607b3a94671e49518c18686fBryan Mawhinney    removeMessages(R.id.decode_failed);
1177620644768ffc235607b3a94671e49518c18686fBryan Mawhinney  }
1187620644768ffc235607b3a94671e49518c18686fBryan Mawhinney
1197620644768ffc235607b3a94671e49518c18686fBryan Mawhinney  private void restartPreviewAndDecode() {
1207620644768ffc235607b3a94671e49518c18686fBryan Mawhinney    if (state == State.SUCCESS) {
1217620644768ffc235607b3a94671e49518c18686fBryan Mawhinney      state = State.PREVIEW;
1227620644768ffc235607b3a94671e49518c18686fBryan Mawhinney      cameraManager.requestPreviewFrame(decodeThread.getHandler(), R.id.decode);
1237620644768ffc235607b3a94671e49518c18686fBryan Mawhinney      cameraManager.requestAutoFocus(this, R.id.auto_focus);
1247620644768ffc235607b3a94671e49518c18686fBryan Mawhinney      activity.drawViewfinder();
1257620644768ffc235607b3a94671e49518c18686fBryan Mawhinney    }
1267620644768ffc235607b3a94671e49518c18686fBryan Mawhinney  }
1277620644768ffc235607b3a94671e49518c18686fBryan Mawhinney
1287620644768ffc235607b3a94671e49518c18686fBryan Mawhinney}
129