1ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian/*
2ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * Copyright (C) 2016 The Android Open Source Project
3ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian *
4ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * Licensed under the Apache License, Version 2.0 (the "License");
5ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * you may not use this file except in compliance with the License.
6ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * You may obtain a copy of the License at
7ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian *
8ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian *      http://www.apache.org/licenses/LICENSE-2.0
9ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian *
10ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * Unless required by applicable law or agreed to in writing, software
11ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * distributed under the License is distributed on an "AS IS" BASIS,
12ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * See the License for the specific language governing permissions and
14ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * limitations under the License.
15ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian */
16ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian
17ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianpackage com.android.dialer.callcomposer.camera;
18ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian
19ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport android.content.Context;
20ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport android.hardware.Camera;
21ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport android.hardware.Camera.CameraInfo;
22ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport android.net.Uri;
23ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport android.os.AsyncTask;
24ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport android.os.Looper;
25ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport android.support.annotation.NonNull;
26fc37b02f5d3381a7882770941e461b13b679b6efEric Erfanianimport android.support.annotation.Nullable;
27ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport android.support.annotation.VisibleForTesting;
28ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport android.text.TextUtils;
29ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport android.view.MotionEvent;
30ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport android.view.OrientationEventListener;
31ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport android.view.Surface;
32ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport android.view.View;
33ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport android.view.WindowManager;
34ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport com.android.dialer.callcomposer.camera.camerafocus.FocusOverlayManager;
35ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport com.android.dialer.callcomposer.camera.camerafocus.RenderOverlay;
36ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport com.android.dialer.common.Assert;
37ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport com.android.dialer.common.LogUtil;
38ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport java.io.IOException;
39ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport java.util.ArrayList;
40ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport java.util.Collections;
41ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport java.util.Comparator;
42ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport java.util.List;
43ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian
44ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian/**
45ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * Class which manages interactions with the camera, but does not do any UI. This class is designed
46ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * to be a singleton to ensure there is one component managing the camera and releasing the native
47ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * resources. In order to acquire a camera, a caller must:
48ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian *
49ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * <ul>
50ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian *   <li>Call selectCamera to select front or back camera
51ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian *   <li>Call setSurface to control where the preview is shown
52ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian *   <li>Call openCamera to request the camera start preview
53ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * </ul>
54ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian *
55ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * Callers should call onPause and onResume to ensure that the camera is release while the activity
56ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * is not active. This class is not thread safe. It should only be called from one thread (the UI
57ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * thread or test thread)
58ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian */
59ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianpublic class CameraManager implements FocusOverlayManager.Listener {
60ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  /** Callbacks for the camera manager listener */
61ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  public interface CameraManagerListener {
62ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    void onCameraError(int errorCode, Exception e);
63ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian
64ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    void onCameraChanged();
65ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  }
66ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian
67ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  /** Callback when taking image or video */
68ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  public interface MediaCallback {
69ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    int MEDIA_CAMERA_CHANGED = 1;
70ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    int MEDIA_NO_DATA = 2;
71ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian
72ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    void onMediaReady(Uri uriToMedia, String contentType, int width, int height);
73ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian
74ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    void onMediaFailed(Exception exception);
75ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian
76ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    void onMediaInfo(int what);
77ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  }
78ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian
79ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  // Error codes
80ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  private static final int ERROR_OPENING_CAMERA = 1;
81ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  private static final int ERROR_SHOWING_PREVIEW = 2;
82ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  private static final int ERROR_HARDWARE_ACCELERATION_DISABLED = 3;
83ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  private static final int ERROR_TAKING_PICTURE = 4;
84ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian
85ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  private static final int NO_CAMERA_SELECTED = -1;
86ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian
87ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  private static final Camera.ShutterCallback DUMMY_SHUTTER_CALLBACK =
88ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      new Camera.ShutterCallback() {
89ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian        @Override
90ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian        public void onShutter() {
91ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian          // Do nothing
92ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian        }
93ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      };
94ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian
95ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  private static CameraManager sInstance;
96ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian
97ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  /** The CameraInfo for the currently selected camera */
98ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  private final CameraInfo mCameraInfo;
99ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian
100ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  /** The index of the selected camera or NO_CAMERA_SELECTED if a camera hasn't been selected yet */
101ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  private int mCameraIndex;
102ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian
103ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  /** True if the device has front and back cameras */
104ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  private final boolean mHasFrontAndBackCamera;
105ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian
106ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  /** True if the camera should be open (may not yet be actually open) */
107ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  private boolean mOpenRequested;
108ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian
109ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  /** The preview view to show the preview on */
110ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  private CameraPreview mCameraPreview;
111ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian
112ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  /** The helper classs to handle orientation changes */
113ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  private OrientationHandler mOrientationHandler;
114ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian
115ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  /** Tracks whether the preview has hardware acceleration */
116ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  private boolean mIsHardwareAccelerationSupported;
117ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian
118ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  /**
119ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian   * The task for opening the camera, so it doesn't block the UI thread Using AsyncTask rather than
120ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian   * SafeAsyncTask because the tasks need to be serialized, but don't need to be on the UI thread
12110ae593a59aa50963e1d3159747da2d65ca79bedEric Erfanian   * TODO: If we have other AyncTasks (not SafeAsyncTasks) this may contend and we may need
122ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian   * to create a dedicated thread, or synchronize the threads in the thread pool
123ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian   */
124ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  private AsyncTask<Integer, Void, Camera> mOpenCameraTask;
125ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian
126ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  /**
127ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian   * The camera index that is queued to be opened, but not completed yet, or NO_CAMERA_SELECTED if
128ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian   * no open task is pending
129ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian   */
130ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  private int mPendingOpenCameraIndex = NO_CAMERA_SELECTED;
131ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian
132ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  /** The instance of the currently opened camera */
133ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  private Camera mCamera;
134ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian
135ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  /** The rotation of the screen relative to the camera's natural orientation */
136ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  private int mRotation;
137ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian
138ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  /** The callback to notify when errors or other events occur */
139ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  private CameraManagerListener mListener;
140ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian
141ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  /** True if the camera is currently in the process of taking an image */
142ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  private boolean mTakingPicture;
143ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian
144ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  /** Manages auto focus visual and behavior */
145ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  private final FocusOverlayManager mFocusOverlayManager;
146ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian
147ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  private CameraManager() {
148ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    mCameraInfo = new CameraInfo();
149ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    mCameraIndex = NO_CAMERA_SELECTED;
150ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian
151ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    // Check to see if a front and back camera exist
152ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    boolean hasFrontCamera = false;
153ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    boolean hasBackCamera = false;
154ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    final CameraInfo cameraInfo = new CameraInfo();
155ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    final int cameraCount = Camera.getNumberOfCameras();
156ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    try {
157ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      for (int i = 0; i < cameraCount; i++) {
158ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian        Camera.getCameraInfo(i, cameraInfo);
159ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian        if (cameraInfo.facing == CameraInfo.CAMERA_FACING_FRONT) {
160ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian          hasFrontCamera = true;
161ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian        } else if (cameraInfo.facing == CameraInfo.CAMERA_FACING_BACK) {
162ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian          hasBackCamera = true;
163ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian        }
164ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian        if (hasFrontCamera && hasBackCamera) {
165ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian          break;
166ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian        }
167ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      }
168ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    } catch (final RuntimeException e) {
169ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      LogUtil.e("CameraManager.CameraManager", "Unable to load camera info", e);
170ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    }
171ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    mHasFrontAndBackCamera = hasFrontCamera && hasBackCamera;
172ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    mFocusOverlayManager = new FocusOverlayManager(this, Looper.getMainLooper());
173ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian
174ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    // Assume the best until we are proven otherwise
175ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    mIsHardwareAccelerationSupported = true;
176ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  }
177ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian
178ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  /** Gets the singleton instance */
179ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  public static CameraManager get() {
180ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    if (sInstance == null) {
181ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      sInstance = new CameraManager();
182ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    }
183ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    return sInstance;
184ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  }
185ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian
186ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  /**
187ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian   * Sets the surface to use to display the preview This must only be called AFTER the CameraPreview
188ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian   * has a texture ready
189ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian   *
190ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian   * @param preview The preview surface view
191ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian   */
192ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  void setSurface(final CameraPreview preview) {
193ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    if (preview == mCameraPreview) {
194ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      return;
195ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    }
196ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian
197ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    if (preview != null) {
198ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      Assert.checkArgument(preview.isValid());
199ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      preview.setOnTouchListener(
200ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian          new View.OnTouchListener() {
201ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian            @Override
202ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian            public boolean onTouch(final View view, final MotionEvent motionEvent) {
203ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian              if ((motionEvent.getActionMasked() & MotionEvent.ACTION_UP)
204ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian                  == MotionEvent.ACTION_UP) {
205ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian                mFocusOverlayManager.setPreviewSize(view.getWidth(), view.getHeight());
206ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian                mFocusOverlayManager.onSingleTapUp(
207ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian                    (int) motionEvent.getX() + view.getLeft(),
208ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian                    (int) motionEvent.getY() + view.getTop());
209ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian              }
210ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian              view.performClick();
211ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian              return true;
212ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian            }
213ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian          });
214ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    }
215ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    mCameraPreview = preview;
216ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    tryShowPreview();
217ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  }
218ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian
219ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  public void setRenderOverlay(final RenderOverlay renderOverlay) {
220ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    mFocusOverlayManager.setFocusRenderer(
221ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian        renderOverlay != null ? renderOverlay.getPieRenderer() : null);
222ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  }
223ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian
224ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  /** Convenience function to swap between front and back facing cameras */
225ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  public void swapCamera() {
226ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    Assert.checkState(mCameraIndex >= 0);
227ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    selectCamera(
228ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian        mCameraInfo.facing == CameraInfo.CAMERA_FACING_FRONT
229ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian            ? CameraInfo.CAMERA_FACING_BACK
230ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian            : CameraInfo.CAMERA_FACING_FRONT);
231ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  }
232ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian
233ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  /**
234ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian   * Selects the first camera facing the desired direction, or the first camera if there is no
235ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian   * camera in the desired direction
236ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian   *
237ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian   * @param desiredFacing One of the CameraInfo.CAMERA_FACING_* constants
238ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian   * @return True if a camera was selected, or false if selecting a camera failed
239ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian   */
240ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  public boolean selectCamera(final int desiredFacing) {
241ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    try {
242ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      // We already selected a camera facing that direction
243ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      if (mCameraIndex >= 0 && mCameraInfo.facing == desiredFacing) {
244ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian        return true;
245ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      }
246ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian
247ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      final int cameraCount = Camera.getNumberOfCameras();
248ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      Assert.checkState(cameraCount > 0);
249ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian
250ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      mCameraIndex = NO_CAMERA_SELECTED;
251ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      setCamera(null);
252ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      final CameraInfo cameraInfo = new CameraInfo();
253ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      for (int i = 0; i < cameraCount; i++) {
254ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian        Camera.getCameraInfo(i, cameraInfo);
255ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian        if (cameraInfo.facing == desiredFacing) {
256ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian          mCameraIndex = i;
257ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian          Camera.getCameraInfo(i, mCameraInfo);
258ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian          break;
259ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian        }
260ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      }
261ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian
262ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      // There's no camera in the desired facing direction, just select the first camera
263ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      // regardless of direction
264ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      if (mCameraIndex < 0) {
265ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian        mCameraIndex = 0;
266ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian        Camera.getCameraInfo(0, mCameraInfo);
267ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      }
268ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian
269ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      if (mOpenRequested) {
270ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian        // The camera is open, so reopen with the newly selected camera
271ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian        openCamera();
272ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      }
273ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      return true;
274ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    } catch (final RuntimeException e) {
275ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      LogUtil.e("CameraManager.selectCamera", "RuntimeException in CameraManager.selectCamera", e);
276ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      if (mListener != null) {
277ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian        mListener.onCameraError(ERROR_OPENING_CAMERA, e);
278ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      }
279ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      return false;
280ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    }
281ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  }
282ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian
283ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  public int getCameraIndex() {
284ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    return mCameraIndex;
285ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  }
286ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian
287ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  public void selectCameraByIndex(final int cameraIndex) {
288ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    if (mCameraIndex == cameraIndex) {
289ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      return;
290ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    }
291ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian
292ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    try {
293ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      mCameraIndex = cameraIndex;
294ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      Camera.getCameraInfo(mCameraIndex, mCameraInfo);
295ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      if (mOpenRequested) {
296ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian        openCamera();
297ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      }
298ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    } catch (final RuntimeException e) {
299ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      LogUtil.e(
300ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian          "CameraManager.selectCameraByIndex",
301ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian          "RuntimeException in CameraManager.selectCameraByIndex",
302ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian          e);
303ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      if (mListener != null) {
304ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian        mListener.onCameraError(ERROR_OPENING_CAMERA, e);
305ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      }
306ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    }
307ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  }
308ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian
309fc37b02f5d3381a7882770941e461b13b679b6efEric Erfanian  @Nullable
310ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  @VisibleForTesting
311ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  public CameraInfo getCameraInfo() {
312ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    if (mCameraIndex == NO_CAMERA_SELECTED) {
313ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      return null;
314ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    }
315ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    return mCameraInfo;
316ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  }
317ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian
318ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  /** @return True if the device has both a front and back camera */
319ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  public boolean hasFrontAndBackCamera() {
320ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    return mHasFrontAndBackCamera;
321ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  }
322ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian
323ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  /** Opens the camera on a separate thread and initiates the preview if one is available */
324ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  void openCamera() {
325ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    if (mCameraIndex == NO_CAMERA_SELECTED) {
326ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      // Ensure a selected camera if none is currently selected. This may happen if the
327ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      // camera chooser is not the default media chooser.
328ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      selectCamera(CameraInfo.CAMERA_FACING_BACK);
329ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    }
330ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    mOpenRequested = true;
331ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    // We're already opening the camera or already have the camera handle, nothing more to do
332ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    if (mPendingOpenCameraIndex == mCameraIndex || mCamera != null) {
333ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      return;
334ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    }
335ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian
336ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    // True if the task to open the camera has to be delayed until the current one completes
337ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    boolean delayTask = false;
338ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian
339ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    // Cancel any previous open camera tasks
340ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    if (mOpenCameraTask != null) {
341ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      mPendingOpenCameraIndex = NO_CAMERA_SELECTED;
342ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      delayTask = true;
343ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    }
344ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian
345ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    mPendingOpenCameraIndex = mCameraIndex;
346ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    mOpenCameraTask =
347ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian        new AsyncTask<Integer, Void, Camera>() {
348ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian          private Exception mException;
349ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian
350ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian          @Override
351ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian          protected Camera doInBackground(final Integer... params) {
352ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian            try {
353ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian              final int cameraIndex = params[0];
354ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian              LogUtil.v("CameraManager.doInBackground", "Opening camera " + mCameraIndex);
355ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian              return Camera.open(cameraIndex);
356ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian            } catch (final Exception e) {
357ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian              LogUtil.e("CameraManager.doInBackground", "Exception while opening camera", e);
358ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian              mException = e;
359ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian              return null;
360ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian            }
361ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian          }
362ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian
363ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian          @Override
364ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian          protected void onPostExecute(final Camera camera) {
365ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian            // If we completed, but no longer want this camera, then release the camera
366ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian            if (mOpenCameraTask != this || !mOpenRequested) {
367ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian              releaseCamera(camera);
368ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian              cleanup();
369ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian              return;
370ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian            }
371ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian
372ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian            cleanup();
373ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian
374ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian            LogUtil.v(
375ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian                "CameraManager.onPostExecute",
376ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian                "Opened camera " + mCameraIndex + " " + (camera != null));
377ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian            setCamera(camera);
378ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian            if (camera == null) {
379ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian              if (mListener != null) {
380ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian                mListener.onCameraError(ERROR_OPENING_CAMERA, mException);
381ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian              }
382ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian              LogUtil.e("CameraManager.onPostExecute", "Error opening camera");
383ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian            }
384ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian          }
385ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian
386ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian          @Override
387ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian          protected void onCancelled() {
388ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian            super.onCancelled();
389ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian            cleanup();
390ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian          }
391ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian
392ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian          private void cleanup() {
393ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian            mPendingOpenCameraIndex = NO_CAMERA_SELECTED;
394ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian            if (mOpenCameraTask != null && mOpenCameraTask.getStatus() == Status.PENDING) {
395ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian              // If there's another task waiting on this one to complete, start it now
396ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian              mOpenCameraTask.execute(mCameraIndex);
397ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian            } else {
398ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian              mOpenCameraTask = null;
399ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian            }
400ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian          }
401ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian        };
402ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    LogUtil.v("CameraManager.openCamera", "Start opening camera " + mCameraIndex);
403ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    if (!delayTask) {
404ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      mOpenCameraTask.execute(mCameraIndex);
405ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    }
406ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  }
407ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian
408ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  /** Closes the camera releasing the resources it uses */
409ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  void closeCamera() {
410ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    mOpenRequested = false;
411ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    setCamera(null);
412ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  }
413ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian
414ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  /**
415ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian   * Sets the listener which will be notified of errors or other events in the camera
416ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian   *
417ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian   * @param listener The listener to notify
418ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian   */
419ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  public void setListener(final CameraManagerListener listener) {
420ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    Assert.isMainThread();
421ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    mListener = listener;
422ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    if (!mIsHardwareAccelerationSupported && mListener != null) {
423ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      mListener.onCameraError(ERROR_HARDWARE_ACCELERATION_DISABLED, null);
424ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    }
425ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  }
426ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian
427ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  public void takePicture(final float heightPercent, @NonNull final MediaCallback callback) {
428ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    Assert.checkState(!mTakingPicture);
429ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    Assert.isNotNull(callback);
430ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    mCameraPreview.setFocusable(false);
431ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    mFocusOverlayManager.cancelAutoFocus();
432ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    if (mCamera == null) {
433ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      // The caller should have checked isCameraAvailable first, but just in case, protect
434ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      // against a null camera by notifying the callback that taking the picture didn't work
435ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      callback.onMediaFailed(null);
436ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      return;
437ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    }
438ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    final Camera.PictureCallback jpegCallback =
439ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian        new Camera.PictureCallback() {
440ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian          @Override
441ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian          public void onPictureTaken(final byte[] bytes, final Camera camera) {
442ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian            mTakingPicture = false;
443ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian            if (mCamera != camera) {
444ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian              // This may happen if the camera was changed between front/back while the
445ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian              // picture is being taken.
446ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian              callback.onMediaInfo(MediaCallback.MEDIA_CAMERA_CHANGED);
447ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian              return;
448ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian            }
449ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian
450ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian            if (bytes == null) {
451ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian              callback.onMediaInfo(MediaCallback.MEDIA_NO_DATA);
452ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian              return;
453ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian            }
454ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian
455ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian            final Camera.Size size = camera.getParameters().getPictureSize();
456ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian            int width;
457ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian            int height;
458ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian            if (mRotation == 90 || mRotation == 270) {
459ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian              // Is rotated, so swapping dimensions is desired
460ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian              //noinspection SuspiciousNameCombination
461ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian              width = size.height;
462ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian              //noinspection SuspiciousNameCombination
463ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian              height = size.width;
464ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian            } else {
465ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian              width = size.width;
466ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian              height = size.height;
467ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian            }
468ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian            LogUtil.i(
469ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian                "CameraManager.onPictureTaken", "taken picture size: " + bytes.length + " bytes");
470ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian            new ImagePersistTask(
471ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian                    width, height, heightPercent, bytes, mCameraPreview.getContext(), callback)
472ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian                .execute();
473ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian          }
474ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian        };
475ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian
476ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    mTakingPicture = true;
477ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    try {
478ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      mCamera.takePicture(
479ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian          // A shutter callback is required to enable shutter sound
480ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian          DUMMY_SHUTTER_CALLBACK, null /* raw */, null /* postView */, jpegCallback);
481ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    } catch (final RuntimeException e) {
482ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      LogUtil.e("CameraManager.takePicture", "RuntimeException in CameraManager.takePicture", e);
483ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      mTakingPicture = false;
484ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      if (mListener != null) {
485ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian        mListener.onCameraError(ERROR_TAKING_PICTURE, e);
486ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      }
487ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    }
488ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  }
489ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian
490ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  /**
491ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian   * Asynchronously releases a camera
492ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian   *
493ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian   * @param camera The camera to release
494ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian   */
495ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  private void releaseCamera(final Camera camera) {
496ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    if (camera == null) {
497ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      return;
498ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    }
499ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian
500ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    mFocusOverlayManager.onCameraReleased();
501ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian
502ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    new AsyncTask<Void, Void, Void>() {
503ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      @Override
504ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      protected Void doInBackground(final Void... params) {
505ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian        LogUtil.v("CameraManager.doInBackground", "Releasing camera " + mCameraIndex);
506ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian        camera.release();
507ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian        return null;
508ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      }
509ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    }.execute();
510ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  }
511ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian
5122f1c7586bcce334ca69022eb8dc6d8965ceb6a05Eric Erfanian  /**
5132f1c7586bcce334ca69022eb8dc6d8965ceb6a05Eric Erfanian   * Updates the orientation of the {@link Camera} w.r.t. the orientation of the device and the
5142f1c7586bcce334ca69022eb8dc6d8965ceb6a05Eric Erfanian   * orientation that the physical camera is mounted on the device.
5152f1c7586bcce334ca69022eb8dc6d8965ceb6a05Eric Erfanian   *
5162f1c7586bcce334ca69022eb8dc6d8965ceb6a05Eric Erfanian   * @param camera that needs to be reorientated
5172f1c7586bcce334ca69022eb8dc6d8965ceb6a05Eric Erfanian   * @param screenRotation rotation of the physical device
5182f1c7586bcce334ca69022eb8dc6d8965ceb6a05Eric Erfanian   * @param cameraOrientation {@link CameraInfo#orientation}
5192f1c7586bcce334ca69022eb8dc6d8965ceb6a05Eric Erfanian   * @param cameraIsFrontFacing {@link CameraInfo#CAMERA_FACING_FRONT}
5202f1c7586bcce334ca69022eb8dc6d8965ceb6a05Eric Erfanian   * @return rotation that images returned from {@link
5212f1c7586bcce334ca69022eb8dc6d8965ceb6a05Eric Erfanian   *     android.hardware.Camera.PictureCallback#onPictureTaken(byte[], Camera)} will be rotated.
5222f1c7586bcce334ca69022eb8dc6d8965ceb6a05Eric Erfanian   */
5232f1c7586bcce334ca69022eb8dc6d8965ceb6a05Eric Erfanian  @VisibleForTesting
5242f1c7586bcce334ca69022eb8dc6d8965ceb6a05Eric Erfanian  static int updateCameraRotation(
5252f1c7586bcce334ca69022eb8dc6d8965ceb6a05Eric Erfanian      @NonNull Camera camera,
5262f1c7586bcce334ca69022eb8dc6d8965ceb6a05Eric Erfanian      int screenRotation,
5272f1c7586bcce334ca69022eb8dc6d8965ceb6a05Eric Erfanian      int cameraOrientation,
5282f1c7586bcce334ca69022eb8dc6d8965ceb6a05Eric Erfanian      boolean cameraIsFrontFacing) {
5292f1c7586bcce334ca69022eb8dc6d8965ceb6a05Eric Erfanian    Assert.isNotNull(camera);
5302f1c7586bcce334ca69022eb8dc6d8965ceb6a05Eric Erfanian    Assert.checkArgument(cameraOrientation % 90 == 0);
5312f1c7586bcce334ca69022eb8dc6d8965ceb6a05Eric Erfanian
5322f1c7586bcce334ca69022eb8dc6d8965ceb6a05Eric Erfanian    int rotation = screenRotationToDegress(screenRotation);
5332f1c7586bcce334ca69022eb8dc6d8965ceb6a05Eric Erfanian    boolean portrait = rotation == 0 || rotation == 180;
5342f1c7586bcce334ca69022eb8dc6d8965ceb6a05Eric Erfanian
5352f1c7586bcce334ca69022eb8dc6d8965ceb6a05Eric Erfanian    if (!portrait && !cameraIsFrontFacing) {
5362f1c7586bcce334ca69022eb8dc6d8965ceb6a05Eric Erfanian      rotation += 180;
5372f1c7586bcce334ca69022eb8dc6d8965ceb6a05Eric Erfanian    }
5382f1c7586bcce334ca69022eb8dc6d8965ceb6a05Eric Erfanian    rotation += cameraOrientation;
5392f1c7586bcce334ca69022eb8dc6d8965ceb6a05Eric Erfanian    rotation %= 360;
5402f1c7586bcce334ca69022eb8dc6d8965ceb6a05Eric Erfanian
5412f1c7586bcce334ca69022eb8dc6d8965ceb6a05Eric Erfanian    // Rotate the camera
5422f1c7586bcce334ca69022eb8dc6d8965ceb6a05Eric Erfanian    if (portrait && cameraIsFrontFacing) {
5432f1c7586bcce334ca69022eb8dc6d8965ceb6a05Eric Erfanian      camera.setDisplayOrientation((rotation + 180) % 360);
5442f1c7586bcce334ca69022eb8dc6d8965ceb6a05Eric Erfanian    } else {
5452f1c7586bcce334ca69022eb8dc6d8965ceb6a05Eric Erfanian      camera.setDisplayOrientation(rotation);
546ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    }
547ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian
5482f1c7586bcce334ca69022eb8dc6d8965ceb6a05Eric Erfanian    // Rotate the images returned when a picture is taken
5492f1c7586bcce334ca69022eb8dc6d8965ceb6a05Eric Erfanian    Camera.Parameters params = camera.getParameters();
5502f1c7586bcce334ca69022eb8dc6d8965ceb6a05Eric Erfanian    params.setRotation(rotation);
5512f1c7586bcce334ca69022eb8dc6d8965ceb6a05Eric Erfanian    camera.setParameters(params);
5522f1c7586bcce334ca69022eb8dc6d8965ceb6a05Eric Erfanian    return rotation;
5532f1c7586bcce334ca69022eb8dc6d8965ceb6a05Eric Erfanian  }
554ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian
5552f1c7586bcce334ca69022eb8dc6d8965ceb6a05Eric Erfanian  private static int screenRotationToDegress(int screenRotation) {
5562f1c7586bcce334ca69022eb8dc6d8965ceb6a05Eric Erfanian    switch (screenRotation) {
557ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      case Surface.ROTATION_0:
5582f1c7586bcce334ca69022eb8dc6d8965ceb6a05Eric Erfanian        return 0;
559ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      case Surface.ROTATION_90:
5602f1c7586bcce334ca69022eb8dc6d8965ceb6a05Eric Erfanian        return 90;
561ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      case Surface.ROTATION_180:
5622f1c7586bcce334ca69022eb8dc6d8965ceb6a05Eric Erfanian        return 180;
563ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      case Surface.ROTATION_270:
5642f1c7586bcce334ca69022eb8dc6d8965ceb6a05Eric Erfanian        return 270;
565fc37b02f5d3381a7882770941e461b13b679b6efEric Erfanian      default:
5662f1c7586bcce334ca69022eb8dc6d8965ceb6a05Eric Erfanian        throw Assert.createIllegalStateFailException("Invalid surface rotation.");
567ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    }
568ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  }
569ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian
570ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  /** Sets the current camera, releasing any previously opened camera */
571ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  private void setCamera(final Camera camera) {
572ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    if (mCamera == camera) {
573ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      return;
574ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    }
575ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian
576ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    releaseCamera(mCamera);
577ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    mCamera = camera;
578ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    tryShowPreview();
579ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    if (mListener != null) {
580ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      mListener.onCameraChanged();
581ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    }
582ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  }
583ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian
584ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  /** Shows the preview if the camera is open and the preview is loaded */
585ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  private void tryShowPreview() {
586ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    if (mCameraPreview == null || mCamera == null) {
587ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      if (mOrientationHandler != null) {
588ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian        mOrientationHandler.disable();
589ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian        mOrientationHandler = null;
590ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      }
591ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      mFocusOverlayManager.onPreviewStopped();
592ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      return;
593ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    }
594ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    try {
595ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      mCamera.stopPreview();
5962f1c7586bcce334ca69022eb8dc6d8965ceb6a05Eric Erfanian      if (!mTakingPicture) {
5972f1c7586bcce334ca69022eb8dc6d8965ceb6a05Eric Erfanian        mRotation =
5982f1c7586bcce334ca69022eb8dc6d8965ceb6a05Eric Erfanian            updateCameraRotation(
5992f1c7586bcce334ca69022eb8dc6d8965ceb6a05Eric Erfanian                mCamera,
6002f1c7586bcce334ca69022eb8dc6d8965ceb6a05Eric Erfanian                getScreenRotation(),
6012f1c7586bcce334ca69022eb8dc6d8965ceb6a05Eric Erfanian                mCameraInfo.orientation,
6022f1c7586bcce334ca69022eb8dc6d8965ceb6a05Eric Erfanian                mCameraInfo.facing == CameraInfo.CAMERA_FACING_FRONT);
6032f1c7586bcce334ca69022eb8dc6d8965ceb6a05Eric Erfanian      }
604ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian
605ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      final Camera.Parameters params = mCamera.getParameters();
606ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      final Camera.Size pictureSize = chooseBestPictureSize();
607ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      final Camera.Size previewSize = chooseBestPreviewSize(pictureSize);
608ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      params.setPreviewSize(previewSize.width, previewSize.height);
609ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      params.setPictureSize(pictureSize.width, pictureSize.height);
610ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      logCameraSize("Setting preview size: ", previewSize);
611ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      logCameraSize("Setting picture size: ", pictureSize);
612ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      mCameraPreview.setSize(previewSize, mCameraInfo.orientation);
613ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      for (final String focusMode : params.getSupportedFocusModes()) {
614ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian        if (TextUtils.equals(focusMode, Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE)) {
615ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian          // Use continuous focus if available
616ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian          params.setFocusMode(focusMode);
617ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian          break;
618ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian        }
619ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      }
620ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian
621ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      mCamera.setParameters(params);
622ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      mCameraPreview.startPreview(mCamera);
623ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      mCamera.startPreview();
624ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      mCamera.setAutoFocusMoveCallback(
625ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian          new Camera.AutoFocusMoveCallback() {
626ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian            @Override
627ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian            public void onAutoFocusMoving(final boolean start, final Camera camera) {
628ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian              mFocusOverlayManager.onAutoFocusMoving(start);
629ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian            }
630ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian          });
631ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      mFocusOverlayManager.setParameters(mCamera.getParameters());
632ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      mFocusOverlayManager.setMirror(mCameraInfo.facing == CameraInfo.CAMERA_FACING_BACK);
633ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      mFocusOverlayManager.onPreviewStarted();
634ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      if (mOrientationHandler == null) {
635ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian        mOrientationHandler = new OrientationHandler(mCameraPreview.getContext());
636ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian        mOrientationHandler.enable();
637ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      }
638ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    } catch (final IOException e) {
639ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      LogUtil.e("CameraManager.tryShowPreview", "IOException in CameraManager.tryShowPreview", e);
640ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      if (mListener != null) {
641ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian        mListener.onCameraError(ERROR_SHOWING_PREVIEW, e);
642ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      }
643ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    } catch (final RuntimeException e) {
644ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      LogUtil.e(
645ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian          "CameraManager.tryShowPreview", "RuntimeException in CameraManager.tryShowPreview", e);
646ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      if (mListener != null) {
647ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian        mListener.onCameraError(ERROR_SHOWING_PREVIEW, e);
648ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      }
649ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    }
650ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  }
651ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian
6522f1c7586bcce334ca69022eb8dc6d8965ceb6a05Eric Erfanian  private int getScreenRotation() {
6532f1c7586bcce334ca69022eb8dc6d8965ceb6a05Eric Erfanian    return mCameraPreview
6542f1c7586bcce334ca69022eb8dc6d8965ceb6a05Eric Erfanian        .getContext()
6552f1c7586bcce334ca69022eb8dc6d8965ceb6a05Eric Erfanian        .getSystemService(WindowManager.class)
6562f1c7586bcce334ca69022eb8dc6d8965ceb6a05Eric Erfanian        .getDefaultDisplay()
6572f1c7586bcce334ca69022eb8dc6d8965ceb6a05Eric Erfanian        .getRotation();
6582f1c7586bcce334ca69022eb8dc6d8965ceb6a05Eric Erfanian  }
6592f1c7586bcce334ca69022eb8dc6d8965ceb6a05Eric Erfanian
660ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  public boolean isCameraAvailable() {
661ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    return mCamera != null && !mTakingPicture && mIsHardwareAccelerationSupported;
662ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  }
663ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian
664ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  /**
665ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian   * Choose the best picture size by trying to find a size close to the MmsConfig's max size, which
666ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian   * is closest to the screen aspect ratio. In case of RCS conversation returns default size.
667ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian   */
668ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  private Camera.Size chooseBestPictureSize() {
669ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    return mCamera.getParameters().getPictureSize();
670ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  }
671ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian
672ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  /**
673ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian   * Chose the best preview size based on the picture size. Try to find a size with the same aspect
674ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian   * ratio and size as the picture if possible
675ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian   */
676ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  private Camera.Size chooseBestPreviewSize(final Camera.Size pictureSize) {
677ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    final List<Camera.Size> sizes =
678ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian        new ArrayList<Camera.Size>(mCamera.getParameters().getSupportedPreviewSizes());
679ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    final float aspectRatio = pictureSize.width / (float) pictureSize.height;
680ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    final int capturePixels = pictureSize.width * pictureSize.height;
681ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian
682ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    // Sort the sizes so the best size is first
683ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    Collections.sort(
684ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian        sizes,
685ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian        new SizeComparator(Integer.MAX_VALUE, Integer.MAX_VALUE, aspectRatio, capturePixels));
686ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian
687ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    return sizes.get(0);
688ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  }
689ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian
690ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  private class OrientationHandler extends OrientationEventListener {
691ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    OrientationHandler(final Context context) {
692ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      super(context);
693ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    }
694ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian
695ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    @Override
696ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    public void onOrientationChanged(final int orientation) {
6972f1c7586bcce334ca69022eb8dc6d8965ceb6a05Eric Erfanian      if (!mTakingPicture) {
6982f1c7586bcce334ca69022eb8dc6d8965ceb6a05Eric Erfanian        mRotation =
6992f1c7586bcce334ca69022eb8dc6d8965ceb6a05Eric Erfanian            updateCameraRotation(
7002f1c7586bcce334ca69022eb8dc6d8965ceb6a05Eric Erfanian                mCamera,
7012f1c7586bcce334ca69022eb8dc6d8965ceb6a05Eric Erfanian                getScreenRotation(),
7022f1c7586bcce334ca69022eb8dc6d8965ceb6a05Eric Erfanian                mCameraInfo.orientation,
7032f1c7586bcce334ca69022eb8dc6d8965ceb6a05Eric Erfanian                mCameraInfo.facing == CameraInfo.CAMERA_FACING_FRONT);
7042f1c7586bcce334ca69022eb8dc6d8965ceb6a05Eric Erfanian      }
705ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    }
706ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  }
707ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian
708ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  private static class SizeComparator implements Comparator<Camera.Size> {
709ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    private static final int PREFER_LEFT = -1;
710ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    private static final int PREFER_RIGHT = 1;
711ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian
712ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    // The max width/height for the preferred size. Integer.MAX_VALUE if no size limit
713ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    private final int mMaxWidth;
714ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    private final int mMaxHeight;
715ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian
716ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    // The desired aspect ratio
717ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    private final float mTargetAspectRatio;
718ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian
719ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    // The desired size (width x height) to try to match
720ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    private final int mTargetPixels;
721ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian
722ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    public SizeComparator(
723ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian        final int maxWidth,
724ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian        final int maxHeight,
725ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian        final float targetAspectRatio,
726ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian        final int targetPixels) {
727ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      mMaxWidth = maxWidth;
728ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      mMaxHeight = maxHeight;
729ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      mTargetAspectRatio = targetAspectRatio;
730ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      mTargetPixels = targetPixels;
731ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    }
732ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian
733ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    /**
734ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian     * Returns a negative value if left is a better choice than right, or a positive value if right
735ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian     * is a better choice is better than left. 0 if they are equal
736ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian     */
737ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    @Override
738ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    public int compare(final Camera.Size left, final Camera.Size right) {
739ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      // If one size is less than the max size prefer it over the other
740ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      if ((left.width <= mMaxWidth && left.height <= mMaxHeight)
741ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian          != (right.width <= mMaxWidth && right.height <= mMaxHeight)) {
742ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian        return left.width <= mMaxWidth ? PREFER_LEFT : PREFER_RIGHT;
743ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      }
744ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian
745ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      // If one is closer to the target aspect ratio, prefer it.
746ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      final float leftAspectRatio = left.width / (float) left.height;
747ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      final float rightAspectRatio = right.width / (float) right.height;
748ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      final float leftAspectRatioDiff = Math.abs(leftAspectRatio - mTargetAspectRatio);
749ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      final float rightAspectRatioDiff = Math.abs(rightAspectRatio - mTargetAspectRatio);
750ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      if (leftAspectRatioDiff != rightAspectRatioDiff) {
751ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian        return (leftAspectRatioDiff - rightAspectRatioDiff) < 0 ? PREFER_LEFT : PREFER_RIGHT;
752ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      }
753ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian
754ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      // At this point they have the same aspect ratio diff and are either both bigger
755ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      // than the max size or both smaller than the max size, so prefer the one closest
756ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      // to target size
757ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      final int leftDiff = Math.abs((left.width * left.height) - mTargetPixels);
758ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      final int rightDiff = Math.abs((right.width * right.height) - mTargetPixels);
759ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      return leftDiff - rightDiff;
760ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    }
761ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  }
762ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian
763ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  @Override // From FocusOverlayManager.Listener
764ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  public void autoFocus() {
765ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    if (mCamera == null) {
766ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      return;
767ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    }
768ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian
769ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    try {
770ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      mCamera.autoFocus(
771ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian          new Camera.AutoFocusCallback() {
772ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian            @Override
773ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian            public void onAutoFocus(final boolean success, final Camera camera) {
774ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian              mFocusOverlayManager.onAutoFocus(success, false /* shutterDown */);
775ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian            }
776ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian          });
777ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    } catch (final RuntimeException e) {
778ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      LogUtil.e("CameraManager.autoFocus", "RuntimeException in CameraManager.autoFocus", e);
779ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      // If autofocus fails, the camera should have called the callback with success=false,
780ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      // but some throw an exception here
781ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      mFocusOverlayManager.onAutoFocus(false /*success*/, false /*shutterDown*/);
782ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    }
783ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  }
784ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian
785ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  @Override // From FocusOverlayManager.Listener
786ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  public void cancelAutoFocus() {
787ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    if (mCamera == null) {
788ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      return;
789ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    }
790ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    try {
791ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      mCamera.cancelAutoFocus();
792ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    } catch (final RuntimeException e) {
793ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      // Ignore
794ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      LogUtil.e(
795ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian          "CameraManager.cancelAutoFocus", "RuntimeException in CameraManager.cancelAutoFocus", e);
796ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    }
797ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  }
798ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian
799ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  @Override // From FocusOverlayManager.Listener
800ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  public boolean capture() {
801ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    return false;
802ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  }
803ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian
804ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  @Override // From FocusOverlayManager.Listener
805ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  public void setFocusParameters() {
806ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    if (mCamera == null) {
807ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      return;
808ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    }
809ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    try {
810ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      final Camera.Parameters parameters = mCamera.getParameters();
811ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      parameters.setFocusMode(mFocusOverlayManager.getFocusMode());
812ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      if (parameters.getMaxNumFocusAreas() > 0) {
813ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian        // Don't set focus areas (even to null) if focus areas aren't supported, camera may
814ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian        // crash
815ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian        parameters.setFocusAreas(mFocusOverlayManager.getFocusAreas());
816ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      }
817ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      parameters.setMeteringAreas(mFocusOverlayManager.getMeteringAreas());
818ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      mCamera.setParameters(parameters);
819ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    } catch (final RuntimeException e) {
820ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      // This occurs when the device is out of space or when the camera is locked
821ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      LogUtil.e(
822ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian          "CameraManager.setFocusParameters",
823ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian          "RuntimeException in CameraManager setFocusParameters");
824ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    }
825ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  }
826ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian
827ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  public void resetPreview() {
828ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    mCamera.startPreview();
829ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    if (mCameraPreview != null) {
830ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      mCameraPreview.setFocusable(true);
831ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    }
832ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  }
833ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian
834ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  private void logCameraSize(final String prefix, final Camera.Size size) {
835ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    // Log the camera size and aspect ratio for help when examining bug reports for camera
836ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    // failures
837ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    LogUtil.i(
838ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian        "CameraManager.logCameraSize",
839ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian        prefix + size.width + "x" + size.height + " (" + (size.width / (float) size.height) + ")");
840ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  }
841ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian
842ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  @VisibleForTesting
843ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  public void resetCameraManager() {
844ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    sInstance = null;
845ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  }
846ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian}
847