/ocr/worldreader/src/com/google/marvin/worldreader/CaptureActivity.java

http://eyes-free.googlecode.com/ · Java · 302 lines · 221 code · 53 blank · 28 comment · 27 complexity · eb73ff70f281c8f5b5e9eb17157becd1 MD5 · raw file

  1. /*
  2. * Copyright (C) 2009 Google Inc.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License"); you may not
  5. * use this file except in compliance with the License. You may obtain a copy of
  6. * 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, WITHOUT
  12. * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
  13. * License for the specific language governing permissions and limitations under
  14. * the License.
  15. */
  16. package com.google.marvin.worldreader;
  17. import android.app.Activity;
  18. import android.content.Intent;
  19. import android.content.res.Resources;
  20. import android.os.Bundle;
  21. import android.os.Handler;
  22. import android.os.Message;
  23. import android.speech.tts.TextToSpeech;
  24. import android.util.Log;
  25. import android.view.GestureDetector;
  26. import android.view.KeyEvent;
  27. import android.view.MotionEvent;
  28. import android.view.SurfaceHolder;
  29. import android.view.SurfaceView;
  30. import android.view.View;
  31. import android.view.Window;
  32. import android.view.WindowManager;
  33. import android.view.GestureDetector.SimpleOnGestureListener;
  34. import android.view.View.OnTouchListener;
  35. import com.android.ocr.client.Config;
  36. import com.android.ocr.client.Intents;
  37. import java.io.IOException;
  38. /**
  39. * Based on code from ZXing licensed under Apache License, Version 2.0.
  40. *
  41. * Modified from com.google.marvin.ocr.intent.CaptureActivity to allow
  42. * swipe-based setting of the text enhancement mode.
  43. *
  44. * @author alanv@google.com (Alan Viverette)
  45. */
  46. public class CaptureActivity extends Activity implements SurfaceHolder.Callback, OnTouchListener {
  47. private static final String TAG = "CaptureActivity";
  48. private static final int DEFAULT_WIDTH = 1024;
  49. private static final int DEFAULT_HEIGHT = 768;
  50. private static final int MODE_DENSE = 0;
  51. private static final int MODE_SPARSE = 1;
  52. private static final int ACTION_FOCUS = 0;
  53. private static final int ACTION_TAKE_PICTURE = 1;
  54. private enum State {
  55. IDLE, FOCUSING, TAKING_PICTURE, COMPLETE
  56. }
  57. private boolean mHasSurface;
  58. private int mMode;
  59. private TextToSpeech mTts;
  60. private CameraManager mCameraManager;
  61. private GestureDetector mGestureDetector;
  62. private SimpleOnGestureListener mGestureListener;
  63. private State mState;
  64. private String[] mModes;
  65. private final Handler mHandler = new Handler() {
  66. @Override
  67. public void handleMessage(Message message) {
  68. switch (message.what) {
  69. case ACTION_FOCUS: {
  70. // Completed focusing, now attempt to take preview or picture
  71. onFocused();
  72. break;
  73. }
  74. case ACTION_TAKE_PICTURE: {
  75. // Obtained picture, now perform full text recognition
  76. if (message.obj == null || message.obj instanceof byte[]) {
  77. onPictureTaken((byte[]) message.obj, message.arg1, message.arg2);
  78. }
  79. break;
  80. }
  81. }
  82. }
  83. };
  84. /** Called with the activity is first created. */
  85. @Override
  86. public void onCreate(Bundle savedInstanceState) {
  87. Log.i(TAG, "Creating CaptureActivity");
  88. super.onCreate(savedInstanceState);
  89. Window window = getWindow();
  90. window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
  91. setContentView(R.layout.capture);
  92. mTts = ReaderActivity.mTts;
  93. Resources resources = getResources();
  94. mModes = resources.getStringArray(R.array.modes);
  95. mGestureListener = new CaptureGestureListener();
  96. mGestureDetector = new GestureDetector(mGestureListener);
  97. SurfaceView surfaceView = (SurfaceView) findViewById(R.id.preview);
  98. surfaceView.setOnTouchListener(this);
  99. mCameraManager = CameraManager.init(getApplication());
  100. mCameraManager.setPictureSize(DEFAULT_WIDTH, DEFAULT_HEIGHT);
  101. mHasSurface = false;
  102. }
  103. @Override
  104. protected void onResume() {
  105. super.onResume();
  106. SurfaceView surfaceView = (SurfaceView) findViewById(R.id.preview);
  107. SurfaceHolder surfaceHolder = surfaceView.getHolder();
  108. if (mHasSurface) {
  109. initCamera(surfaceHolder);
  110. } else {
  111. surfaceHolder.addCallback(this);
  112. surfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
  113. }
  114. }
  115. @Override
  116. protected void onPause() {
  117. mCameraManager.closeDriver();
  118. super.onPause();
  119. }
  120. @Override
  121. protected void onDestroy() {
  122. super.onDestroy();
  123. }
  124. @Override
  125. public void surfaceCreated(SurfaceHolder holder) {
  126. if (!mHasSurface) {
  127. mHasSurface = true;
  128. initCamera(holder);
  129. }
  130. }
  131. @Override
  132. public void surfaceDestroyed(SurfaceHolder holder) {
  133. mHasSurface = false;
  134. }
  135. @Override
  136. public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
  137. // Do nothing
  138. }
  139. @Override
  140. public boolean onKeyDown(int keyCode, KeyEvent event) {
  141. switch (keyCode) {
  142. case KeyEvent.KEYCODE_BACK:
  143. if (mState != State.TAKING_PICTURE) {
  144. setResult(RESULT_CANCELED);
  145. finish();
  146. }
  147. return true;
  148. case KeyEvent.KEYCODE_FOCUS:
  149. if (event.getRepeatCount() == 0) {
  150. mState = State.FOCUSING;
  151. mCameraManager.requestAutoFocus(mHandler, ACTION_FOCUS);
  152. }
  153. return true;
  154. case KeyEvent.KEYCODE_DPAD_CENTER:
  155. case KeyEvent.KEYCODE_CAMERA:
  156. if (event.getRepeatCount() == 0) {
  157. mState = State.TAKING_PICTURE;
  158. mCameraManager.requestAutoFocus(mHandler, ACTION_FOCUS);
  159. }
  160. return true;
  161. }
  162. return super.onKeyDown(keyCode, event);
  163. }
  164. @Override
  165. public boolean onKeyUp(int keyCode, KeyEvent event) {
  166. // TODO Is this necessary?
  167. switch (keyCode) {
  168. case KeyEvent.KEYCODE_FOCUS:
  169. return true;
  170. }
  171. return super.onKeyUp(keyCode, event);
  172. }
  173. private void initCamera(SurfaceHolder surfaceHolder) {
  174. try {
  175. mCameraManager.openDriver(surfaceHolder);
  176. mCameraManager.startPreview();
  177. mTts.speak("ready", TextToSpeech.QUEUE_FLUSH, null);
  178. } catch (IOException e) {
  179. Log.e(TAG, e.toString());
  180. }
  181. }
  182. private void onFocused() {
  183. if (mState == State.TAKING_PICTURE) {
  184. mCameraManager.requestTakePicture(mHandler, ACTION_TAKE_PICTURE);
  185. } else {
  186. mState = State.IDLE;
  187. }
  188. }
  189. private void onPictureTaken(final byte[] data, int width, int height) {
  190. mState = State.IDLE;
  191. Config config = new Config();
  192. config.image = data;
  193. config.width = width;
  194. config.height = height;
  195. config.format = Config.FORMAT_JPEG;
  196. switch (mMode) {
  197. case MODE_DENSE: {
  198. config.options |= Config.OPT_NORMALIZE_BG;
  199. break;
  200. }
  201. case MODE_SPARSE: {
  202. config.options |= Config.OPT_DETECT_TEXT;
  203. }
  204. }
  205. Intent result = new Intent();
  206. result.setAction(Intents.Capture.ACTION);
  207. result.putExtra(Intents.Capture.CONFIG, config);
  208. setResult(RESULT_OK, result);
  209. finish();
  210. }
  211. @Override
  212. public boolean onTouch(View v, MotionEvent event) {
  213. mGestureDetector.onTouchEvent(event);
  214. return true;
  215. }
  216. private void cycleMode(int direction) {
  217. mMode = (mMode + direction) % mModes.length;
  218. if (mMode < 0) {
  219. mMode += mModes.length;
  220. }
  221. mTts.speak(mModes[mMode], TextToSpeech.QUEUE_FLUSH, null);
  222. }
  223. private class CaptureGestureListener extends SimpleOnGestureListener {
  224. private static final int SWIPE_MIN_DISTANCE = 120;
  225. private static final int SWIPE_THRESHOLD_VELOCITY = 200;
  226. @Override
  227. public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
  228. float distX = e1.getX() - e2.getX();
  229. float distY = e1.getY() - e2.getY();
  230. if (Math.abs(velocityX) > SWIPE_THRESHOLD_VELOCITY
  231. || Math.abs(velocityY) > SWIPE_THRESHOLD_VELOCITY) {
  232. if (distX > SWIPE_MIN_DISTANCE || distY > SWIPE_MIN_DISTANCE) {
  233. cycleMode(1);
  234. return true;
  235. } else if (distX < -1 * SWIPE_MIN_DISTANCE || distY < -1 * SWIPE_MIN_DISTANCE) {
  236. cycleMode(-1);
  237. return true;
  238. }
  239. }
  240. return false;
  241. }
  242. @Override
  243. public boolean onSingleTapConfirmed(MotionEvent e) {
  244. mState = State.TAKING_PICTURE;
  245. mCameraManager.requestAutoFocus(mHandler, ACTION_FOCUS);
  246. return true;
  247. }
  248. }
  249. }