diff options
author | Shuzhen Wang <shuzhenwang@google.com> | 2018-05-10 13:21:10 -0700 |
---|---|---|
committer | android-build-merger <android-build-merger@google.com> | 2018-05-10 13:21:10 -0700 |
commit | 5aaa1df87c426e557edd0e1a667f2ac84a255342 (patch) | |
tree | ab23c5617c51a1729c89f79de6ae1019fffdd5a9 /apps | |
parent | b4ca4f367c1d8baeb47f0fee25e4d3e6419b21c8 (diff) | |
parent | 20f8673a5e1d916d1591eb302fd938fb32896bd8 (diff) | |
download | pdk-5aaa1df87c426e557edd0e1a667f2ac84a255342.tar.gz |
TestingCamera2: Add new functionalities am: 78a60a74ac
am: 20f8673a5e
Change-Id: I5010174bf9fbdf97698088b83950d3397b321210
Diffstat (limited to 'apps')
4 files changed, 162 insertions, 24 deletions
diff --git a/apps/TestingCamera2/res/layout/main.xml b/apps/TestingCamera2/res/layout/main.xml index ad12d43..488265d 100644 --- a/apps/TestingCamera2/res/layout/main.xml +++ b/apps/TestingCamera2/res/layout/main.xml @@ -39,6 +39,11 @@ android:layout_width="240dp" android:layout_height="180dp" /> + <SurfaceView + android:id="@+id/preview_view2" + android:layout_width="240dp" + android:layout_height="180dp" /> + </GridLayout> <ScrollView @@ -54,6 +59,14 @@ android:layout_marginLeft="5dp" android:orientation="vertical" > + <Spinner + android:id="@+id/camera_id_spinner" + android:layout_width="fill_parent" + android:layout_height="wrap_content" + android:spinnerMode="dropdown" + android:prompt="@string/camera_id_spinner_prompt" + /> + <Button android:id="@+id/info_button" android:text="@string/info_button_label" diff --git a/apps/TestingCamera2/res/values/strings.xml b/apps/TestingCamera2/res/values/strings.xml index 5f749aa..c3bc711 100644 --- a/apps/TestingCamera2/res/values/strings.xml +++ b/apps/TestingCamera2/res/values/strings.xml @@ -86,6 +86,7 @@ <!-- V1 strings --> <string name="v1_app_name">TestingCam2</string> + <string name="camera_id_spinner_prompt">Camera Id</string> <string name="info_button_label">JPEG!</string> <string name="flush_button_label">Flush device</string> <string name="focus_lock_button_label">Focus Lock</string> diff --git a/apps/TestingCamera2/src/com/android/testingcamera2/v1/CameraOps.java b/apps/TestingCamera2/src/com/android/testingcamera2/v1/CameraOps.java index aae07e9..753fa00 100644 --- a/apps/TestingCamera2/src/com/android/testingcamera2/v1/CameraOps.java +++ b/apps/TestingCamera2/src/com/android/testingcamera2/v1/CameraOps.java @@ -26,6 +26,7 @@ import android.hardware.camera2.CameraMetadata; import android.hardware.camera2.CameraCharacteristics; import android.hardware.camera2.CaptureRequest; import android.hardware.camera2.CaptureRequest.Builder; +import android.hardware.camera2.params.OutputConfiguration; import android.util.Size; import android.media.Image; import android.media.ImageReader; @@ -45,6 +46,7 @@ import com.android.ex.camera2.blocking.BlockingSessionCallback; import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import java.util.Set; /** * A camera controller class that runs in its own thread, to @@ -67,6 +69,7 @@ public class CameraOps { private final BlockingStateCallback mDeviceListener = new BlockingStateCallback(); + private String mCameraId; private CameraDevice mCamera; private CameraCaptureSession mSession; @@ -80,6 +83,7 @@ public class CameraOps { private CaptureRequest.Builder mRecordingRequestBuilder; List<Surface> mOutputSurfaces = new ArrayList<Surface>(2); private Surface mPreviewSurface; + private Surface mPreviewSurface2; // How many JPEG buffers do we want to hold on to at once private static final int MAX_CONCURRENT_JPEGS = 2; @@ -103,6 +107,11 @@ public class CameraOps { private final Listener mListener; private final Handler mListenerHandler; + // Physical camera id of the current logical multi-camera. "" if this is not a logical + // multi-camera. + private String mPhysicalCameraId1; + private String mPhysicalCameraId2; + private void checkOk() { if (mStatus < STATUS_OK) { throw new IllegalStateException(String.format("Device not OK: %d", mStatus )); @@ -173,18 +182,36 @@ public class CameraOps { } private void minimalOpenCamera() throws ApiFailureException { - if (mCamera == null) { - final String[] devices; - final CameraCharacteristics characteristics; + // Open camera if not yet opened, or the currently opened camera is not the right one. + if (mCamera == null || !mCameraId.equals(mCamera.getId())) { + closeDevice(); + mPhysicalCameraId1 = ""; + mPhysicalCameraId2 = ""; + final CameraCharacteristics characteristics; try { - devices = mCameraManager.getCameraIdList(); - if (devices == null || devices.length == 0) { - throw new ApiFailureException("no devices"); + CameraCharacteristics c = mCameraManager.getCameraCharacteristics(mCameraId); + int[] caps = c.get(CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES); + for (int cap : caps) { + if (CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_LOGICAL_MULTI_CAMERA + != cap) { + continue; + } + + Set<String> physicalIds = c.getPhysicalCameraIds(); + if (physicalIds.size() != 2) { + throw new ApiFailureException( + "3 or more physical cameras are not yet supported"); + } + String[] physicalIdsArray = physicalIds.toArray(new String[2]); + mPhysicalCameraId1 = physicalIdsArray[0]; + mPhysicalCameraId2 = physicalIdsArray[1]; + break; } - mCamera = mBlockingCameraManager.openCamera(devices[0], + Log.i(TAG, "Opening " + mCameraId); + mCamera = mBlockingCameraManager.openCamera(mCameraId, mDeviceListener, mOpsHandler); - mCameraCharacteristics = mCameraManager.getCameraCharacteristics(mCamera.getId()); + mCameraCharacteristics = mCameraManager.getCameraCharacteristics(mCameraId); characteristics = mCameraCharacteristics; } catch (CameraAccessException e) { throw new ApiFailureException("open failure", e); @@ -197,7 +224,7 @@ public class CameraOps { mListenerHandler.post(new Runnable() { @Override public void run() { - mListener.onCameraOpened(devices[0], characteristics); + mListener.onCameraOpened(mCameraId, characteristics); } }); } @@ -212,11 +239,20 @@ public class CameraOps { mSession = sessionListener.waitAndGetSession(IDLE_WAIT_MS); } + private void configureOutputsByConfigs(List<OutputConfiguration> outputConfigs) + throws CameraAccessException { + BlockingSessionCallback sessionListener = new BlockingSessionCallback(); + mCamera.createCaptureSessionByOutputConfigurations(outputConfigs, sessionListener, mOpsHandler); + mSession = sessionListener.waitAndGetSession(IDLE_WAIT_MS); + } + /** * Set up SurfaceView dimensions for camera preview */ - public void minimalPreviewConfig(SurfaceHolder previewHolder) throws ApiFailureException { + public void minimalPreviewConfig(String cameraId, SurfaceHolder previewHolder, + SurfaceHolder previewHolder2) throws ApiFailureException { + mCameraId = cameraId; minimalOpenCamera(); try { CameraCharacteristics properties = @@ -236,7 +272,9 @@ public class CameraOps { } Log.i(TAG, "Set preview size to " + sz.toString()); previewHolder.setFixedSize(sz.getWidth(), sz.getHeight()); + previewHolder2.setFixedSize(sz.getWidth(), sz.getHeight()); mPreviewSurface = previewHolder.getSurface(); + mPreviewSurface2 = previewHolder2.getSurface(); } catch (CameraAccessException e) { throw new ApiFailureException("Error setting up minimal preview", e); } @@ -329,24 +367,40 @@ public class CameraOps { /** * Configure streams and run minimal preview */ - public void minimalPreview(SurfaceHolder previewHolder, CameraControls camCtl) - throws ApiFailureException { + public void minimalPreview(SurfaceHolder previewHolder, SurfaceHolder previewHolder2, + CameraControls camCtl) throws ApiFailureException { minimalOpenCamera(); - if (mPreviewSurface == null) { + if (mPreviewSurface == null || mPreviewSurface2 == null) { throw new ApiFailureException("Preview surface is not created"); } try { - List<Surface> outputSurfaces = new ArrayList<Surface>(/*capacity*/1); - outputSurfaces.add(mPreviewSurface); - - configureOutputs(outputSurfaces); + List<OutputConfiguration> outputConfigs = + new ArrayList<OutputConfiguration>(/*capacity*/2); + boolean isLogicalCamera = + !mPhysicalCameraId1.equals("") && !mPhysicalCameraId2.equals(""); + if (isLogicalCamera) { + OutputConfiguration config1 = new OutputConfiguration(previewHolder.getSurface()); + config1.setPhysicalCameraId(mPhysicalCameraId1); + outputConfigs.add(config1); + + OutputConfiguration config2 = new OutputConfiguration(previewHolder2.getSurface()); + config2.setPhysicalCameraId(mPhysicalCameraId2); + outputConfigs.add(config2); + } else { + OutputConfiguration config = new OutputConfiguration(previewHolder.getSurface()); + outputConfigs.add(config); + } + configureOutputsByConfigs(outputConfigs); mPreviewRequestBuilder = mCamera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW); updateCaptureRequest(mPreviewRequestBuilder, camCtl); mPreviewRequestBuilder.addTarget(mPreviewSurface); + if (isLogicalCamera) { + mPreviewRequestBuilder.addTarget(mPreviewSurface2); + } mSession.setRepeatingRequest(mPreviewRequestBuilder.build(), null, null); } catch (CameraAccessException e) { diff --git a/apps/TestingCamera2/src/com/android/testingcamera2/v1/TestingCamera2.java b/apps/TestingCamera2/src/com/android/testingcamera2/v1/TestingCamera2.java index 9bd3113..7a4a9b5 100644 --- a/apps/TestingCamera2/src/com/android/testingcamera2/v1/TestingCamera2.java +++ b/apps/TestingCamera2/src/com/android/testingcamera2/v1/TestingCamera2.java @@ -71,6 +71,8 @@ public class TestingCamera2 extends Activity implements SurfaceHolder.Callback { private static final String TAG = "TestingCamera2"; private static final boolean VERBOSE = Log.isLoggable(TAG, Log.VERBOSE); private CameraOps mCameraOps; + private String[] mAvailableCameraIds; + private String mCameraId; private static final int mSeekBarMax = 100; private static final long MAX_EXPOSURE = 200000000L; // 200ms private static final long MIN_EXPOSURE = 100000L; // 100us @@ -85,10 +87,14 @@ public class TestingCamera2 extends Activity implements SurfaceHolder.Callback { private int mLastOrientation = ORIENTATION_UNINITIALIZED; private OrientationEventListener mOrientationEventListener; private SurfaceView mPreviewView; + private SurfaceView mPreviewView2; private ImageView mStillView; private SurfaceHolder mCurrentPreviewHolder = null; + private SurfaceHolder mCurrentPreviewHolder2 = null; + private Spinner mCameraIdSpinner; + private OnItemSelectedListener mCameraIdSelectionListener; private Button mInfoButton; private Button mFlushButton; private ToggleButton mFocusLockToggle; @@ -127,8 +133,12 @@ public class TestingCamera2 extends Activity implements SurfaceHolder.Callback { mPreviewView = (SurfaceView) findViewById(R.id.preview_view); mPreviewView.getHolder().addCallback(this); + mPreviewView2 = (SurfaceView) findViewById(R.id.preview_view2); + mPreviewView2.getHolder().addCallback(this); + mStillView = (ImageView) findViewById(R.id.still_view); + mCameraIdSpinner = (Spinner) findViewById(R.id.camera_id_spinner); mInfoButton = (Button) findViewById(R.id.info_button); mInfoButton.setOnClickListener(mInfoButtonListener); mFlushButton = (Button) findViewById(R.id.flush_button); @@ -180,6 +190,25 @@ public class TestingCamera2 extends Activity implements SurfaceHolder.Callback { logException("Cannot create camera ops!",e); } + // Map available camera Ids to camera id spinner dropdown list of strings + try { + mAvailableCameraIds = mCameraOps.getDevices(); + if (mAvailableCameraIds == null || mAvailableCameraIds.length == 0) { + throw new ApiFailureException("no devices"); + } + } catch(ApiFailureException e) { + logException("CameraOps::getDevices failed!",e); + } + mCameraId = mAvailableCameraIds[0]; + ArrayAdapter<String> cameraIdDataAdapter = new ArrayAdapter<>(TestingCamera2.this, + android.R.layout.simple_spinner_item, mAvailableCameraIds); + mCameraIdSpinner.setAdapter(cameraIdDataAdapter); + + /* + * Change the camera ID and update preview when camera ID spinner's selected item changes + */ + mCameraIdSpinner.setOnItemSelectedListener(mCameraIdSelectedListener); + mOrientationEventListener = new OrientationEventListener(this) { @Override public void onOrientationChanged(int orientation) { @@ -237,8 +266,10 @@ public class TestingCamera2 extends Activity implements SurfaceHolder.Callback { private void setUpPreview() { try { - mCameraOps.minimalPreviewConfig(mPreviewView.getHolder()); + mCameraOps.minimalPreviewConfig(mCameraId, mPreviewView.getHolder(), + mPreviewView2.getHolder()); mCurrentPreviewHolder = mPreviewView.getHolder(); + mCurrentPreviewHolder2 = mPreviewView2.getHolder(); } catch (ApiFailureException e) { logException("Can't configure preview surface: ",e); } @@ -255,6 +286,7 @@ public class TestingCamera2 extends Activity implements SurfaceHolder.Callback { logException("Can't close device: ",e); } mCurrentPreviewHolder = null; + mCurrentPreviewHolder2 = null; } @Override @@ -289,6 +321,7 @@ public class TestingCamera2 extends Activity implements SurfaceHolder.Callback { private void updatePreviewOrientation() { LayoutParams params = mPreviewView.getLayoutParams(); + LayoutParams params2 = mPreviewView2.getLayoutParams(); int width = params.width; int height = params.height; @@ -323,8 +356,11 @@ public class TestingCamera2 extends Activity implements SurfaceHolder.Callback { } params.width = width; params.height = height; - mPreviewView.setLayoutParams(params); + + params2.width = width; + params2.height = height; + mPreviewView2.setLayoutParams(params2); } } @@ -338,9 +374,11 @@ public class TestingCamera2 extends Activity implements SurfaceHolder.Callback { Log.v(TAG, String.format("surfaceChanged: format %x, width %d, height %d", format, width, height)); } - if (mCurrentPreviewHolder != null && holder == mCurrentPreviewHolder) { + if ((mCurrentPreviewHolder != null && holder == mCurrentPreviewHolder) || + (mCurrentPreviewHolder2 != null && holder == mCurrentPreviewHolder2)) { try { - mCameraOps.minimalPreview(holder, mCameraControl); + mCameraOps.minimalPreview(mCurrentPreviewHolder, mCurrentPreviewHolder2, + mCameraControl); } catch (ApiFailureException e) { logException("Can't start minimal preview: ", e); } @@ -366,8 +404,9 @@ public class TestingCamera2 extends Activity implements SurfaceHolder.Callback { try { mCameraOps.minimalJpegCapture(mCaptureCallback, mCaptureResultListener, uiHandler, mCameraControl); - if (mCurrentPreviewHolder != null) { - mCameraOps.minimalPreview(mCurrentPreviewHolder, mCameraControl); + if (mCurrentPreviewHolder != null && mCurrentPreviewHolder2 != null) { + mCameraOps.minimalPreview(mCurrentPreviewHolder, + mCurrentPreviewHolder2, mCameraControl); } } catch (ApiFailureException e) { logException("Can't take a JPEG! ", e); @@ -702,6 +741,36 @@ public class TestingCamera2 extends Activity implements SurfaceHolder.Callback { } }; + private final OnItemSelectedListener mCameraIdSelectedListener = + new OnItemSelectedListener() { + @Override + public void onItemSelected(AdapterView<?> parent, View view, int position, + long id) { + String cameraId = mAvailableCameraIds[position]; + + if (cameraId != mCameraId) { + Log.i(TAG, "Switch to camera " + cameraId); + try { + mCameraOps.minimalPreviewConfig(cameraId, mPreviewView.getHolder(), + mPreviewView2.getHolder()); + + if (mCurrentPreviewHolder != null && mCurrentPreviewHolder2 != null) { + mCameraOps.minimalPreview(mCurrentPreviewHolder, + mCurrentPreviewHolder2, mCameraControl); + } + } catch (ApiFailureException e) { + logException("Can't configure preview surface: ", e); + } + mCameraId = cameraId; + } + } + + @Override + public void onNothingSelected(AdapterView<?> parent) { + // Do nothing + } + }; + private final CameraOps.Listener mCameraOpsListener = new CameraOps.Listener() { @Override public void onCameraOpened(String cameraId, CameraCharacteristics characteristics) { @@ -726,7 +795,8 @@ public class TestingCamera2 extends Activity implements SurfaceHolder.Callback { ArrayAdapter<String> dataAdapter = new ArrayAdapter<>(TestingCamera2.this, android.R.layout.simple_spinner_item, afModeList); - dataAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); + dataAdapter.setDropDownViewResource( + android.R.layout.simple_spinner_dropdown_item); mFocusModeSpinner.setAdapter(dataAdapter); /* |