/*
* Copyright (C) 2014 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.hardware.camera2.legacy;
import android.hardware.Camera;
import android.hardware.camera2.CameraAccessException;
import android.hardware.camera2.CaptureRequest;
import android.hardware.camera2.ICameraDeviceCallbacks;
import android.hardware.camera2.ICameraDeviceUser;
import android.hardware.camera2.utils.LongParcelable;
import android.hardware.camera2.impl.CameraMetadataNative;
import android.hardware.camera2.utils.CameraBinderDecorator;
import android.hardware.camera2.utils.CameraRuntimeException;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;
import android.util.SparseArray;
import android.view.Surface;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
/**
* Compatibility implementation of the Camera2 API binder interface.
*
*
* This is intended to be called from the same process as client
* {@link android.hardware.camera2.CameraDevice}, and wraps a
* {@link android.hardware.camera2.legacy.LegacyCameraDevice} that emulates Camera2 service using
* the Camera1 API.
*
*
*
* Keep up to date with ICameraDeviceUser.aidl.
*
*/
public class CameraDeviceUserShim implements ICameraDeviceUser {
private static final String TAG = "CameraDeviceUserShim";
private static final boolean DEBUG = Log.isLoggable(LegacyCameraDevice.DEBUG_PROP, Log.DEBUG);
private final LegacyCameraDevice mLegacyDevice;
private final Object mConfigureLock = new Object();
private int mSurfaceIdCounter;
private boolean mConfiguring;
private final SparseArray mSurfaces;
protected CameraDeviceUserShim(int cameraId, LegacyCameraDevice legacyCamera) {
mLegacyDevice = legacyCamera;
mConfiguring = false;
mSurfaces = new SparseArray();
mSurfaceIdCounter = 0;
}
public static CameraDeviceUserShim connectBinderShim(ICameraDeviceCallbacks callbacks,
int cameraId) {
if (DEBUG) {
Log.d(TAG, "Opening shim Camera device");
}
// TODO: Move open/init into LegacyCameraDevice thread when API is switched to async.
Camera legacyCamera = Camera.openUninitialized();
int initErrors = legacyCamera.cameraInitUnspecified(cameraId);
// Check errors old HAL initialization
CameraBinderDecorator.throwOnError(initErrors);
LegacyCameraDevice device = new LegacyCameraDevice(cameraId, legacyCamera, callbacks);
return new CameraDeviceUserShim(cameraId, device);
}
@Override
public void disconnect() {
if (DEBUG) {
Log.d(TAG, "disconnect called.");
}
mLegacyDevice.close();
}
@Override
public int submitRequest(CaptureRequest request, boolean streaming,
/*out*/LongParcelable lastFrameNumber) {
if (DEBUG) {
Log.d(TAG, "submitRequest called.");
}
synchronized(mConfigureLock) {
if (mConfiguring) {
Log.e(TAG, "Cannot submit request, configuration change in progress.");
return CameraBinderDecorator.INVALID_OPERATION;
}
}
return mLegacyDevice.submitRequest(request, streaming, lastFrameNumber);
}
@Override
public int submitRequestList(List request, boolean streaming,
/*out*/LongParcelable lastFrameNumber) {
if (DEBUG) {
Log.d(TAG, "submitRequestList called.");
}
synchronized(mConfigureLock) {
if (mConfiguring) {
Log.e(TAG, "Cannot submit request, configuration change in progress.");
return CameraBinderDecorator.INVALID_OPERATION;
}
}
return mLegacyDevice.submitRequestList(request, streaming, lastFrameNumber);
}
@Override
public int cancelRequest(int requestId, /*out*/LongParcelable lastFrameNumber) {
if (DEBUG) {
Log.d(TAG, "cancelRequest called.");
}
synchronized(mConfigureLock) {
if (mConfiguring) {
Log.e(TAG, "Cannot cancel request, configuration change in progress.");
return CameraBinderDecorator.INVALID_OPERATION;
}
}
long lastFrame = mLegacyDevice.cancelRequest(requestId);
lastFrameNumber.setNumber(lastFrame);
return CameraBinderDecorator.NO_ERROR;
}
@Override
public int beginConfigure() {
if (DEBUG) {
Log.d(TAG, "beginConfigure called.");
}
synchronized(mConfigureLock) {
if (mConfiguring) {
Log.e(TAG, "Cannot begin configure, configuration change already in progress.");
return CameraBinderDecorator.INVALID_OPERATION;
}
mConfiguring = true;
}
return CameraBinderDecorator.NO_ERROR;
}
@Override
public int endConfigure() {
if (DEBUG) {
Log.d(TAG, "endConfigure called.");
}
ArrayList surfaces = null;
synchronized(mConfigureLock) {
if (!mConfiguring) {
Log.e(TAG, "Cannot end configure, no configuration change in progress.");
return CameraBinderDecorator.INVALID_OPERATION;
}
int numSurfaces = mSurfaces.size();
if (numSurfaces > 0) {
for (int i = 0; i < numSurfaces; ++i) {
surfaces.add(mSurfaces.valueAt(i));
}
}
mConfiguring = false;
}
return mLegacyDevice.configureOutputs(surfaces);
}
@Override
public int deleteStream(int streamId) {
if (DEBUG) {
Log.d(TAG, "deleteStream called.");
}
synchronized(mConfigureLock) {
if (!mConfiguring) {
Log.e(TAG, "Cannot delete stream, beginConfigure hasn't been called yet.");
return CameraBinderDecorator.INVALID_OPERATION;
}
int index = mSurfaces.indexOfKey(streamId);
if (index < 0) {
Log.e(TAG, "Cannot delete stream, stream id " + streamId + " doesn't exist.");
return CameraBinderDecorator.BAD_VALUE;
}
mSurfaces.removeAt(index);
}
return CameraBinderDecorator.NO_ERROR;
}
@Override
public int createStream(int width, int height, int format, Surface surface) {
if (DEBUG) {
Log.d(TAG, "createStream called.");
}
synchronized(mConfigureLock) {
if (!mConfiguring) {
Log.e(TAG, "Cannot create stream, beginConfigure hasn't been called yet.");
return CameraBinderDecorator.INVALID_OPERATION;
}
int id = ++mSurfaceIdCounter;
mSurfaces.put(id, surface);
return id;
}
}
@Override
public int createDefaultRequest(int templateId, /*out*/CameraMetadataNative request) {
if (DEBUG) {
Log.d(TAG, "createDefaultRequest called.");
}
// TODO: implement createDefaultRequest.
Log.e(TAG, "createDefaultRequest unimplemented.");
return CameraBinderDecorator.NO_ERROR;
}
@Override
public int getCameraInfo(/*out*/CameraMetadataNative info) {
if (DEBUG) {
Log.d(TAG, "getCameraInfo called.");
}
// TODO: implement getCameraInfo.
Log.e(TAG, "getCameraInfo unimplemented.");
return CameraBinderDecorator.NO_ERROR;
}
@Override
public int waitUntilIdle() throws RemoteException {
if (DEBUG) {
Log.d(TAG, "waitUntilIdle called.");
}
synchronized(mConfigureLock) {
if (mConfiguring) {
Log.e(TAG, "Cannot wait until idle, configuration change in progress.");
return CameraBinderDecorator.INVALID_OPERATION;
}
}
mLegacyDevice.waitUntilIdle();
return CameraBinderDecorator.NO_ERROR;
}
@Override
public int flush(/*out*/LongParcelable lastFrameNumber) {
if (DEBUG) {
Log.d(TAG, "flush called.");
}
synchronized(mConfigureLock) {
if (mConfiguring) {
Log.e(TAG, "Cannot flush, configuration change in progress.");
return CameraBinderDecorator.INVALID_OPERATION;
}
}
// TODO: implement flush.
return CameraBinderDecorator.NO_ERROR;
}
@Override
public IBinder asBinder() {
// This is solely intended to be used for in-process binding.
return null;
}
}