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.camera;
187620644768ffc235607b3a94671e49518c18686fBryan Mawhinney
197620644768ffc235607b3a94671e49518c18686fBryan Mawhinneyimport com.google.zxing.client.android.PlanarYUVLuminanceSource;
207620644768ffc235607b3a94671e49518c18686fBryan Mawhinney
217620644768ffc235607b3a94671e49518c18686fBryan Mawhinneyimport android.content.Context;
227620644768ffc235607b3a94671e49518c18686fBryan Mawhinneyimport android.content.SharedPreferences;
237620644768ffc235607b3a94671e49518c18686fBryan Mawhinneyimport android.graphics.Point;
247620644768ffc235607b3a94671e49518c18686fBryan Mawhinneyimport android.graphics.Rect;
257620644768ffc235607b3a94671e49518c18686fBryan Mawhinneyimport android.hardware.Camera;
267620644768ffc235607b3a94671e49518c18686fBryan Mawhinneyimport android.os.Handler;
277620644768ffc235607b3a94671e49518c18686fBryan Mawhinneyimport android.preference.PreferenceManager;
287620644768ffc235607b3a94671e49518c18686fBryan Mawhinneyimport android.util.Log;
297620644768ffc235607b3a94671e49518c18686fBryan Mawhinneyimport android.view.SurfaceHolder;
307620644768ffc235607b3a94671e49518c18686fBryan Mawhinney
317620644768ffc235607b3a94671e49518c18686fBryan Mawhinneyimport java.io.IOException;
327620644768ffc235607b3a94671e49518c18686fBryan Mawhinney
337620644768ffc235607b3a94671e49518c18686fBryan Mawhinney/**
347620644768ffc235607b3a94671e49518c18686fBryan Mawhinney * This object wraps the Camera service object and expects to be the only one talking to it. The
357620644768ffc235607b3a94671e49518c18686fBryan Mawhinney * implementation encapsulates the steps needed to take preview-sized images, which are used for
367620644768ffc235607b3a94671e49518c18686fBryan Mawhinney * both preview and decoding.
377620644768ffc235607b3a94671e49518c18686fBryan Mawhinney *
387620644768ffc235607b3a94671e49518c18686fBryan Mawhinney * @author dswitkin@google.com (Daniel Switkin)
397620644768ffc235607b3a94671e49518c18686fBryan Mawhinney */
407620644768ffc235607b3a94671e49518c18686fBryan Mawhinneypublic final class CameraManager {
417620644768ffc235607b3a94671e49518c18686fBryan Mawhinney
427620644768ffc235607b3a94671e49518c18686fBryan Mawhinney  private static final String TAG = CameraManager.class.getSimpleName();
437620644768ffc235607b3a94671e49518c18686fBryan Mawhinney
447620644768ffc235607b3a94671e49518c18686fBryan Mawhinney  private static final int MIN_FRAME_WIDTH = 240;
457620644768ffc235607b3a94671e49518c18686fBryan Mawhinney  private static final int MIN_FRAME_HEIGHT = 240;
467620644768ffc235607b3a94671e49518c18686fBryan Mawhinney  private static final int MAX_FRAME_WIDTH = 600;
477620644768ffc235607b3a94671e49518c18686fBryan Mawhinney  private static final int MAX_FRAME_HEIGHT = 400;
487620644768ffc235607b3a94671e49518c18686fBryan Mawhinney
497620644768ffc235607b3a94671e49518c18686fBryan Mawhinney  private final Context context;
507620644768ffc235607b3a94671e49518c18686fBryan Mawhinney  private final CameraConfigurationManager configManager;
517620644768ffc235607b3a94671e49518c18686fBryan Mawhinney  private Camera camera;
527620644768ffc235607b3a94671e49518c18686fBryan Mawhinney  private Rect framingRect;
537620644768ffc235607b3a94671e49518c18686fBryan Mawhinney  private Rect framingRectInPreview;
547620644768ffc235607b3a94671e49518c18686fBryan Mawhinney  private boolean initialized;
557620644768ffc235607b3a94671e49518c18686fBryan Mawhinney  private boolean previewing;
567620644768ffc235607b3a94671e49518c18686fBryan Mawhinney  private boolean reverseImage;
577620644768ffc235607b3a94671e49518c18686fBryan Mawhinney  private int requestedFramingRectWidth;
587620644768ffc235607b3a94671e49518c18686fBryan Mawhinney  private int requestedFramingRectHeight;
597620644768ffc235607b3a94671e49518c18686fBryan Mawhinney  /**
607620644768ffc235607b3a94671e49518c18686fBryan Mawhinney   * Preview frames are delivered here, which we pass on to the registered handler. Make sure to
617620644768ffc235607b3a94671e49518c18686fBryan Mawhinney   * clear the handler so it will only receive one message.
627620644768ffc235607b3a94671e49518c18686fBryan Mawhinney   */
637620644768ffc235607b3a94671e49518c18686fBryan Mawhinney  private final PreviewCallback previewCallback;
647620644768ffc235607b3a94671e49518c18686fBryan Mawhinney  /** Autofocus callbacks arrive here, and are dispatched to the Handler which requested them. */
657620644768ffc235607b3a94671e49518c18686fBryan Mawhinney  private final AutoFocusCallback autoFocusCallback;
667620644768ffc235607b3a94671e49518c18686fBryan Mawhinney
677620644768ffc235607b3a94671e49518c18686fBryan Mawhinney  public CameraManager(Context context) {
687620644768ffc235607b3a94671e49518c18686fBryan Mawhinney    this.context = context;
697620644768ffc235607b3a94671e49518c18686fBryan Mawhinney    this.configManager = new CameraConfigurationManager(context);
707620644768ffc235607b3a94671e49518c18686fBryan Mawhinney    previewCallback = new PreviewCallback(configManager);
717620644768ffc235607b3a94671e49518c18686fBryan Mawhinney    autoFocusCallback = new AutoFocusCallback();
727620644768ffc235607b3a94671e49518c18686fBryan Mawhinney  }
737620644768ffc235607b3a94671e49518c18686fBryan Mawhinney
747620644768ffc235607b3a94671e49518c18686fBryan Mawhinney  /**
757620644768ffc235607b3a94671e49518c18686fBryan Mawhinney   * Opens the camera driver and initializes the hardware parameters.
767620644768ffc235607b3a94671e49518c18686fBryan Mawhinney   *
777620644768ffc235607b3a94671e49518c18686fBryan Mawhinney   * @param holder The surface object which the camera will draw preview frames into.
787620644768ffc235607b3a94671e49518c18686fBryan Mawhinney   * @throws IOException Indicates the camera driver failed to open.
797620644768ffc235607b3a94671e49518c18686fBryan Mawhinney   */
807620644768ffc235607b3a94671e49518c18686fBryan Mawhinney  public void openDriver(SurfaceHolder holder) throws IOException {
817620644768ffc235607b3a94671e49518c18686fBryan Mawhinney    Camera theCamera = camera;
827620644768ffc235607b3a94671e49518c18686fBryan Mawhinney    if (theCamera == null) {
837620644768ffc235607b3a94671e49518c18686fBryan Mawhinney      theCamera = Camera.open();
847620644768ffc235607b3a94671e49518c18686fBryan Mawhinney      if (theCamera == null) {
857620644768ffc235607b3a94671e49518c18686fBryan Mawhinney        throw new IOException();
867620644768ffc235607b3a94671e49518c18686fBryan Mawhinney      }
877620644768ffc235607b3a94671e49518c18686fBryan Mawhinney      camera = theCamera;
887620644768ffc235607b3a94671e49518c18686fBryan Mawhinney    }
897620644768ffc235607b3a94671e49518c18686fBryan Mawhinney    theCamera.setPreviewDisplay(holder);
907620644768ffc235607b3a94671e49518c18686fBryan Mawhinney
917620644768ffc235607b3a94671e49518c18686fBryan Mawhinney    if (!initialized) {
927620644768ffc235607b3a94671e49518c18686fBryan Mawhinney      initialized = true;
937620644768ffc235607b3a94671e49518c18686fBryan Mawhinney      configManager.initFromCameraParameters(theCamera);
947620644768ffc235607b3a94671e49518c18686fBryan Mawhinney      if (requestedFramingRectWidth > 0 && requestedFramingRectHeight > 0) {
957620644768ffc235607b3a94671e49518c18686fBryan Mawhinney        setManualFramingRect(requestedFramingRectWidth, requestedFramingRectHeight);
967620644768ffc235607b3a94671e49518c18686fBryan Mawhinney        requestedFramingRectWidth = 0;
977620644768ffc235607b3a94671e49518c18686fBryan Mawhinney        requestedFramingRectHeight = 0;
987620644768ffc235607b3a94671e49518c18686fBryan Mawhinney      }
997620644768ffc235607b3a94671e49518c18686fBryan Mawhinney    }
1007620644768ffc235607b3a94671e49518c18686fBryan Mawhinney    configManager.setDesiredCameraParameters(theCamera);
1017620644768ffc235607b3a94671e49518c18686fBryan Mawhinney
1027620644768ffc235607b3a94671e49518c18686fBryan Mawhinney    SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
1037620644768ffc235607b3a94671e49518c18686fBryan Mawhinney    reverseImage = false;
1047620644768ffc235607b3a94671e49518c18686fBryan Mawhinney  }
1057620644768ffc235607b3a94671e49518c18686fBryan Mawhinney
1067620644768ffc235607b3a94671e49518c18686fBryan Mawhinney  /**
1077620644768ffc235607b3a94671e49518c18686fBryan Mawhinney   * Closes the camera driver if still in use.
1087620644768ffc235607b3a94671e49518c18686fBryan Mawhinney   */
1097620644768ffc235607b3a94671e49518c18686fBryan Mawhinney  public void closeDriver() {
1107620644768ffc235607b3a94671e49518c18686fBryan Mawhinney    if (camera != null) {
1117620644768ffc235607b3a94671e49518c18686fBryan Mawhinney      camera.release();
1127620644768ffc235607b3a94671e49518c18686fBryan Mawhinney      camera = null;
1137620644768ffc235607b3a94671e49518c18686fBryan Mawhinney      // Make sure to clear these each time we close the camera, so that any scanning rect
1147620644768ffc235607b3a94671e49518c18686fBryan Mawhinney      // requested by intent is forgotten.
1157620644768ffc235607b3a94671e49518c18686fBryan Mawhinney      framingRect = null;
1167620644768ffc235607b3a94671e49518c18686fBryan Mawhinney      framingRectInPreview = null;
1177620644768ffc235607b3a94671e49518c18686fBryan Mawhinney    }
1187620644768ffc235607b3a94671e49518c18686fBryan Mawhinney  }
1197620644768ffc235607b3a94671e49518c18686fBryan Mawhinney
1207620644768ffc235607b3a94671e49518c18686fBryan Mawhinney  /**
1217620644768ffc235607b3a94671e49518c18686fBryan Mawhinney   * Asks the camera hardware to begin drawing preview frames to the screen.
1227620644768ffc235607b3a94671e49518c18686fBryan Mawhinney   */
1237620644768ffc235607b3a94671e49518c18686fBryan Mawhinney  public void startPreview() {
1247620644768ffc235607b3a94671e49518c18686fBryan Mawhinney    Camera theCamera = camera;
1257620644768ffc235607b3a94671e49518c18686fBryan Mawhinney    if (theCamera != null && !previewing) {
1267620644768ffc235607b3a94671e49518c18686fBryan Mawhinney      theCamera.startPreview();
1277620644768ffc235607b3a94671e49518c18686fBryan Mawhinney      previewing = true;
1287620644768ffc235607b3a94671e49518c18686fBryan Mawhinney    }
1297620644768ffc235607b3a94671e49518c18686fBryan Mawhinney  }
1307620644768ffc235607b3a94671e49518c18686fBryan Mawhinney
1317620644768ffc235607b3a94671e49518c18686fBryan Mawhinney  /**
1327620644768ffc235607b3a94671e49518c18686fBryan Mawhinney   * Tells the camera to stop drawing preview frames.
1337620644768ffc235607b3a94671e49518c18686fBryan Mawhinney   */
1347620644768ffc235607b3a94671e49518c18686fBryan Mawhinney  public void stopPreview() {
1357620644768ffc235607b3a94671e49518c18686fBryan Mawhinney    if (camera != null && previewing) {
1367620644768ffc235607b3a94671e49518c18686fBryan Mawhinney      camera.stopPreview();
1377620644768ffc235607b3a94671e49518c18686fBryan Mawhinney      previewCallback.setHandler(null, 0);
1387620644768ffc235607b3a94671e49518c18686fBryan Mawhinney      autoFocusCallback.setHandler(null, 0);
1397620644768ffc235607b3a94671e49518c18686fBryan Mawhinney      previewing = false;
1407620644768ffc235607b3a94671e49518c18686fBryan Mawhinney    }
1417620644768ffc235607b3a94671e49518c18686fBryan Mawhinney  }
1427620644768ffc235607b3a94671e49518c18686fBryan Mawhinney
1437620644768ffc235607b3a94671e49518c18686fBryan Mawhinney  /**
1447620644768ffc235607b3a94671e49518c18686fBryan Mawhinney   * A single preview frame will be returned to the handler supplied. The data will arrive as byte[]
1457620644768ffc235607b3a94671e49518c18686fBryan Mawhinney   * in the message.obj field, with width and height encoded as message.arg1 and message.arg2,
1467620644768ffc235607b3a94671e49518c18686fBryan Mawhinney   * respectively.
1477620644768ffc235607b3a94671e49518c18686fBryan Mawhinney   *
1487620644768ffc235607b3a94671e49518c18686fBryan Mawhinney   * @param handler The handler to send the message to.
1497620644768ffc235607b3a94671e49518c18686fBryan Mawhinney   * @param message The what field of the message to be sent.
1507620644768ffc235607b3a94671e49518c18686fBryan Mawhinney   */
1517620644768ffc235607b3a94671e49518c18686fBryan Mawhinney  public void requestPreviewFrame(Handler handler, int message) {
1527620644768ffc235607b3a94671e49518c18686fBryan Mawhinney    Camera theCamera = camera;
1537620644768ffc235607b3a94671e49518c18686fBryan Mawhinney    if (theCamera != null && previewing) {
1547620644768ffc235607b3a94671e49518c18686fBryan Mawhinney      previewCallback.setHandler(handler, message);
1557620644768ffc235607b3a94671e49518c18686fBryan Mawhinney      theCamera.setOneShotPreviewCallback(previewCallback);
1567620644768ffc235607b3a94671e49518c18686fBryan Mawhinney    }
1577620644768ffc235607b3a94671e49518c18686fBryan Mawhinney  }
1587620644768ffc235607b3a94671e49518c18686fBryan Mawhinney
1597620644768ffc235607b3a94671e49518c18686fBryan Mawhinney  /**
1607620644768ffc235607b3a94671e49518c18686fBryan Mawhinney   * Asks the camera hardware to perform an autofocus.
1617620644768ffc235607b3a94671e49518c18686fBryan Mawhinney   *
1627620644768ffc235607b3a94671e49518c18686fBryan Mawhinney   * @param handler The Handler to notify when the autofocus completes.
1637620644768ffc235607b3a94671e49518c18686fBryan Mawhinney   * @param message The message to deliver.
1647620644768ffc235607b3a94671e49518c18686fBryan Mawhinney   */
1657620644768ffc235607b3a94671e49518c18686fBryan Mawhinney  public void requestAutoFocus(Handler handler, int message) {
1667620644768ffc235607b3a94671e49518c18686fBryan Mawhinney    if (camera != null && previewing) {
1677620644768ffc235607b3a94671e49518c18686fBryan Mawhinney      autoFocusCallback.setHandler(handler, message);
1687620644768ffc235607b3a94671e49518c18686fBryan Mawhinney      camera.autoFocus(autoFocusCallback);
1697620644768ffc235607b3a94671e49518c18686fBryan Mawhinney    }
1707620644768ffc235607b3a94671e49518c18686fBryan Mawhinney  }
1717620644768ffc235607b3a94671e49518c18686fBryan Mawhinney
1727620644768ffc235607b3a94671e49518c18686fBryan Mawhinney  /**
1737620644768ffc235607b3a94671e49518c18686fBryan Mawhinney   * Calculates the framing rect which the UI should draw to show the user where to place the
1747620644768ffc235607b3a94671e49518c18686fBryan Mawhinney   * barcode. This target helps with alignment as well as forces the user to hold the device
1757620644768ffc235607b3a94671e49518c18686fBryan Mawhinney   * far enough away to ensure the image will be in focus.
1767620644768ffc235607b3a94671e49518c18686fBryan Mawhinney   *
1777620644768ffc235607b3a94671e49518c18686fBryan Mawhinney   * @return The rectangle to draw on screen in window coordinates.
1787620644768ffc235607b3a94671e49518c18686fBryan Mawhinney   */
1797620644768ffc235607b3a94671e49518c18686fBryan Mawhinney  public Rect getFramingRect() {
1807620644768ffc235607b3a94671e49518c18686fBryan Mawhinney    if (framingRect == null) {
1817620644768ffc235607b3a94671e49518c18686fBryan Mawhinney      if (camera == null) {
1827620644768ffc235607b3a94671e49518c18686fBryan Mawhinney        return null;
1837620644768ffc235607b3a94671e49518c18686fBryan Mawhinney      }
1847620644768ffc235607b3a94671e49518c18686fBryan Mawhinney      Point screenResolution = configManager.getScreenResolution();
1857620644768ffc235607b3a94671e49518c18686fBryan Mawhinney      int width = screenResolution.x * 3 / 4;
1867620644768ffc235607b3a94671e49518c18686fBryan Mawhinney      if (width < MIN_FRAME_WIDTH) {
1877620644768ffc235607b3a94671e49518c18686fBryan Mawhinney        width = MIN_FRAME_WIDTH;
1887620644768ffc235607b3a94671e49518c18686fBryan Mawhinney      } else if (width > MAX_FRAME_WIDTH) {
1897620644768ffc235607b3a94671e49518c18686fBryan Mawhinney        width = MAX_FRAME_WIDTH;
1907620644768ffc235607b3a94671e49518c18686fBryan Mawhinney      }
1917620644768ffc235607b3a94671e49518c18686fBryan Mawhinney      int height = screenResolution.y * 3 / 4;
1927620644768ffc235607b3a94671e49518c18686fBryan Mawhinney      if (height < MIN_FRAME_HEIGHT) {
1937620644768ffc235607b3a94671e49518c18686fBryan Mawhinney        height = MIN_FRAME_HEIGHT;
1947620644768ffc235607b3a94671e49518c18686fBryan Mawhinney      } else if (height > MAX_FRAME_HEIGHT) {
1957620644768ffc235607b3a94671e49518c18686fBryan Mawhinney        height = MAX_FRAME_HEIGHT;
1967620644768ffc235607b3a94671e49518c18686fBryan Mawhinney      }
1977620644768ffc235607b3a94671e49518c18686fBryan Mawhinney      int leftOffset = (screenResolution.x - width) / 2;
1987620644768ffc235607b3a94671e49518c18686fBryan Mawhinney      int topOffset = (screenResolution.y - height) / 2;
1997620644768ffc235607b3a94671e49518c18686fBryan Mawhinney      framingRect = new Rect(leftOffset, topOffset, leftOffset + width, topOffset + height);
2007620644768ffc235607b3a94671e49518c18686fBryan Mawhinney      Log.d(TAG, "Calculated framing rect: " + framingRect);
2017620644768ffc235607b3a94671e49518c18686fBryan Mawhinney    }
2027620644768ffc235607b3a94671e49518c18686fBryan Mawhinney    return framingRect;
2037620644768ffc235607b3a94671e49518c18686fBryan Mawhinney  }
2047620644768ffc235607b3a94671e49518c18686fBryan Mawhinney
2057620644768ffc235607b3a94671e49518c18686fBryan Mawhinney  /**
2067620644768ffc235607b3a94671e49518c18686fBryan Mawhinney   * Like {@link #getFramingRect} but coordinates are in terms of the preview frame,
2077620644768ffc235607b3a94671e49518c18686fBryan Mawhinney   * not UI / screen.
2087620644768ffc235607b3a94671e49518c18686fBryan Mawhinney   */
2097620644768ffc235607b3a94671e49518c18686fBryan Mawhinney  public Rect getFramingRectInPreview() {
2107620644768ffc235607b3a94671e49518c18686fBryan Mawhinney    if (framingRectInPreview == null) {
2117620644768ffc235607b3a94671e49518c18686fBryan Mawhinney      Rect framingRect = getFramingRect();
2127620644768ffc235607b3a94671e49518c18686fBryan Mawhinney      if (framingRect == null) {
2137620644768ffc235607b3a94671e49518c18686fBryan Mawhinney        return null;
2147620644768ffc235607b3a94671e49518c18686fBryan Mawhinney      }
2157620644768ffc235607b3a94671e49518c18686fBryan Mawhinney      Rect rect = new Rect(framingRect);
2167620644768ffc235607b3a94671e49518c18686fBryan Mawhinney      Point cameraResolution = configManager.getCameraResolution();
2177620644768ffc235607b3a94671e49518c18686fBryan Mawhinney      if (cameraResolution == null) {
2187620644768ffc235607b3a94671e49518c18686fBryan Mawhinney        return framingRect;
2197620644768ffc235607b3a94671e49518c18686fBryan Mawhinney      }
2207620644768ffc235607b3a94671e49518c18686fBryan Mawhinney      Point screenResolution = configManager.getScreenResolution();
2217620644768ffc235607b3a94671e49518c18686fBryan Mawhinney      rect.left = rect.left * cameraResolution.x / screenResolution.x;
2227620644768ffc235607b3a94671e49518c18686fBryan Mawhinney      rect.right = rect.right * cameraResolution.x / screenResolution.x;
2237620644768ffc235607b3a94671e49518c18686fBryan Mawhinney      rect.top = rect.top * cameraResolution.y / screenResolution.y;
2247620644768ffc235607b3a94671e49518c18686fBryan Mawhinney      rect.bottom = rect.bottom * cameraResolution.y / screenResolution.y;
2257620644768ffc235607b3a94671e49518c18686fBryan Mawhinney      framingRectInPreview = rect;
2267620644768ffc235607b3a94671e49518c18686fBryan Mawhinney    }
2277620644768ffc235607b3a94671e49518c18686fBryan Mawhinney    return framingRectInPreview;
2287620644768ffc235607b3a94671e49518c18686fBryan Mawhinney  }
2297620644768ffc235607b3a94671e49518c18686fBryan Mawhinney
2307620644768ffc235607b3a94671e49518c18686fBryan Mawhinney  /**
2317620644768ffc235607b3a94671e49518c18686fBryan Mawhinney   * Allows third party apps to specify the scanning rectangle dimensions, rather than determine
2327620644768ffc235607b3a94671e49518c18686fBryan Mawhinney   * them automatically based on screen resolution.
2337620644768ffc235607b3a94671e49518c18686fBryan Mawhinney   *
2347620644768ffc235607b3a94671e49518c18686fBryan Mawhinney   * @param width The width in pixels to scan.
2357620644768ffc235607b3a94671e49518c18686fBryan Mawhinney   * @param height The height in pixels to scan.
2367620644768ffc235607b3a94671e49518c18686fBryan Mawhinney   */
2377620644768ffc235607b3a94671e49518c18686fBryan Mawhinney  public void setManualFramingRect(int width, int height) {
2387620644768ffc235607b3a94671e49518c18686fBryan Mawhinney    if (initialized) {
2397620644768ffc235607b3a94671e49518c18686fBryan Mawhinney      Point screenResolution = configManager.getScreenResolution();
2407620644768ffc235607b3a94671e49518c18686fBryan Mawhinney      if (width > screenResolution.x) {
2417620644768ffc235607b3a94671e49518c18686fBryan Mawhinney        width = screenResolution.x;
2427620644768ffc235607b3a94671e49518c18686fBryan Mawhinney      }
2437620644768ffc235607b3a94671e49518c18686fBryan Mawhinney      if (height > screenResolution.y) {
2447620644768ffc235607b3a94671e49518c18686fBryan Mawhinney        height = screenResolution.y;
2457620644768ffc235607b3a94671e49518c18686fBryan Mawhinney      }
2467620644768ffc235607b3a94671e49518c18686fBryan Mawhinney      int leftOffset = (screenResolution.x - width) / 2;
2477620644768ffc235607b3a94671e49518c18686fBryan Mawhinney      int topOffset = (screenResolution.y - height) / 2;
2487620644768ffc235607b3a94671e49518c18686fBryan Mawhinney      framingRect = new Rect(leftOffset, topOffset, leftOffset + width, topOffset + height);
2497620644768ffc235607b3a94671e49518c18686fBryan Mawhinney      Log.d(TAG, "Calculated manual framing rect: " + framingRect);
2507620644768ffc235607b3a94671e49518c18686fBryan Mawhinney      framingRectInPreview = null;
2517620644768ffc235607b3a94671e49518c18686fBryan Mawhinney    } else {
2527620644768ffc235607b3a94671e49518c18686fBryan Mawhinney      requestedFramingRectWidth = width;
2537620644768ffc235607b3a94671e49518c18686fBryan Mawhinney      requestedFramingRectHeight = height;
2547620644768ffc235607b3a94671e49518c18686fBryan Mawhinney    }
2557620644768ffc235607b3a94671e49518c18686fBryan Mawhinney  }
2567620644768ffc235607b3a94671e49518c18686fBryan Mawhinney
2577620644768ffc235607b3a94671e49518c18686fBryan Mawhinney  /**
2587620644768ffc235607b3a94671e49518c18686fBryan Mawhinney   * A factory method to build the appropriate LuminanceSource object based on the format
2597620644768ffc235607b3a94671e49518c18686fBryan Mawhinney   * of the preview buffers, as described by Camera.Parameters.
2607620644768ffc235607b3a94671e49518c18686fBryan Mawhinney   *
2617620644768ffc235607b3a94671e49518c18686fBryan Mawhinney   * @param data A preview frame.
2627620644768ffc235607b3a94671e49518c18686fBryan Mawhinney   * @param width The width of the image.
2637620644768ffc235607b3a94671e49518c18686fBryan Mawhinney   * @param height The height of the image.
2647620644768ffc235607b3a94671e49518c18686fBryan Mawhinney   * @return A PlanarYUVLuminanceSource instance.
2657620644768ffc235607b3a94671e49518c18686fBryan Mawhinney   */
2667620644768ffc235607b3a94671e49518c18686fBryan Mawhinney  public PlanarYUVLuminanceSource buildLuminanceSource(byte[] data, int width, int height) {
2677620644768ffc235607b3a94671e49518c18686fBryan Mawhinney    Rect rect = getFramingRectInPreview();
2687620644768ffc235607b3a94671e49518c18686fBryan Mawhinney    if (rect == null) {
2697620644768ffc235607b3a94671e49518c18686fBryan Mawhinney      return null;
2707620644768ffc235607b3a94671e49518c18686fBryan Mawhinney    }
2717620644768ffc235607b3a94671e49518c18686fBryan Mawhinney    // Go ahead and assume it's YUV rather than die.
2727620644768ffc235607b3a94671e49518c18686fBryan Mawhinney    return new PlanarYUVLuminanceSource(data, width, height, rect.left, rect.top,
2737620644768ffc235607b3a94671e49518c18686fBryan Mawhinney                                        rect.width(), rect.height(), reverseImage);
2747620644768ffc235607b3a94671e49518c18686fBryan Mawhinney  }
2757620644768ffc235607b3a94671e49518c18686fBryan Mawhinney
2767620644768ffc235607b3a94671e49518c18686fBryan Mawhinney}
277