diff options
Diffstat (limited to 'src/com/android/camera/CaptureModule.java')
-rw-r--r-- | src/com/android/camera/CaptureModule.java | 285 |
1 files changed, 208 insertions, 77 deletions
diff --git a/src/com/android/camera/CaptureModule.java b/src/com/android/camera/CaptureModule.java index 604a705f3..555c2e3c0 100644 --- a/src/com/android/camera/CaptureModule.java +++ b/src/com/android/camera/CaptureModule.java @@ -42,6 +42,8 @@ import android.media.ImageReader; import android.net.Uri; import android.os.Handler; import android.os.HandlerThread; +import android.os.Looper; +import android.os.Message; import android.util.Log; import android.util.Size; import android.util.SparseIntArray; @@ -66,7 +68,11 @@ import java.util.concurrent.Semaphore; import java.util.concurrent.TimeUnit; public class CaptureModule implements CameraModule, PhotoController { - private static final int NUMCAM = 1; + public static final int DUAL_MODE = 0; + public static final int BAYER_MODE = 1; + public static final int MONO_MODE = 2; + private static final int OPEN_CAMERA = 0; + private static final int MAX_NUM_CAM = 3; /** * Conversion from screen rotation to JPEG orientation. */ @@ -91,7 +97,11 @@ public class CaptureModule implements CameraModule, PhotoController { * Camera state: Picture was taken. */ private static final int STATE_PICTURE_TAKEN = 4; + //Todo: Read ids from the device dynamically + private static final int BAYER_ID = 0; + private static final int MONO_ID = 1; private static final String TAG = "SnapCam_CaptureModule"; + private static int MODE = DUAL_MODE; static { ORIENTATIONS.append(Surface.ROTATION_0, 90); @@ -100,16 +110,17 @@ public class CaptureModule implements CameraModule, PhotoController { ORIENTATIONS.append(Surface.ROTATION_270, 180); } + private boolean mInitialized = false; private long mCaptureStartTime; private boolean mSurfaceReady = false; - private boolean mCameraOpened = false; - private CameraDevice[] mCameraDevice = new CameraDevice[NUMCAM]; - private String[] mCameraId = new String[NUMCAM]; + private boolean[] mCameraOpened = new boolean[MAX_NUM_CAM]; + private CameraDevice[] mCameraDevice = new CameraDevice[MAX_NUM_CAM]; + private String[] mCameraId = new String[MAX_NUM_CAM]; private CaptureUI mUI; private CameraActivity mActivity; private PreferenceGroup mPreferenceGroup; private ComboPreferences mPreferences; - private CaptureRequest.Builder[] mCaptureBuilder = new CaptureRequest.Builder[NUMCAM]; + private CaptureRequest.Builder[] mCaptureBuilder = new CaptureRequest.Builder[MAX_NUM_CAM]; private final CameraPreference.OnPreferenceChangedListener prefListener = new CameraPreference.OnPreferenceChangedListener() { @Override @@ -137,7 +148,7 @@ public class CaptureModule implements CameraModule, PhotoController { /** * A {@link CameraCaptureSession } for camera preview. */ - private CameraCaptureSession[] mCaptureSession = new CameraCaptureSession[NUMCAM]; + private CameraCaptureSession[] mCaptureSession = new CameraCaptureSession[MAX_NUM_CAM]; /** * An additional thread for running tasks that shouldn't block the UI. */ @@ -153,7 +164,7 @@ public class CaptureModule implements CameraModule, PhotoController { /** * An {@link ImageReader} that handles still image capture. */ - private ImageReader[] mImageReader = new ImageReader[NUMCAM]; + private ImageReader[] mImageReader = new ImageReader[MAX_NUM_CAM]; private NamedImages mNamedImages; private ContentResolver mContentResolver; private MediaSaveService.OnMediaSavedListener mOnMediaSavedListener = @@ -174,6 +185,7 @@ public class CaptureModule implements CameraModule, PhotoController { @Override public void onImageAvailable(ImageReader reader) { + Log.d(TAG, "image available"); mCaptureStartTime = System.currentTimeMillis(); mNamedImages.nameNewImage(mCaptureStartTime); NamedEntity name = mNamedImages.getNextNameEntity(); @@ -182,30 +194,31 @@ public class CaptureModule implements CameraModule, PhotoController { Image mImage = reader.acquireNextImage(); ByteBuffer buffer = mImage.getPlanes()[0].getBuffer(); + //Todo: dont create new buffer and use the one from ImageReader byte[] bytes = new byte[buffer.remaining()]; buffer.get(bytes); mActivity.getMediaSaveService().addImage( bytes, title, date, null, reader.getWidth(), reader.getHeight(), 0, null, mOnMediaSavedListener, mContentResolver, "jpeg"); + mImage.close(); } }; - /** * {@link CaptureRequest.Builder} for the camera preview */ - private CaptureRequest.Builder[] mPreviewRequestBuilder = new CaptureRequest.Builder[NUMCAM]; + private CaptureRequest.Builder[] mPreviewRequestBuilder = new CaptureRequest.Builder[MAX_NUM_CAM]; /** * {@link CaptureRequest} generated by {@link #mPreviewRequestBuilder} */ - private CaptureRequest[] mPreviewRequest = new CaptureRequest[NUMCAM]; + private CaptureRequest[] mPreviewRequest = new CaptureRequest[MAX_NUM_CAM]; /** * The current state of camera state for taking pictures. * * @see #mCaptureCallback */ - private int mState = STATE_PREVIEW; + private int[] mState = new int[MAX_NUM_CAM]; /** * A {@link Semaphore} make sure the camera open callback happens first before closing the * camera. @@ -218,23 +231,26 @@ public class CaptureModule implements CameraModule, PhotoController { = new CameraCaptureSession.CaptureCallback() { private void process(CaptureResult result) { - switch (mState) { + int id = (int) result.getRequest().getTag(); + switch (mState[id]) { case STATE_PREVIEW: { - // We have nothing to do when the camera preview is working normally. break; } case STATE_WAITING_LOCK: { Integer afState = result.get(CaptureResult.CONTROL_AF_STATE); - if (CaptureResult.CONTROL_AF_STATE_FOCUSED_LOCKED == afState || + Integer aeState = result.get(CaptureResult.CONTROL_AE_STATE); + if (afState == null) { + captureStillPicture(id); + } else if (CaptureResult.CONTROL_AF_STATE_FOCUSED_LOCKED == afState || CaptureResult.CONTROL_AF_STATE_NOT_FOCUSED_LOCKED == afState) { // CONTROL_AE_STATE can be null on some devices - Integer aeState = result.get(CaptureResult.CONTROL_AE_STATE); + if (aeState == null || aeState == CaptureResult.CONTROL_AE_STATE_CONVERGED) { - mState = STATE_PICTURE_TAKEN; - captureStillPicture(0); + mState[id] = STATE_PICTURE_TAKEN; + captureStillPicture(id); } else { - runPrecaptureSequence(0); + runPrecaptureSequence(id); } } break; @@ -245,7 +261,7 @@ public class CaptureModule implements CameraModule, PhotoController { if (aeState == null || aeState == CaptureResult.CONTROL_AE_STATE_PRECAPTURE || aeState == CaptureRequest.CONTROL_AE_STATE_FLASH_REQUIRED) { - mState = STATE_WAITING_NON_PRECAPTURE; + mState[id] = STATE_WAITING_NON_PRECAPTURE; } break; } @@ -253,8 +269,8 @@ public class CaptureModule implements CameraModule, PhotoController { // CONTROL_AE_STATE can be null on some devices Integer aeState = result.get(CaptureResult.CONTROL_AE_STATE); if (aeState == null || aeState != CaptureResult.CONTROL_AE_STATE_PRECAPTURE) { - mState = STATE_PICTURE_TAKEN; - captureStillPicture(0); + mState[id] = STATE_PICTURE_TAKEN; + captureStillPicture(id); } break; } @@ -274,61 +290,91 @@ public class CaptureModule implements CameraModule, PhotoController { TotalCaptureResult result) { process(result); } - }; private final CameraDevice.StateCallback mStateCallback = new CameraDevice.StateCallback() { @Override public void onOpened(CameraDevice cameraDevice) { int id = Integer.parseInt(cameraDevice.getId()); - + Log.d(TAG, "onOpened " + id); mCameraOpenCloseLock.release(); - - PreferenceInflater inflater = new PreferenceInflater(mActivity); - PreferenceGroup group = - (PreferenceGroup) inflater.inflate(R.xml.camera_preferences); - mPreferenceGroup = group; - mActivity.runOnUiThread(new Runnable() { - @Override - public void run() { - mUI.onCameraOpened(mPreferenceGroup, prefListener); - } - - - }); + if (MODE == DUAL_MODE && id == BAYER_ID) { + Message msg = Message.obtain(); + msg.what = OPEN_CAMERA; + msg.arg1 = MONO_ID; + mCameraHandler.sendMessage(msg); + } + if (!mInitialized) { + mInitialized = true; + mActivity.runOnUiThread(new Runnable() { + @Override + public void run() { + mUI.onCameraOpened(mPreferenceGroup, prefListener); + } + }); + } mCameraDevice[id] = cameraDevice; - mCameraOpened = true; + mCameraOpened[id] = true; createSession(id); } @Override public void onDisconnected(CameraDevice cameraDevice) { - mCameraOpenCloseLock.release(); + int id = Integer.parseInt(cameraDevice.getId()); + Log.d(TAG, "onDisconnected " + id); cameraDevice.close(); mCameraDevice = null; + mCameraOpenCloseLock.release(); } @Override public void onError(CameraDevice cameraDevice, int error) { int id = Integer.parseInt(cameraDevice.getId()); - mCameraOpenCloseLock.release(); + Log.d(TAG, "onError " + id + error); cameraDevice.close(); - mCameraDevice = null; + mCameraDevice[id] = null; + mCameraOpenCloseLock.release(); if (null != mActivity) { mActivity.finish(); } } + @Override + public void onClosed(CameraDevice cameraDevice) { + int id = Integer.parseInt(cameraDevice.getId()); + Log.d(TAG, "onClosed " + id); + mCameraDevice[id] = null; + mCameraOpenCloseLock.release(); + } + }; + public static boolean setMode(String value) { + int mode = DUAL_MODE; + switch (value) { + case "dual": + mode = DUAL_MODE; + break; + case "bayer": + mode = BAYER_MODE; + break; + case "mono": + mode = MONO_MODE; + break; + } + if (MODE == mode) return false; + MODE = mode; + return true; + } + private void createSession(final int id) { - if (!mCameraOpened || !mSurfaceReady) return; + if (!mCameraOpened[id] || !mSurfaceReady) return; List<Surface> list = new LinkedList<Surface>(); mUI.hidePreviewCover(); try { Surface surface; - if (id == 0) { + if (id == BAYER_ID || (id == MONO_ID && MODE == MONO_MODE)) { SurfaceHolder sh = mUI.getSurfaceHolder(); if (sh == null) { return; @@ -345,6 +391,13 @@ public class CaptureModule implements CameraModule, PhotoController { mPreviewRequestBuilder[id] = mCameraDevice[id].createCaptureRequest(CameraDevice .TEMPLATE_PREVIEW); mPreviewRequestBuilder[id].addTarget(surface); + // Auto focus should be continuous for camera preview. + mPreviewRequestBuilder[id].set(CaptureRequest.CONTROL_AF_MODE, + CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE); + // Flash is automatically enabled when necessary. + mPreviewRequestBuilder[id].set(CaptureRequest.CONTROL_AE_MODE, + CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH); + mPreviewRequestBuilder[id].setTag(id); // This is the CaptureRequest.Builder that we use to take a picture. mCaptureBuilder[id] = @@ -372,18 +425,10 @@ public class CaptureModule implements CameraModule, PhotoController { // When the session is ready, we start displaying the preview. mCaptureSession[id] = cameraCaptureSession; try { - // Auto focus should be continuous for camera preview. - mPreviewRequestBuilder[id].set(CaptureRequest.CONTROL_AF_MODE, - CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE); - // Flash is automatically enabled when necessary. - mPreviewRequestBuilder[id].set(CaptureRequest.CONTROL_AE_MODE, - CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH); - // Finally, we start displaying the camera preview. mPreviewRequest[id] = mPreviewRequestBuilder[id].build(); mCaptureSession[id].setRepeatingRequest(mPreviewRequest[id], mCaptureCallback, mCameraHandler); - applyAllSettings(0); } catch (CameraAccessException e) { e.printStackTrace(); } @@ -401,16 +446,31 @@ public class CaptureModule implements CameraModule, PhotoController { @Override public void init(CameraActivity activity, View parent) { - mCameraOpened = false; + Log.d(TAG, "init"); + for (int i = 0; i < MAX_NUM_CAM; i++) { + mCameraOpened[i] = false; + } mSurfaceReady = false; + mActivity = activity; + for (int i = 0; i < MAX_NUM_CAM; i++) { + mState[i] = STATE_PREVIEW; + } mPreferences = new ComboPreferences(mActivity); CameraSettings.upgradeGlobalPreferences(mPreferences.getGlobal(), activity); - mPreferences.setLocalId(mActivity, 0); + mPreferences.setLocalId(mActivity, BAYER_ID); CameraSettings.upgradeLocalPreferences(mPreferences.getLocal()); + PreferenceInflater inflater = new PreferenceInflater(mActivity); + PreferenceGroup group = + (PreferenceGroup) inflater.inflate(R.xml.camera_preferences); + mPreferenceGroup = group; + + ListPreference pref = group.findPreference(CameraSettings.KEY_DUAL_CAMERA); + setMode(pref.getValue()); + mContentResolver = mActivity.getContentResolver(); mUI = new CaptureUI(activity, this, parent); mUI.initializeControlByIntent(); @@ -421,19 +481,32 @@ public class CaptureModule implements CameraModule, PhotoController { * Initiate a still image capture. */ private void takePicture() { - lockFocus(0); + Log.d(TAG, "takePicture"); + switch (MODE) { + case DUAL_MODE: + lockFocus(BAYER_ID); + lockFocus(MONO_ID); + break; + case BAYER_MODE: + lockFocus(BAYER_ID); + break; + case MONO_MODE: + lockFocus(MONO_ID); + break; + } } /** * Lock the focus as the first step for a still image capture. */ private void lockFocus(int id) { + Log.d(TAG, "lockFocus " + id); try { // This is how to tell the camera to lock focus. mPreviewRequestBuilder[id].set(CaptureRequest.CONTROL_AF_TRIGGER, CameraMetadata.CONTROL_AF_TRIGGER_START); // Tell #mCaptureCallback to wait for the lock. - mState = STATE_WAITING_LOCK; + mState[id] = STATE_WAITING_LOCK; mCaptureSession[id].capture(mPreviewRequestBuilder[id].build(), mCaptureCallback, mCameraHandler); } catch (CameraAccessException e) { @@ -446,6 +519,7 @@ public class CaptureModule implements CameraModule, PhotoController { * {@link #mCaptureCallback} from both {@link #lockFocus()}. */ private void captureStillPicture(final int id) { + Log.d(TAG, "captureStillPicture " + id); try { if (null == mActivity || null == mCameraDevice) { return; @@ -467,11 +541,13 @@ public class CaptureModule implements CameraModule, PhotoController { public void onCaptureCompleted(CameraCaptureSession session, CaptureRequest request, TotalCaptureResult result) { + Log.d(TAG, "captureStillPicture onCaptureCompleted"); } @Override public void onCaptureSequenceCompleted(CameraCaptureSession session, int sequenceId, long frameNumber) { + Log.d(TAG, "captureStillPicture onCaptureSequenceCompleted"); unlockFocus(id); } @@ -493,7 +569,7 @@ public class CaptureModule implements CameraModule, PhotoController { mPreviewRequestBuilder[id].set(CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER, CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER_START); // Tell #mCaptureCallback to wait for the precapture sequence to be set. - mState = STATE_WAITING_PRECAPTURE; + mState[id] = STATE_WAITING_PRECAPTURE; mCaptureSession[id].capture(mPreviewRequestBuilder[id].build(), mCaptureCallback, mCameraHandler); } catch (CameraAccessException e) { @@ -512,7 +588,8 @@ public class CaptureModule implements CameraModule, PhotoController { CameraManager manager = (CameraManager) activity.getSystemService(Context.CAMERA_SERVICE); try { String[] cameraIdList = manager.getCameraIdList(); - for (int i = 0; i < NUMCAM; i++) { + + for (int i = 0; i < cameraIdList.length; i++) { String cameraId = cameraIdList[i]; CameraCharacteristics characteristics = manager.getCameraCharacteristics(cameraId); @@ -529,11 +606,10 @@ public class CaptureModule implements CameraModule, PhotoController { new CompareSizesByArea()); mImageReader[i] = ImageReader.newInstance(largest.getWidth(), largest.getHeight(), - ImageFormat.JPEG, 10); + ImageFormat.JPEG, 3); mImageReader[i].setOnImageAvailableListener( mOnImageAvailableListener, mImageAvailableHandler); mCameraId[i] = cameraId; - //return; } } catch (CameraAccessException e) { e.printStackTrace(); @@ -546,6 +622,7 @@ public class CaptureModule implements CameraModule, PhotoController { * finished. */ private void unlockFocus(int id) { + Log.d(TAG, "unlockFocus " + id); try { // Reset the auto-focus trigger mPreviewRequestBuilder[id].set(CaptureRequest.CONTROL_AF_TRIGGER, @@ -555,7 +632,7 @@ public class CaptureModule implements CameraModule, PhotoController { mCaptureSession[id].capture(mPreviewRequestBuilder[id].build(), mCaptureCallback, mCameraHandler); // After this, the camera will go back to the normal state of preview. - mState = STATE_PREVIEW; + mState[id] = STATE_PREVIEW; mCaptureSession[id].setRepeatingRequest(mPreviewRequest[id], mCaptureCallback, mCameraHandler); } catch (CameraAccessException e) { @@ -567,24 +644,28 @@ public class CaptureModule implements CameraModule, PhotoController { * Closes the current {@link CameraDevice}. */ private void closeCamera() { + Log.d(TAG, "closeCamera"); try { mCameraOpenCloseLock.acquire(); - for (int i = 0; i < NUMCAM; i++) { + for (int i = 0; i < MAX_NUM_CAM; i++) { if (null != mCaptureSession[i]) { mCaptureSession[i].close(); mCaptureSession[i] = null; } - if (null != mCameraDevice[i]) { - mCameraDevice[i].close(); - mCameraDevice[i] = null; - mCameraOpened = false; - } if (null != mImageReader[i]) { mImageReader[i].close(); mImageReader[i] = null; } } + for (int i = 0; i < MAX_NUM_CAM; i++) { + if (null != mCameraDevice[i]) { + mCameraDevice[i].close(); + mCameraDevice[i] = null; + mCameraOpened[i] = false; + } + } } catch (InterruptedException e) { + mCameraOpenCloseLock.release(); throw new RuntimeException("Interrupted while trying to lock camera closing.", e); } finally { mCameraOpenCloseLock.release(); @@ -602,7 +683,7 @@ public class CaptureModule implements CameraModule, PhotoController { mCallbackThread = new HandlerThread("CameraCallback"); mCallbackThread.start(); - mCameraHandler = new Handler(mCameraThread.getLooper()); + mCameraHandler = new MyCameraHandler(mCameraThread.getLooper()); mImageAvailableHandler = new Handler(mImageAvailableThread.getLooper()); mCallbackHandler = new Handler(mCallbackThread.getLooper()); } @@ -638,12 +719,14 @@ public class CaptureModule implements CameraModule, PhotoController { } private void openCamera(int id) { + Log.d(TAG, "openCamera " + id); CameraManager manager; try { manager = (CameraManager) mActivity.getSystemService(Context.CAMERA_SERVICE); mCameraId[id] = manager.getCameraIdList()[id]; - if (!mCameraOpenCloseLock.tryAcquire(2500, TimeUnit.MILLISECONDS)) { + if (!mCameraOpenCloseLock.tryAcquire(5000, TimeUnit.MILLISECONDS)) { Log.d(TAG, "Time out waiting to lock camera opening."); + throw new RuntimeException("Time out waiting to lock camera opening"); } manager.openCamera(mCameraId[id], mStateCallback, mCameraHandler); } catch (CameraAccessException e) { @@ -665,6 +748,7 @@ public class CaptureModule implements CameraModule, PhotoController { @Override public void onPauseAfterSuper() { + Log.d(TAG, "onPause"); mUI.showPreviewCover(); stopBackgroundThread(); closeCamera(); @@ -678,9 +762,23 @@ public class CaptureModule implements CameraModule, PhotoController { @Override public void onResumeAfterSuper() { + Log.d(TAG, "onResume " + MODE); setUpCameraOutputs(); - openCamera(0); startBackgroundThread(); + Message msg = Message.obtain(); + msg.what = OPEN_CAMERA; + switch (MODE) { + case DUAL_MODE: + case BAYER_MODE: + msg.arg1 = BAYER_ID; + mCameraHandler.sendMessage(msg); + break; + case MONO_MODE: + msg.what = OPEN_CAMERA; + msg.arg1 = MONO_ID; + mCameraHandler.sendMessage(msg); + break; + } mUI.hidePreviewCover(); mUI.enableShutter(true); mUI.initializeFirstTime(); @@ -798,8 +896,20 @@ public class CaptureModule implements CameraModule, PhotoController { @Override public void onPreviewUIReady() { + Log.d(TAG, "onPreviewUIReady"); mSurfaceReady = true; - createSession(0); + switch (MODE) { + case DUAL_MODE: + createSession(BAYER_ID); + createSession(MONO_ID); + break; + case BAYER_MODE: + createSession(BAYER_ID); + break; + case MONO_MODE: + createSession(MONO_ID); + break; + } } @Override @@ -873,24 +983,26 @@ public class CaptureModule implements CameraModule, PhotoController { } private void applyPreference(int cameraId, ListPreference pref) { - if (pref.getKey().equals(CameraSettings.KEY_FLASH_MODE)) { - if (pref.getValue().equals("on")) { + String key = pref.getKey(); + String value = pref.getValue(); + if (key.equals(CameraSettings.KEY_FLASH_MODE)) { + if (value.equals("on")) { mCaptureBuilder[cameraId].set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON_ALWAYS_FLASH); - } else if (pref.getValue().equals("auto")) { + } else if (value.equals("auto")) { mCaptureBuilder[cameraId].set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH); - } else if (pref.getValue().equals("off")) { + } else if (value.equals("off")) { mCaptureBuilder[cameraId].set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON); } + } else if (key.equals(CameraSettings.KEY_MONO_PREVIEW)) { + if (value.equals("on")) { + } else if (value.equals("off")) { + } } } - private void applyAllSettings(int cameraId) { - - } - /** * Compares two {@code Size}s based on their areas. */ @@ -904,4 +1016,23 @@ public class CaptureModule implements CameraModule, PhotoController { } } + + private class MyCameraHandler extends Handler { + + public MyCameraHandler(Looper looper) { + super(looper); + } + + @Override + public void handleMessage(Message msg) { + switch (msg.what) { + case OPEN_CAMERA: { + int id = msg.arg1; + openCamera(id); + break; + } + } + } + } + } |