Merge "Camera2: Switch to auto-gen C++ binder interfaces" into nyc-dev am: 74989b4d3f

am: 72071de87c

* commit '72071de87c62717cc85937b319df8df10cf4b7e9':
  Camera2: Switch to auto-gen C++ binder interfaces
This commit is contained in:
Eino-Ville Talvala
2016-03-02 23:08:24 +00:00
committed by android-build-merger
49 changed files with 1112 additions and 2081 deletions

View File

@@ -150,14 +150,14 @@ LOCAL_SRC_FILES += \
core/java/android/content/pm/IPackageStatsObserver.aidl \
core/java/android/content/pm/IOnPermissionsChangeListener.aidl \
core/java/android/database/IContentObserver.aidl \
core/java/android/hardware/ICameraService.aidl \
core/java/android/hardware/ICameraServiceListener.aidl \
core/java/android/hardware/ICameraServiceProxy.aidl \
core/java/android/hardware/ICamera.aidl \
core/java/android/hardware/ICameraClient.aidl \
../av/camera/aidl/android/hardware/ICameraService.aidl \
../av/camera/aidl/android/hardware/ICameraServiceListener.aidl \
../av/camera/aidl/android/hardware/ICameraServiceProxy.aidl \
../av/camera/aidl/android/hardware/ICamera.aidl \
../av/camera/aidl/android/hardware/ICameraClient.aidl \
../av/camera/aidl/android/hardware/camera2/ICameraDeviceUser.aidl \
../av/camera/aidl/android/hardware/camera2/ICameraDeviceCallbacks.aidl \
core/java/android/hardware/IConsumerIrService.aidl \
core/java/android/hardware/camera2/ICameraDeviceUser.aidl \
core/java/android/hardware/camera2/ICameraDeviceCallbacks.aidl \
core/java/android/hardware/ISerialManager.aidl \
core/java/android/hardware/display/IDisplayManager.aidl \
core/java/android/hardware/display/IDisplayManagerCallback.aidl \
@@ -455,6 +455,10 @@ LOCAL_AIDL_INCLUDES += \
$(FRAMEWORKS_BASE_JAVA_SRC_DIRS) \
frameworks/native/aidl/binder
LOCAL_AIDL_INCLUDES += \
frameworks/av/camera/aidl \
frameworks/native/aidl/gui
LOCAL_INTERMEDIATE_SOURCES := \
$(framework_res_source_path)/android/R.java \
$(framework_res_source_path)/android/Manifest.java \
@@ -575,7 +579,7 @@ aidl_files := \
frameworks/base/core/java/android/view/Display.aidl \
frameworks/base/core/java/android/view/InputDevice.aidl \
frameworks/base/core/java/android/view/InputEvent.aidl \
frameworks/base/core/java/android/view/Surface.aidl \
frameworks/native/aidl/gui/android/view/Surface.aidl \
frameworks/base/core/java/android/view/WindowContentFrameStats.aidl \
frameworks/base/core/java/android/view/inputmethod/InputMethodSubtype.aidl \
frameworks/base/core/java/android/view/inputmethod/CursorAnchorInfo.aidl \

View File

@@ -1,20 +0,0 @@
/*
* Copyright (C) 2013 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;
/** @hide */
parcelable CameraInfo;

View File

@@ -1,26 +0,0 @@
/*
* Copyright (C) 2013 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;
/** @hide */
interface ICamera
{
/**
* Keep up-to-date with frameworks/av/include/camera/ICamera.h
*/
void disconnect();
}

View File

@@ -1,26 +0,0 @@
/*
* Copyright (C) 2013 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;
/** @hide */
interface ICameraClient
{
/**
* Keep up-to-date with frameworks/av/include/camera/ICameraClient.h
*/
// TODO: consider implementing this.
}

View File

@@ -1,89 +0,0 @@
/*
* Copyright (C) 2013 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;
import android.hardware.ICamera;
import android.hardware.ICameraClient;
import android.hardware.camera2.ICameraDeviceUser;
import android.hardware.camera2.ICameraDeviceCallbacks;
import android.hardware.camera2.impl.CameraMetadataNative;
import android.hardware.camera2.utils.BinderHolder;
import android.hardware.ICameraServiceListener;
import android.hardware.CameraInfo;
/**
* Binder interface for the native camera service running in mediaserver.
*
* @hide
*/
interface ICameraService
{
/**
* Keep up-to-date with frameworks/av/include/camera/ICameraService.h
*/
int getNumberOfCameras(int type);
// rest of 'int' return values in this file are actually status_t
int getCameraInfo(int cameraId, out CameraInfo info);
int connect(ICameraClient client, int cameraId,
String opPackageName,
int clientUid,
// Container for an ICamera object
out BinderHolder device);
int connectDevice(ICameraDeviceCallbacks callbacks, int cameraId,
String opPackageName,
int clientUid,
// Container for an ICameraDeviceUser object
out BinderHolder device);
int addListener(ICameraServiceListener listener);
int removeListener(ICameraServiceListener listener);
int getCameraCharacteristics(int cameraId, out CameraMetadataNative info);
/**
* The java stubs for this method are not intended to be used. Please use
* the native stub in frameworks/av/include/camera/ICameraService.h instead.
* The BinderHolder output is being used as a placeholder, and will not be
* well-formatted in the generated java method.
*/
int getCameraVendorTagDescriptor(out BinderHolder desc);
// Writes the camera1 parameters into a single-element array.
int getLegacyParameters(int cameraId, out String[] parameters);
// Determines if a particular API version is supported; see ICameraService.h for version defines
int supportsCameraApi(int cameraId, int apiVersion);
int connectLegacy(ICameraClient client, int cameraId,
int halVersion,
String opPackageName,
int clientUid,
// Container for an ICamera object
out BinderHolder device);
int setTorchMode(String CameraId, boolean enabled, IBinder clientBinder);
/**
* Notify the camera service of a system event. Should only be called from system_server.
*
* Callers require the android.permission.CAMERA_SEND_SYSTEM_EVENTS permission.
*/
oneway void notifySystemEvent(int eventId, in int[] args);
}

View File

@@ -1,28 +0,0 @@
/*
* Copyright (C) 2013 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;
/** @hide */
interface ICameraServiceListener
{
/**
* Keep up-to-date with frameworks/av/include/camera/ICameraServiceListener.h
*/
void onStatusChanged(int status, int cameraId);
void onTorchStatusChanged(int status, String cameraId);
}

View File

@@ -1,37 +0,0 @@
/*
* Copyright (C) 2015 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;
/**
* Binder interface for the camera service proxy running in system_server.
*
* Keep in sync with frameworks/av/include/camera/ICameraServiceProxy.h
*
* @hide
*/
interface ICameraServiceProxy
{
/**
* Ping the service proxy to update the valid users for the camera service.
*/
oneway void pingForUserUpdate();
/**
* Update the status of a camera device
*/
oneway void notifyCameraState(String cameraId, int newCameraState);
}

View File

@@ -114,12 +114,12 @@ public class CameraAccessException extends AndroidException {
}
public CameraAccessException(@AccessError int problem, String message) {
super(message);
super(getCombinedMessage(problem, message));
mReason = problem;
}
public CameraAccessException(@AccessError int problem, String message, Throwable cause) {
super(message, cause);
super(getCombinedMessage(problem, message), cause);
mReason = problem;
}
@@ -151,4 +151,37 @@ public class CameraAccessException extends AndroidException {
}
return null;
}
private static String getCombinedMessage(@AccessError int problem, String message) {
String problemString = getProblemString(problem);
return String.format("%s (%d): %s", problemString, problem, message);
}
private static String getProblemString(int problem) {
String problemString;
switch (problem) {
case CAMERA_IN_USE:
problemString = "CAMERA_IN_USE";
break;
case MAX_CAMERAS_IN_USE:
problemString = "MAX_CAMERAS_IN_USE";
break;
case CAMERA_DISCONNECTED:
problemString = "CAMERA_DISCONNECTED";
break;
case CAMERA_DISABLED:
problemString = "CAMERA_DISABLED";
break;
case CAMERA_ERROR:
problemString = "CAMERA_ERROR";
break;
case CAMERA_DEPRECATED_HAL:
problemString = "CAMERA_DEPRECATED_HAL";
break;
default:
problemString = "<UNKNOWN ERROR>";
}
return problemString;
}
}

View File

@@ -26,15 +26,14 @@ import android.hardware.CameraInfo;
import android.hardware.camera2.impl.CameraMetadataNative;
import android.hardware.camera2.legacy.CameraDeviceUserShim;
import android.hardware.camera2.legacy.LegacyMetadataMapper;
import android.hardware.camera2.utils.CameraServiceBinderDecorator;
import android.hardware.camera2.utils.CameraRuntimeException;
import android.hardware.camera2.utils.BinderHolder;
import android.os.IBinder;
import android.os.Binder;
import android.os.DeadObjectException;
import android.os.Handler;
import android.os.Looper;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.ServiceSpecificException;
import android.util.Log;
import android.util.ArrayMap;
@@ -240,25 +239,19 @@ public final class CameraManager {
if (!supportsCamera2ApiLocked(cameraId)) {
// Legacy backwards compatibility path; build static info from the camera
// parameters
String[] outParameters = new String[1];
String parameters = cameraService.getLegacyParameters(id);
cameraService.getLegacyParameters(id, /*out*/outParameters);
String parameters = outParameters[0];
CameraInfo info = new CameraInfo();
cameraService.getCameraInfo(id, /*out*/info);
CameraInfo info = cameraService.getCameraInfo(id);
characteristics = LegacyMetadataMapper.createCharacteristics(parameters, info);
} else {
// Normal path: Get the camera characteristics directly from the camera service
CameraMetadataNative info = new CameraMetadataNative();
cameraService.getCameraCharacteristics(id, info);
CameraMetadataNative info = cameraService.getCameraCharacteristics(id);
characteristics = new CameraCharacteristics(info);
}
} catch (CameraRuntimeException e) {
throw e.asChecked();
} catch (ServiceSpecificException e) {
throwAsPublicException(e);
} catch (RemoteException e) {
// Camera service died - act as if the camera was disconnected
throw new CameraAccessException(CameraAccessException.CAMERA_DISCONNECTED,
@@ -292,85 +285,83 @@ public final class CameraManager {
throws CameraAccessException {
CameraCharacteristics characteristics = getCameraCharacteristics(cameraId);
CameraDevice device = null;
try {
synchronized (mLock) {
synchronized (mLock) {
ICameraDeviceUser cameraUser = null;
ICameraDeviceUser cameraUser = null;
android.hardware.camera2.impl.CameraDeviceImpl deviceImpl =
new android.hardware.camera2.impl.CameraDeviceImpl(
cameraId,
callback,
handler,
characteristics);
android.hardware.camera2.impl.CameraDeviceImpl deviceImpl =
new android.hardware.camera2.impl.CameraDeviceImpl(
cameraId,
callback,
handler,
characteristics);
BinderHolder holder = new BinderHolder();
ICameraDeviceCallbacks callbacks = deviceImpl.getCallbacks();
ICameraDeviceCallbacks callbacks = deviceImpl.getCallbacks();
int id = Integer.parseInt(cameraId);
try {
if (supportsCamera2ApiLocked(cameraId)) {
// Use cameraservice's cameradeviceclient implementation for HAL3.2+ devices
ICameraService cameraService = CameraManagerGlobal.get().getCameraService();
if (cameraService == null) {
throw new CameraRuntimeException(
CameraAccessException.CAMERA_DISCONNECTED,
"Camera service is currently unavailable");
}
cameraService.connectDevice(callbacks, id,
mContext.getOpPackageName(), USE_CALLING_UID, holder);
cameraUser = ICameraDeviceUser.Stub.asInterface(holder.getBinder());
} else {
// Use legacy camera implementation for HAL1 devices
Log.i(TAG, "Using legacy camera HAL.");
cameraUser = CameraDeviceUserShim.connectBinderShim(callbacks, id);
}
} catch (CameraRuntimeException e) {
if (e.getReason() == CameraAccessException.CAMERA_DEPRECATED_HAL) {
throw new AssertionError("Should've gone down the shim path");
} else if (e.getReason() == CameraAccessException.CAMERA_IN_USE ||
e.getReason() == CameraAccessException.MAX_CAMERAS_IN_USE ||
e.getReason() == CameraAccessException.CAMERA_DISABLED ||
e.getReason() == CameraAccessException.CAMERA_DISCONNECTED ||
e.getReason() == CameraAccessException.CAMERA_ERROR) {
// Received one of the known connection errors
// The remote camera device cannot be connected to, so
// set the local camera to the startup error state
deviceImpl.setRemoteFailure(e);
if (e.getReason() == CameraAccessException.CAMERA_DISABLED ||
e.getReason() == CameraAccessException.CAMERA_DISCONNECTED ||
e.getReason() == CameraAccessException.CAMERA_IN_USE) {
// Per API docs, these failures call onError and throw
throw e.asChecked();
}
} else {
// Unexpected failure - rethrow
throw e;
}
} catch (RemoteException e) {
// Camera service died - act as if it's a CAMERA_DISCONNECTED case
CameraRuntimeException ce = new CameraRuntimeException(
CameraAccessException.CAMERA_DISCONNECTED,
"Camera service is currently unavailable", e);
deviceImpl.setRemoteFailure(ce);
throw ce.asChecked();
}
// TODO: factor out callback to be non-nested, then move setter to constructor
// For now, calling setRemoteDevice will fire initial
// onOpened/onUnconfigured callbacks.
deviceImpl.setRemoteDevice(cameraUser);
device = deviceImpl;
int id;
try {
id = Integer.parseInt(cameraId);
} catch (NumberFormatException e) {
throw new IllegalArgumentException("Expected cameraId to be numeric, but it was: "
+ cameraId);
}
} catch (NumberFormatException e) {
throw new IllegalArgumentException("Expected cameraId to be numeric, but it was: "
+ cameraId);
} catch (CameraRuntimeException e) {
throw e.asChecked();
try {
if (supportsCamera2ApiLocked(cameraId)) {
// Use cameraservice's cameradeviceclient implementation for HAL3.2+ devices
ICameraService cameraService = CameraManagerGlobal.get().getCameraService();
if (cameraService == null) {
throw new ServiceSpecificException(
ICameraService.ERROR_DISCONNECTED,
"Camera service is currently unavailable");
}
cameraUser = cameraService.connectDevice(callbacks, id,
mContext.getOpPackageName(), USE_CALLING_UID);
} else {
// Use legacy camera implementation for HAL1 devices
Log.i(TAG, "Using legacy camera HAL.");
cameraUser = CameraDeviceUserShim.connectBinderShim(callbacks, id);
}
} catch (ServiceSpecificException e) {
if (e.errorCode == ICameraService.ERROR_DEPRECATED_HAL) {
throw new AssertionError("Should've gone down the shim path");
} else if (e.errorCode == ICameraService.ERROR_CAMERA_IN_USE ||
e.errorCode == ICameraService.ERROR_MAX_CAMERAS_IN_USE ||
e.errorCode == ICameraService.ERROR_DISABLED ||
e.errorCode == ICameraService.ERROR_DISCONNECTED ||
e.errorCode == ICameraService.ERROR_INVALID_OPERATION) {
// Received one of the known connection errors
// The remote camera device cannot be connected to, so
// set the local camera to the startup error state
deviceImpl.setRemoteFailure(e);
if (e.errorCode == ICameraService.ERROR_DISABLED ||
e.errorCode == ICameraService.ERROR_DISCONNECTED ||
e.errorCode == ICameraService.ERROR_CAMERA_IN_USE) {
// Per API docs, these failures call onError and throw
throwAsPublicException(e);
}
} else {
// Unexpected failure - rethrow
throwAsPublicException(e);
}
} catch (RemoteException e) {
// Camera service died - act as if it's a CAMERA_DISCONNECTED case
ServiceSpecificException sse = new ServiceSpecificException(
ICameraService.ERROR_DISCONNECTED,
"Camera service is currently unavailable");
deviceImpl.setRemoteFailure(sse);
throwAsPublicException(sse);
}
// TODO: factor out callback to be non-nested, then move setter to constructor
// For now, calling setRemoteDevice will fire initial
// onOpened/onUnconfigured callbacks.
deviceImpl.setRemoteDevice(cameraUser);
device = deviceImpl;
}
return device;
}
@@ -601,6 +592,56 @@ public final class CameraManager {
}
}
/**
* Convert ServiceSpecificExceptions and Binder RemoteExceptions from camera binder interfaces
* into the correct public exceptions.
*
* @hide
*/
public static void throwAsPublicException(Throwable t) throws CameraAccessException {
if (t instanceof ServiceSpecificException) {
ServiceSpecificException e = (ServiceSpecificException) t;
int reason = CameraAccessException.CAMERA_ERROR;
switch(e.errorCode) {
case ICameraService.ERROR_DISCONNECTED:
reason = CameraAccessException.CAMERA_DISCONNECTED;
break;
case ICameraService.ERROR_DISABLED:
reason = CameraAccessException.CAMERA_DISABLED;
break;
case ICameraService.ERROR_CAMERA_IN_USE:
reason = CameraAccessException.CAMERA_IN_USE;
break;
case ICameraService.ERROR_MAX_CAMERAS_IN_USE:
reason = CameraAccessException.MAX_CAMERAS_IN_USE;
break;
case ICameraService.ERROR_DEPRECATED_HAL:
reason = CameraAccessException.CAMERA_DEPRECATED_HAL;
break;
case ICameraService.ERROR_ILLEGAL_ARGUMENT:
case ICameraService.ERROR_ALREADY_EXISTS:
throw new IllegalArgumentException(e.getMessage(), e);
case ICameraService.ERROR_PERMISSION_DENIED:
throw new SecurityException(e.getMessage(), e);
case ICameraService.ERROR_TIMED_OUT:
case ICameraService.ERROR_INVALID_OPERATION:
default:
reason = CameraAccessException.CAMERA_ERROR;
}
throw new CameraAccessException(reason, e.getMessage(), e);
} else if (t instanceof DeadObjectException) {
throw new CameraAccessException(CameraAccessException.CAMERA_DISCONNECTED,
"Camera service has died unexpectedly",
t);
} else if (t instanceof RemoteException) {
throw new UnsupportedOperationException("An unknown RemoteException was thrown" +
" which should never happen.", t);
} else if (t instanceof RuntimeException) {
RuntimeException e = (RuntimeException) t;
throw e;
}
}
/**
* Return or create the list of currently connected camera devices.
*
@@ -619,34 +660,32 @@ public final class CameraManager {
try {
numCameras = cameraService.getNumberOfCameras(CAMERA_TYPE_ALL);
} catch(CameraRuntimeException e) {
throw e.asChecked();
} catch(ServiceSpecificException e) {
throwAsPublicException(e);
} catch (RemoteException e) {
// camera service just died - if no camera service, then no devices
return deviceIdList;
}
CameraMetadataNative info = new CameraMetadataNative();
for (int i = 0; i < numCameras; ++i) {
// Non-removable cameras use integers starting at 0 for their
// identifiers
boolean isDeviceSupported = false;
try {
cameraService.getCameraCharacteristics(i, info);
CameraMetadataNative info = cameraService.getCameraCharacteristics(i);
if (!info.isEmpty()) {
isDeviceSupported = true;
} else {
throw new AssertionError("Expected to get non-empty characteristics");
}
} catch(IllegalArgumentException e) {
// Got a BAD_VALUE from service, meaning that this
// device is not supported.
} catch(CameraRuntimeException e) {
} catch(ServiceSpecificException e) {
// DISCONNECTED means that the HAL reported an low-level error getting the
// device info; skip listing the device. Other errors,
// device info; ILLEGAL_ARGUMENT means that this devices is not supported.
// Skip listing the device. Other errors,
// propagate exception onward
if (e.getReason() != CameraAccessException.CAMERA_DISCONNECTED) {
throw e.asChecked();
if (e.errorCode != ICameraService.ERROR_DISCONNECTED ||
e.errorCode != ICameraService.ERROR_ILLEGAL_ARGUMENT) {
throwAsPublicException(e);
}
} catch(RemoteException e) {
// Camera service died - no devices to list
@@ -699,17 +738,7 @@ public final class CameraManager {
// If no camera service, no support
if (cameraService == null) return false;
int res = cameraService.supportsCameraApi(id, apiVersion);
if (res != CameraServiceBinderDecorator.NO_ERROR) {
throw new AssertionError("Unexpected value " + res);
}
return true;
} catch (CameraRuntimeException e) {
if (e.getReason() != CameraAccessException.CAMERA_DEPRECATED_HAL) {
throw e;
}
// API level is not supported
return cameraService.supportsCameraApi(id, apiVersion);
} catch (RemoteException e) {
// Camera service is now down, no support for any API level
}
@@ -737,21 +766,6 @@ public final class CameraManager {
*/
private static final String CAMERA_SERVICE_BINDER_NAME = "media.camera";
// Keep up-to-date with ICameraServiceListener.h
// Device physically unplugged
public static final int STATUS_NOT_PRESENT = 0;
// Device physically has been plugged in
// and the camera can be used exclusively
public static final int STATUS_PRESENT = 1;
// Device physically has been plugged in
// but it will not be connect-able until enumeration is complete
public static final int STATUS_ENUMERATING = 2;
// Camera is in use by another app and cannot be used exclusively
public static final int STATUS_NOT_AVAILABLE = 0x80000000;
// End enums shared with ICameraServiceListener.h
// Camera ID -> Status map
private final ArrayMap<String, Integer> mDeviceStatus = new ArrayMap<String, Integer>();
@@ -759,17 +773,6 @@ public final class CameraManager {
private final ArrayMap<AvailabilityCallback, Handler> mCallbackMap =
new ArrayMap<AvailabilityCallback, Handler>();
// Keep up-to-date with ICameraServiceListener.h
// torch mode has become not available to set via setTorchMode().
public static final int TORCH_STATUS_NOT_AVAILABLE = 0;
// torch mode is off and available to be turned on via setTorchMode().
public static final int TORCH_STATUS_AVAILABLE_OFF = 1;
// torch mode is on and available to be turned off via setTorchMode().
public static final int TORCH_STATUS_AVAILABLE_ON = 2;
// End enums shared with ICameraServiceListener.h
// torch client binder to set the torch mode with.
private Binder mTorchClientBinder = new Binder();
@@ -839,29 +842,20 @@ public final class CameraManager {
return;
}
ICameraService cameraServiceRaw = ICameraService.Stub.asInterface(cameraServiceBinder);
/**
* Wrap the camera service in a decorator which automatically translates return codes
* into exceptions.
*/
ICameraService cameraService =
CameraServiceBinderDecorator.newInstance(cameraServiceRaw);
ICameraService cameraService = ICameraService.Stub.asInterface(cameraServiceBinder);
try {
CameraServiceBinderDecorator.throwOnError(
CameraMetadataNative.nativeSetupGlobalVendorTagDescriptor());
} catch (CameraRuntimeException e) {
handleRecoverableSetupErrors(e, "Failed to set up vendor tags");
CameraMetadataNative.setupGlobalVendorTagDescriptor();
} catch (ServiceSpecificException e) {
handleRecoverableSetupErrors(e);
}
try {
cameraService.addListener(this);
mCameraService = cameraService;
} catch(CameraRuntimeException e) {
} catch(ServiceSpecificException e) {
// Unexpected failure
throw new IllegalStateException("Failed to register a camera service listener",
e.asChecked());
throw new IllegalStateException("Failed to register a camera service listener", e);
} catch (RemoteException e) {
// Camera service is now down, leave mCameraService as null
}
@@ -881,16 +875,9 @@ public final class CameraManager {
}
try {
int status = cameraService.setTorchMode(cameraId, enabled, mTorchClientBinder);
} catch(CameraRuntimeException e) {
int problem = e.getReason();
switch (problem) {
case CameraAccessException.CAMERA_ERROR:
throw new IllegalArgumentException(
"the camera device doesn't have a flash unit.");
default:
throw e.asChecked();
}
cameraService.setTorchMode(cameraId, enabled, mTorchClientBinder);
} catch(ServiceSpecificException e) {
throwAsPublicException(e);
} catch (RemoteException e) {
throw new CameraAccessException(CameraAccessException.CAMERA_DISCONNECTED,
"Camera service is currently unavailable");
@@ -898,21 +885,19 @@ public final class CameraManager {
}
}
private void handleRecoverableSetupErrors(CameraRuntimeException e, String msg) {
int problem = e.getReason();
switch (problem) {
case CameraAccessException.CAMERA_DISCONNECTED:
String errorMsg = CameraAccessException.getDefaultMessage(problem);
Log.w(TAG, msg + ": " + errorMsg);
private void handleRecoverableSetupErrors(ServiceSpecificException e) {
switch (e.errorCode) {
case ICameraService.ERROR_DISCONNECTED:
Log.w(TAG, e.getMessage());
break;
default:
throw new IllegalStateException(msg, e.asChecked());
throw new IllegalStateException(e);
}
}
private boolean isAvailable(int status) {
switch (status) {
case STATUS_PRESENT:
case ICameraServiceListener.STATUS_PRESENT:
return true;
default:
return false;
@@ -921,10 +906,10 @@ public final class CameraManager {
private boolean validStatus(int status) {
switch (status) {
case STATUS_NOT_PRESENT:
case STATUS_PRESENT:
case STATUS_ENUMERATING:
case STATUS_NOT_AVAILABLE:
case ICameraServiceListener.STATUS_NOT_PRESENT:
case ICameraServiceListener.STATUS_PRESENT:
case ICameraServiceListener.STATUS_ENUMERATING:
case ICameraServiceListener.STATUS_NOT_AVAILABLE:
return true;
default:
return false;
@@ -933,9 +918,9 @@ public final class CameraManager {
private boolean validTorchStatus(int status) {
switch (status) {
case TORCH_STATUS_NOT_AVAILABLE:
case TORCH_STATUS_AVAILABLE_ON:
case TORCH_STATUS_AVAILABLE_OFF:
case ICameraServiceListener.TORCH_STATUS_NOT_AVAILABLE:
case ICameraServiceListener.TORCH_STATUS_AVAILABLE_ON:
case ICameraServiceListener.TORCH_STATUS_AVAILABLE_OFF:
return true;
default:
return false;
@@ -966,14 +951,14 @@ public final class CameraManager {
private void postSingleTorchUpdate(final TorchCallback callback, final Handler handler,
final String id, final int status) {
switch(status) {
case TORCH_STATUS_AVAILABLE_ON:
case TORCH_STATUS_AVAILABLE_OFF:
case ICameraServiceListener.TORCH_STATUS_AVAILABLE_ON:
case ICameraServiceListener.TORCH_STATUS_AVAILABLE_OFF:
handler.post(
new Runnable() {
@Override
public void run() {
callback.onTorchModeChanged(id, status ==
TORCH_STATUS_AVAILABLE_ON);
ICameraServiceListener.TORCH_STATUS_AVAILABLE_ON);
}
});
break;
@@ -1220,11 +1205,12 @@ public final class CameraManager {
// and torch statuses will be updated.
for (int i = 0; i < mDeviceStatus.size(); i++) {
String cameraId = mDeviceStatus.keyAt(i);
onStatusChangedLocked(STATUS_NOT_PRESENT, cameraId);
onStatusChangedLocked(ICameraServiceListener.STATUS_NOT_PRESENT, cameraId);
}
for (int i = 0; i < mTorchStatus.size(); i++) {
String cameraId = mTorchStatus.keyAt(i);
onTorchStatusChangedLocked(TORCH_STATUS_NOT_AVAILABLE, cameraId);
onTorchStatusChangedLocked(ICameraServiceListener.TORCH_STATUS_NOT_AVAILABLE,
cameraId);
}
scheduleCameraServiceReconnectionLocked();

View File

@@ -1,20 +0,0 @@
/*
* Copyright (C) 2013 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;
/** @hide */
parcelable CaptureRequest;

View File

@@ -1,35 +0,0 @@
/*
* Copyright (C) 2013 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;
import android.hardware.camera2.impl.CameraMetadataNative;
import android.hardware.camera2.impl.CaptureResultExtras;
/** @hide */
interface ICameraDeviceCallbacks
{
/**
* Keep up-to-date with frameworks/av/include/camera/camera2/ICameraDeviceCallbacks.h
*/
oneway void onDeviceError(int errorCode, in CaptureResultExtras resultExtras);
oneway void onDeviceIdle();
oneway void onCaptureStarted(in CaptureResultExtras resultExtras, long timestamp);
oneway void onResultReceived(in CameraMetadataNative result,
in CaptureResultExtras resultExtras);
oneway void onPrepared(int streamId);
}

View File

@@ -1,107 +0,0 @@
/*
* Copyright (C) 2013 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;
import android.hardware.camera2.CaptureRequest;
import android.hardware.camera2.impl.CameraMetadataNative;
import android.hardware.camera2.params.OutputConfiguration;
import android.hardware.camera2.utils.LongParcelable;
import android.view.Surface;
/** @hide */
interface ICameraDeviceUser
{
/**
* Keep up-to-date with frameworks/av/include/camera/camera2/ICameraDeviceUser.h and
* frameworks/base/core/java/android/hardware/camera2/legacy/CameraDeviceUserShim.java
*/
void disconnect();
// ints here are status_t
// non-negative value is the requestId. negative value is status_t
int submitRequest(in CaptureRequest request, boolean streaming,
out LongParcelable lastFrameNumber);
int submitRequestList(in List<CaptureRequest> requestList, boolean streaming,
out LongParcelable lastFrameNumber);
int cancelRequest(int requestId, out LongParcelable lastFrameNumber);
/**
* Begin the device configuration.
*
* <p>
* beginConfigure must be called before any call to deleteStream, createStream,
* or endConfigure. It is not valid to call this when the device is not idle.
* <p>
*/
int beginConfigure();
/**
* End the device configuration.
*
* <p>
* endConfigure must be called after stream configuration is complete (i.e. after
* a call to beginConfigure and subsequent createStream/deleteStream calls). This
* must be called before any requests can be submitted.
* <p>
*/
int endConfigure(boolean isConstrainedHighSpeed);
int deleteStream(int streamId);
// non-negative value is the stream ID. negative value is status_t
int createStream(in OutputConfiguration outputConfiguration);
/**
* Create an input stream
*
* <p>Create an input stream of width, height, and format</p>
*
* @param width Width of the input buffers
* @param height Height of the input buffers
* @param format Format of the input buffers. One of HAL_PIXEL_FORMAT_*.
*
* @return stream ID if it's a non-negative value. status_t if it's a negative value.
*/
int createInputStream(int width, int height, int format);
/**
* Get the surface of the input stream.
*
* <p>It's valid to call this method only after a stream configuration is completed
* successfully and the stream configuration includes a input stream.</p>
*
* @param surface An output argument for the surface of the input stream buffer queue.
*/
int getInputSurface(out Surface surface);
int createDefaultRequest(int templateId, out CameraMetadataNative request);
int getCameraInfo(out CameraMetadataNative info);
int waitUntilIdle();
int flush(out LongParcelable lastFrameNumber);
int prepare(int streamId);
int tearDown(int streamId);
int prepare2(int maxCount, int streamId);
}

View File

@@ -33,14 +33,14 @@ import android.hardware.camera2.params.InputConfiguration;
import android.hardware.camera2.params.OutputConfiguration;
import android.hardware.camera2.params.ReprocessFormatsMap;
import android.hardware.camera2.params.StreamConfigurationMap;
import android.hardware.camera2.utils.CameraBinderDecorator;
import android.hardware.camera2.utils.CameraRuntimeException;
import android.hardware.camera2.utils.LongParcelable;
import android.hardware.camera2.utils.SubmitInfo;
import android.hardware.camera2.utils.SurfaceUtils;
import android.hardware.ICameraService;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
import android.os.RemoteException;
import android.os.ServiceSpecificException;
import android.util.Log;
import android.util.Range;
import android.util.Size;
@@ -70,7 +70,7 @@ public class CameraDeviceImpl extends CameraDevice {
private static final int REQUEST_ID_NONE = -1;
// TODO: guard every function with if (!mRemoteDevice) check (if it was closed)
private ICameraDeviceUser mRemoteDevice;
private ICameraDeviceUserWrapper mRemoteDevice;
// Lock to synchronize cross-thread access to device public interface
final Object mInterfaceLock = new Object(); // access from this class and Session only!
@@ -267,7 +267,7 @@ public class CameraDeviceImpl extends CameraDevice {
// If setRemoteFailure already called, do nothing
if (mInError) return;
mRemoteDevice = CameraBinderDecorator.newInstance(remoteDevice);
mRemoteDevice = new ICameraDeviceUserWrapper(remoteDevice);
mDeviceHandler.post(mCallOnOpened);
mDeviceHandler.post(mCallOnUnconfigured);
@@ -280,28 +280,29 @@ public class CameraDeviceImpl extends CameraDevice {
* <p>This places the camera device in the error state and informs the callback.
* Use in place of setRemoteDevice() when startup fails.</p>
*/
public void setRemoteFailure(final CameraRuntimeException failure) {
public void setRemoteFailure(final ServiceSpecificException failure) {
int failureCode = StateCallback.ERROR_CAMERA_DEVICE;
boolean failureIsError = true;
switch (failure.getReason()) {
case CameraAccessException.CAMERA_IN_USE:
switch (failure.errorCode) {
case ICameraService.ERROR_CAMERA_IN_USE:
failureCode = StateCallback.ERROR_CAMERA_IN_USE;
break;
case CameraAccessException.MAX_CAMERAS_IN_USE:
case ICameraService.ERROR_MAX_CAMERAS_IN_USE:
failureCode = StateCallback.ERROR_MAX_CAMERAS_IN_USE;
break;
case CameraAccessException.CAMERA_DISABLED:
case ICameraService.ERROR_DISABLED:
failureCode = StateCallback.ERROR_CAMERA_DISABLED;
break;
case CameraAccessException.CAMERA_DISCONNECTED:
case ICameraService.ERROR_DISCONNECTED:
failureIsError = false;
break;
case CameraAccessException.CAMERA_ERROR:
case ICameraService.ERROR_INVALID_OPERATION:
failureCode = StateCallback.ERROR_CAMERA_DEVICE;
break;
default:
Log.wtf(TAG, "Unknown failure in opening camera device: " + failure.getReason());
Log.e(TAG, "Unexpected failure in opening camera device: " + failure.errorCode +
failure.getMessage());
break;
}
final int code = failureCode;
@@ -430,27 +431,20 @@ public class CameraDeviceImpl extends CameraDevice {
}
}
try {
mRemoteDevice.endConfigure(isConstrainedHighSpeed);
}
catch (IllegalArgumentException e) {
// OK. camera service can reject stream config if it's not supported by HAL
// This is only the result of a programmer misusing the camera2 api.
Log.w(TAG, "Stream configuration failed");
return false;
}
mRemoteDevice.endConfigure(isConstrainedHighSpeed);
success = true;
} catch (CameraRuntimeException e) {
if (e.getReason() == CAMERA_IN_USE) {
throw new IllegalStateException("The camera is currently busy." +
" You must wait until the previous operation completes.");
}
throw e.asChecked();
} catch (RemoteException e) {
// impossible
} catch (IllegalArgumentException e) {
// OK. camera service can reject stream config if it's not supported by HAL
// This is only the result of a programmer misusing the camera2 api.
Log.w(TAG, "Stream configuration failed due to: " + e.getMessage());
return false;
} catch (CameraAccessException e) {
if (e.getReason() == CameraAccessException.CAMERA_IN_USE) {
throw new IllegalStateException("The camera is currently busy." +
" You must wait until the previous operation completes.", e);
}
throw e;
} finally {
if (success && outputs.size() > 0) {
mDeviceHandler.post(mCallOnIdle);
@@ -594,12 +588,7 @@ public class CameraDeviceImpl extends CameraDevice {
configureSuccess = configureStreamsChecked(inputConfig, outputConfigurations,
isConstrainedHighSpeed);
if (configureSuccess == true && inputConfig != null) {
input = new Surface();
try {
mRemoteDevice.getInputSurface(/*out*/input);
} catch (CameraRuntimeException e) {
e.asChecked();
}
input = mRemoteDevice.getInputSurface();
}
} catch (CameraAccessException e) {
configureSuccess = false;
@@ -608,9 +597,6 @@ public class CameraDeviceImpl extends CameraDevice {
if (DEBUG) {
Log.v(TAG, "createCaptureSession - failed with exception ", e);
}
} catch (RemoteException e) {
// impossible
return;
}
List<Surface> outSurfaces = new ArrayList<>(outputConfigurations.size());
@@ -655,16 +641,9 @@ public class CameraDeviceImpl extends CameraDevice {
synchronized(mInterfaceLock) {
checkIfCameraClosedOrInError();
CameraMetadataNative templatedRequest = new CameraMetadataNative();
CameraMetadataNative templatedRequest = null;
try {
mRemoteDevice.createDefaultRequest(templateType, /*out*/templatedRequest);
} catch (CameraRuntimeException e) {
throw e.asChecked();
} catch (RemoteException e) {
// impossible
return null;
}
templatedRequest = mRemoteDevice.createDefaultRequest(templateType);
CaptureRequest.Builder builder = new CaptureRequest.Builder(
templatedRequest, /*reprocess*/false, CameraCaptureSession.SESSION_ID_NONE);
@@ -701,14 +680,8 @@ public class CameraDeviceImpl extends CameraDevice {
if (streamId == -1) {
throw new IllegalArgumentException("Surface is not part of this session");
}
try {
mRemoteDevice.prepare(streamId);
} catch (CameraRuntimeException e) {
throw e.asChecked();
} catch (RemoteException e) {
// impossible
return;
}
mRemoteDevice.prepare(streamId);
}
}
@@ -728,14 +701,8 @@ public class CameraDeviceImpl extends CameraDevice {
if (streamId == -1) {
throw new IllegalArgumentException("Surface is not part of this session");
}
try {
mRemoteDevice.prepare2(maxCount, streamId);
} catch (CameraRuntimeException e) {
throw e.asChecked();
} catch (RemoteException e) {
// impossible
return;
}
mRemoteDevice.prepare2(maxCount, streamId);
}
}
@@ -753,14 +720,8 @@ public class CameraDeviceImpl extends CameraDevice {
if (streamId == -1) {
throw new IllegalArgumentException("Surface is not part of this session");
}
try {
mRemoteDevice.tearDown(streamId);
} catch (CameraRuntimeException e) {
throw e.asChecked();
} catch (RemoteException e) {
// impossible
return;
}
mRemoteDevice.tearDown(streamId);
}
}
@@ -875,45 +836,37 @@ public class CameraDeviceImpl extends CameraDevice {
synchronized(mInterfaceLock) {
checkIfCameraClosedOrInError();
int requestId;
if (repeating) {
stopRepeating();
}
LongParcelable lastFrameNumberRef = new LongParcelable();
try {
requestId = mRemoteDevice.submitRequestList(requestList, repeating,
/*out*/lastFrameNumberRef);
if (DEBUG) {
Log.v(TAG, "last frame number " + lastFrameNumberRef.getNumber());
}
} catch (CameraRuntimeException e) {
throw e.asChecked();
} catch (RemoteException e) {
// impossible
return -1;
SubmitInfo requestInfo;
CaptureRequest[] requestArray = requestList.toArray(new CaptureRequest[requestList.size()]);
requestInfo = mRemoteDevice.submitRequestList(requestArray, repeating);
if (DEBUG) {
Log.v(TAG, "last frame number " + requestInfo.getLastFrameNumber());
}
if (callback != null) {
mCaptureCallbackMap.put(requestId, new CaptureCallbackHolder(callback,
requestList, handler, repeating, mNextSessionId - 1));
mCaptureCallbackMap.put(requestInfo.getRequestId(),
new CaptureCallbackHolder(
callback, requestList, handler, repeating, mNextSessionId - 1));
} else {
if (DEBUG) {
Log.d(TAG, "Listen for request " + requestId + " is null");
Log.d(TAG, "Listen for request " + requestInfo.getRequestId() + " is null");
}
}
long lastFrameNumber = lastFrameNumberRef.getNumber();
if (repeating) {
if (mRepeatingRequestId != REQUEST_ID_NONE) {
checkEarlyTriggerSequenceComplete(mRepeatingRequestId, lastFrameNumber);
checkEarlyTriggerSequenceComplete(mRepeatingRequestId,
requestInfo.getLastFrameNumber());
}
mRepeatingRequestId = requestId;
mRepeatingRequestId = requestInfo.getRequestId();
} else {
mRequestLastFrameNumbersList.add(new RequestLastFrameNumbersHolder(requestList,
requestId, lastFrameNumber));
mRequestLastFrameNumbersList.add(
new RequestLastFrameNumbersHolder(requestList, requestInfo));
}
if (mIdle) {
@@ -921,7 +874,7 @@ public class CameraDeviceImpl extends CameraDevice {
}
mIdle = false;
return requestId;
return requestInfo.getRequestId();
}
}
@@ -949,19 +902,9 @@ public class CameraDeviceImpl extends CameraDevice {
int requestId = mRepeatingRequestId;
mRepeatingRequestId = REQUEST_ID_NONE;
try {
LongParcelable lastFrameNumberRef = new LongParcelable();
mRemoteDevice.cancelRequest(requestId, /*out*/lastFrameNumberRef);
long lastFrameNumber = lastFrameNumberRef.getNumber();
long lastFrameNumber = mRemoteDevice.cancelRequest(requestId);
checkEarlyTriggerSequenceComplete(requestId, lastFrameNumber);
} catch (CameraRuntimeException e) {
throw e.asChecked();
} catch (RemoteException e) {
// impossible
return;
}
checkEarlyTriggerSequenceComplete(requestId, lastFrameNumber);
}
}
}
@@ -974,14 +917,8 @@ public class CameraDeviceImpl extends CameraDevice {
if (mRepeatingRequestId != REQUEST_ID_NONE) {
throw new IllegalStateException("Active repeating request ongoing");
}
try {
mRemoteDevice.waitUntilIdle();
} catch (CameraRuntimeException e) {
throw e.asChecked();
} catch (RemoteException e) {
// impossible
return;
}
mRemoteDevice.waitUntilIdle();
}
}
@@ -997,19 +934,11 @@ public class CameraDeviceImpl extends CameraDevice {
mDeviceHandler.post(mCallOnIdle);
return;
}
try {
LongParcelable lastFrameNumberRef = new LongParcelable();
mRemoteDevice.flush(/*out*/lastFrameNumberRef);
if (mRepeatingRequestId != REQUEST_ID_NONE) {
long lastFrameNumber = lastFrameNumberRef.getNumber();
checkEarlyTriggerSequenceComplete(mRepeatingRequestId, lastFrameNumber);
mRepeatingRequestId = REQUEST_ID_NONE;
}
} catch (CameraRuntimeException e) {
throw e.asChecked();
} catch (RemoteException e) {
// impossible
return;
long lastFrameNumber = mRemoteDevice.flush();
if (mRepeatingRequestId != REQUEST_ID_NONE) {
checkEarlyTriggerSequenceComplete(mRepeatingRequestId, lastFrameNumber);
mRepeatingRequestId = REQUEST_ID_NONE;
}
}
}
@@ -1021,14 +950,8 @@ public class CameraDeviceImpl extends CameraDevice {
return;
}
try {
if (mRemoteDevice != null) {
mRemoteDevice.disconnect();
}
} catch (CameraRuntimeException e) {
Log.e(TAG, "Exception while closing: ", e.asChecked());
} catch (RemoteException e) {
// impossible
if (mRemoteDevice != null) {
mRemoteDevice.disconnect();
}
// Only want to fire the onClosed callback once;
@@ -1297,14 +1220,14 @@ public class CameraDeviceImpl extends CameraDevice {
* Create a request-last-frame-numbers holder with a list of requests, request ID, and
* the last frame number returned by camera service.
*/
public RequestLastFrameNumbersHolder(List<CaptureRequest> requestList, int requestId,
long lastFrameNumber) {
public RequestLastFrameNumbersHolder(List<CaptureRequest> requestList, SubmitInfo requestInfo) {
long lastRegularFrameNumber = CaptureCallback.NO_FRAMES_CAPTURED;
long lastReprocessFrameNumber = CaptureCallback.NO_FRAMES_CAPTURED;
long frameNumber = lastFrameNumber;
long frameNumber = requestInfo.getLastFrameNumber();
if (lastFrameNumber < requestList.size() - 1) {
throw new IllegalArgumentException("lastFrameNumber: " + lastFrameNumber +
if (requestInfo.getLastFrameNumber() < requestList.size() - 1) {
throw new IllegalArgumentException(
"lastFrameNumber: " + requestInfo.getLastFrameNumber() +
" should be at least " + (requestList.size() - 1) + " for the number of " +
" requests in the list: " + requestList.size());
}
@@ -1330,7 +1253,7 @@ public class CameraDeviceImpl extends CameraDevice {
mLastRegularFrameNumber = lastRegularFrameNumber;
mLastReprocessFrameNumber = lastReprocessFrameNumber;
mRequestId = requestId;
mRequestId = requestInfo.getRequestId();
}
/**

View File

@@ -1,20 +0,0 @@
/*
* Copyright (C) 2013 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.impl;
/** @hide */
parcelable CameraMetadataNative;

View File

@@ -58,6 +58,7 @@ import android.location.Location;
import android.location.LocationManager;
import android.os.Parcelable;
import android.os.Parcel;
import android.os.ServiceSpecificException;
import android.util.Log;
import android.util.Size;
@@ -363,13 +364,24 @@ public class CameraMetadataNative implements Parcelable {
* Set the global client-side vendor tag descriptor to allow use of vendor
* tags in camera applications.
*
* @return int A native status_t value corresponding to one of the
* {@link CameraBinderDecorator} integer constants.
* @see CameraBinderDecorator#throwOnError
*
* @throws ServiceSpecificException
* @hide
*/
public static native int nativeSetupGlobalVendorTagDescriptor();
public static void setupGlobalVendorTagDescriptor() throws ServiceSpecificException {
int err = nativeSetupGlobalVendorTagDescriptor();
if (err != 0) {
throw new ServiceSpecificException(err, "Failure to set up global vendor tags");
}
}
/**
* Set the global client-side vendor tag descriptor to allow use of vendor
* tags in camera applications.
*
* @return int An error code corresponding to one of the
* {@link ICameraService} error constants, or 0 on success.
*/
private static native int nativeSetupGlobalVendorTagDescriptor();
/**
* Set a camera metadata field to a value. The field definitions can be

View File

@@ -1,20 +0,0 @@
/*
* 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.impl;
/** @hide */
parcelable CaptureResultExtras;

View File

@@ -0,0 +1,212 @@
/*
* Copyright (C) 2016 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.impl;
import static android.hardware.camera2.CameraAccessException.CAMERA_DISABLED;
import static android.hardware.camera2.CameraAccessException.CAMERA_DISCONNECTED;
import static android.hardware.camera2.CameraAccessException.CAMERA_IN_USE;
import static android.hardware.camera2.CameraAccessException.CAMERA_ERROR;
import static android.hardware.camera2.CameraAccessException.MAX_CAMERAS_IN_USE;
import static android.hardware.camera2.CameraAccessException.CAMERA_DEPRECATED_HAL;
import android.hardware.ICameraService;
import android.hardware.camera2.CameraManager;
import android.hardware.camera2.CameraAccessException;
import android.hardware.camera2.CaptureRequest;
import android.hardware.camera2.ICameraDeviceUser;
import android.hardware.camera2.impl.CameraMetadataNative;
import android.hardware.camera2.params.OutputConfiguration;
import android.hardware.camera2.utils.SubmitInfo;
import android.os.RemoteException;
import android.view.Surface;
/**
* A wrapper around ICameraDeviceUser.
*
* Mainly used to convert ServiceSpecificExceptions to the correct
* checked / unchecked exception.
*
* @hide
*/
public class ICameraDeviceUserWrapper {
private final ICameraDeviceUser mRemoteDevice;
public ICameraDeviceUserWrapper(ICameraDeviceUser remoteDevice) {
if (remoteDevice == null) {
throw new NullPointerException("Remote device may not be null");
}
mRemoteDevice = remoteDevice;
}
public void disconnect() {
try {
mRemoteDevice.disconnect();
} catch (RemoteException t) {
// ignore binder errors for disconnect
}
}
public SubmitInfo submitRequest(CaptureRequest request, boolean streaming)
throws CameraAccessException {
try {
return mRemoteDevice.submitRequest(request, streaming);
} catch (Throwable t) {
CameraManager.throwAsPublicException(t);
throw new UnsupportedOperationException("Unexpected exception", t);
}
}
public SubmitInfo submitRequestList(CaptureRequest[] requestList, boolean streaming)
throws CameraAccessException {
try {
return mRemoteDevice.submitRequestList(requestList, streaming);
} catch (Throwable t) {
CameraManager.throwAsPublicException(t);
throw new UnsupportedOperationException("Unexpected exception", t);
}
}
public long cancelRequest(int requestId) throws CameraAccessException {
try {
return mRemoteDevice.cancelRequest(requestId);
} catch (Throwable t) {
CameraManager.throwAsPublicException(t);
throw new UnsupportedOperationException("Unexpected exception", t);
}
}
public void beginConfigure() throws CameraAccessException {
try {
mRemoteDevice.beginConfigure();
} catch (Throwable t) {
CameraManager.throwAsPublicException(t);
throw new UnsupportedOperationException("Unexpected exception", t);
}
}
public void endConfigure(boolean isConstrainedHighSpeed) throws CameraAccessException {
try {
mRemoteDevice.endConfigure(isConstrainedHighSpeed);
} catch (Throwable t) {
CameraManager.throwAsPublicException(t);
throw new UnsupportedOperationException("Unexpected exception", t);
}
}
public void deleteStream(int streamId) throws CameraAccessException {
try {
mRemoteDevice.deleteStream(streamId);
} catch (Throwable t) {
CameraManager.throwAsPublicException(t);
throw new UnsupportedOperationException("Unexpected exception", t);
}
}
public int createStream(OutputConfiguration outputConfiguration)
throws CameraAccessException {
try {
return mRemoteDevice.createStream(outputConfiguration);
} catch (Throwable t) {
CameraManager.throwAsPublicException(t);
throw new UnsupportedOperationException("Unexpected exception", t);
}
}
public int createInputStream(int width, int height, int format) throws CameraAccessException {
try {
return mRemoteDevice.createInputStream(width, height, format);
} catch (Throwable t) {
CameraManager.throwAsPublicException(t);
throw new UnsupportedOperationException("Unexpected exception", t);
}
}
public Surface getInputSurface() throws CameraAccessException {
try {
return mRemoteDevice.getInputSurface();
} catch (Throwable t) {
CameraManager.throwAsPublicException(t);
throw new UnsupportedOperationException("Unexpected exception", t);
}
}
public CameraMetadataNative createDefaultRequest(int templateId) throws CameraAccessException {
try {
return mRemoteDevice.createDefaultRequest(templateId);
} catch (Throwable t) {
CameraManager.throwAsPublicException(t);
throw new UnsupportedOperationException("Unexpected exception", t);
}
}
public CameraMetadataNative getCameraInfo() throws CameraAccessException {
try {
return mRemoteDevice.getCameraInfo();
} catch (Throwable t) {
CameraManager.throwAsPublicException(t);
throw new UnsupportedOperationException("Unexpected exception", t);
}
}
public void waitUntilIdle() throws CameraAccessException {
try {
mRemoteDevice.waitUntilIdle();
} catch (Throwable t) {
CameraManager.throwAsPublicException(t);
throw new UnsupportedOperationException("Unexpected exception", t);
}
}
public long flush() throws CameraAccessException {
try {
return mRemoteDevice.flush();
} catch (Throwable t) {
CameraManager.throwAsPublicException(t);
throw new UnsupportedOperationException("Unexpected exception", t);
}
}
public void prepare(int streamId) throws CameraAccessException {
try {
mRemoteDevice.prepare(streamId);
} catch (Throwable t) {
CameraManager.throwAsPublicException(t);
throw new UnsupportedOperationException("Unexpected exception", t);
}
}
public void tearDown(int streamId) throws CameraAccessException {
try {
mRemoteDevice.tearDown(streamId);
} catch (Throwable t) {
CameraManager.throwAsPublicException(t);
throw new UnsupportedOperationException("Unexpected exception", t);
}
}
public void prepare2(int maxCount, int streamId) throws CameraAccessException {
try {
mRemoteDevice.prepare2(maxCount, streamId);
} catch (Throwable t) {
CameraManager.throwAsPublicException(t);
throw new UnsupportedOperationException("Unexpected exception", t);
}
}
}

View File

@@ -35,10 +35,10 @@ public class BurstHolder {
*
* @param requestId id of the burst request.
* @param repeating true if this burst is repeating.
* @param requests a {@link List} of {@link CaptureRequest}s in this burst.
* @param requests the array of {@link CaptureRequest}s for this burst.
* @param jpegSurfaceIds a {@link Collection} of IDs for the surfaces that have jpeg outputs.
*/
public BurstHolder(int requestId, boolean repeating, List<CaptureRequest> requests,
public BurstHolder(int requestId, boolean repeating, CaptureRequest[] requests,
Collection<Long> jpegSurfaceIds) {
mRequestBuilders = new ArrayList<>();
int i = 0;

View File

@@ -16,6 +16,7 @@
package android.hardware.camera2.legacy;
import android.hardware.ICameraService;
import android.hardware.Camera;
import android.hardware.Camera.CameraInfo;
import android.hardware.camera2.CameraAccessException;
@@ -23,12 +24,10 @@ import android.hardware.camera2.CameraCharacteristics;
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.impl.CaptureResultExtras;
import android.hardware.camera2.params.OutputConfiguration;
import android.hardware.camera2.utils.CameraBinderDecorator;
import android.hardware.camera2.utils.CameraRuntimeException;
import android.hardware.camera2.utils.SubmitInfo;
import android.os.ConditionVariable;
import android.os.IBinder;
import android.os.Looper;
@@ -36,6 +35,7 @@ import android.os.Handler;
import android.os.HandlerThread;
import android.os.Message;
import android.os.RemoteException;
import android.os.ServiceSpecificException;
import android.util.Log;
import android.util.SparseArray;
import android.view.Surface;
@@ -93,7 +93,7 @@ public class CameraDeviceUserShim implements ICameraDeviceUser {
private static int translateErrorsFromCamera1(int errorCode) {
if (errorCode == -EACCES) {
return CameraBinderDecorator.PERMISSION_DENIED;
return ICameraService.ERROR_PERMISSION_DENIED;
}
return errorCode;
@@ -173,7 +173,7 @@ public class CameraDeviceUserShim implements ICameraDeviceUser {
*
* @return int error code
*
* @throws CameraRuntimeException if the camera open times out with ({@code CAMERA_ERROR})
* @throws ServiceSpecificException if the camera open times out with ({@code CAMERA_ERROR})
*/
public int waitForOpen(int timeoutMs) {
// Block until the camera is open asynchronously
@@ -186,7 +186,7 @@ public class CameraDeviceUserShim implements ICameraDeviceUser {
Log.e(TAG, "connectBinderShim - Failed to release camera after timeout ", e);
}
throw new CameraRuntimeException(CameraAccessException.CAMERA_ERROR);
throw new ServiceSpecificException(ICameraService.ERROR_INVALID_OPERATION);
}
return mInitErrors;
@@ -344,7 +344,7 @@ public class CameraDeviceUserShim implements ICameraDeviceUser {
Camera legacyCamera = init.getCamera();
// Check errors old HAL initialization
CameraBinderDecorator.throwOnError(initErrors);
LegacyExceptionUtils.throwOnServiceError(initErrors);
// Disable shutter sounds (this will work unconditionally) for api2 clients
legacyCamera.disableShutterSound();
@@ -356,8 +356,8 @@ public class CameraDeviceUserShim implements ICameraDeviceUser {
try {
legacyParameters = legacyCamera.getParameters();
} catch (RuntimeException e) {
throw new CameraRuntimeException(CameraAccessException.CAMERA_ERROR,
"Unable to get initial parameters", e);
throw new ServiceSpecificException(ICameraService.ERROR_INVALID_OPERATION,
"Unable to get initial parameters: " + e.getMessage());
}
CameraCharacteristics characteristics =
@@ -386,101 +386,106 @@ public class CameraDeviceUserShim implements ICameraDeviceUser {
}
@Override
public int submitRequest(CaptureRequest request, boolean streaming,
/*out*/LongParcelable lastFrameNumber) {
public SubmitInfo submitRequest(CaptureRequest request, boolean streaming) {
if (DEBUG) {
Log.d(TAG, "submitRequest called.");
}
if (mLegacyDevice.isClosed()) {
Log.e(TAG, "Cannot submit request, device has been closed.");
return -ENODEV;
String err = "Cannot submit request, device has been closed.";
Log.e(TAG, err);
throw new ServiceSpecificException(ICameraService.ERROR_DISCONNECTED, err);
}
synchronized(mConfigureLock) {
if (mConfiguring) {
Log.e(TAG, "Cannot submit request, configuration change in progress.");
return CameraBinderDecorator.INVALID_OPERATION;
String err = "Cannot submit request, configuration change in progress.";
Log.e(TAG, err);
throw new ServiceSpecificException(ICameraService.ERROR_INVALID_OPERATION, err);
}
}
return mLegacyDevice.submitRequest(request, streaming, lastFrameNumber);
return mLegacyDevice.submitRequest(request, streaming);
}
@Override
public int submitRequestList(List<CaptureRequest> request, boolean streaming,
/*out*/LongParcelable lastFrameNumber) {
public SubmitInfo submitRequestList(CaptureRequest[] request, boolean streaming) {
if (DEBUG) {
Log.d(TAG, "submitRequestList called.");
}
if (mLegacyDevice.isClosed()) {
Log.e(TAG, "Cannot submit request list, device has been closed.");
return -ENODEV;
String err = "Cannot submit request list, device has been closed.";
Log.e(TAG, err);
throw new ServiceSpecificException(ICameraService.ERROR_DISCONNECTED, err);
}
synchronized(mConfigureLock) {
if (mConfiguring) {
Log.e(TAG, "Cannot submit request, configuration change in progress.");
return CameraBinderDecorator.INVALID_OPERATION;
String err = "Cannot submit request, configuration change in progress.";
Log.e(TAG, err);
throw new ServiceSpecificException(ICameraService.ERROR_INVALID_OPERATION, err);
}
}
return mLegacyDevice.submitRequestList(request, streaming, lastFrameNumber);
return mLegacyDevice.submitRequestList(request, streaming);
}
@Override
public int cancelRequest(int requestId, /*out*/LongParcelable lastFrameNumber) {
public long cancelRequest(int requestId) {
if (DEBUG) {
Log.d(TAG, "cancelRequest called.");
}
if (mLegacyDevice.isClosed()) {
Log.e(TAG, "Cannot cancel request, device has been closed.");
return -ENODEV;
String err = "Cannot cancel request, device has been closed.";
Log.e(TAG, err);
throw new ServiceSpecificException(ICameraService.ERROR_DISCONNECTED, err);
}
synchronized(mConfigureLock) {
if (mConfiguring) {
Log.e(TAG, "Cannot cancel request, configuration change in progress.");
return CameraBinderDecorator.INVALID_OPERATION;
String err = "Cannot cancel request, configuration change in progress.";
Log.e(TAG, err);
throw new ServiceSpecificException(ICameraService.ERROR_INVALID_OPERATION, err);
}
}
long lastFrame = mLegacyDevice.cancelRequest(requestId);
lastFrameNumber.setNumber(lastFrame);
return CameraBinderDecorator.NO_ERROR;
return mLegacyDevice.cancelRequest(requestId);
}
@Override
public int beginConfigure() {
public void beginConfigure() {
if (DEBUG) {
Log.d(TAG, "beginConfigure called.");
}
if (mLegacyDevice.isClosed()) {
Log.e(TAG, "Cannot begin configure, device has been closed.");
return -ENODEV;
String err = "Cannot begin configure, device has been closed.";
Log.e(TAG, err);
throw new ServiceSpecificException(ICameraService.ERROR_DISCONNECTED, err);
}
synchronized(mConfigureLock) {
if (mConfiguring) {
Log.e(TAG, "Cannot begin configure, configuration change already in progress.");
return CameraBinderDecorator.INVALID_OPERATION;
String err = "Cannot begin configure, configuration change already in progress.";
Log.e(TAG, err);
throw new ServiceSpecificException(ICameraService.ERROR_INVALID_OPERATION, err);
}
mConfiguring = true;
}
return CameraBinderDecorator.NO_ERROR;
}
@Override
public int endConfigure(boolean isConstrainedHighSpeed) {
public void endConfigure(boolean isConstrainedHighSpeed) {
if (DEBUG) {
Log.d(TAG, "endConfigure called.");
}
if (mLegacyDevice.isClosed()) {
Log.e(TAG, "Cannot end configure, device has been closed.");
return -ENODEV;
String err = "Cannot end configure, device has been closed.";
Log.e(TAG, err);
throw new ServiceSpecificException(ICameraService.ERROR_DISCONNECTED, err);
}
ArrayList<Surface> surfaces = null;
synchronized(mConfigureLock) {
if (!mConfiguring) {
Log.e(TAG, "Cannot end configure, no configuration change in progress.");
return CameraBinderDecorator.INVALID_OPERATION;
String err = "Cannot end configure, no configuration change in progress.";
Log.e(TAG, err);
throw new ServiceSpecificException(ICameraService.ERROR_INVALID_OPERATION, err);
}
int numSurfaces = mSurfaces.size();
if (numSurfaces > 0) {
@@ -491,32 +496,34 @@ public class CameraDeviceUserShim implements ICameraDeviceUser {
}
mConfiguring = false;
}
return mLegacyDevice.configureOutputs(surfaces);
mLegacyDevice.configureOutputs(surfaces);
}
@Override
public int deleteStream(int streamId) {
public void deleteStream(int streamId) {
if (DEBUG) {
Log.d(TAG, "deleteStream called.");
}
if (mLegacyDevice.isClosed()) {
Log.e(TAG, "Cannot delete stream, device has been closed.");
return -ENODEV;
String err = "Cannot delete stream, device has been closed.";
Log.e(TAG, err);
throw new ServiceSpecificException(ICameraService.ERROR_DISCONNECTED, err);
}
synchronized(mConfigureLock) {
if (!mConfiguring) {
Log.e(TAG, "Cannot delete stream, beginConfigure hasn't been called yet.");
return CameraBinderDecorator.INVALID_OPERATION;
String err = "Cannot delete stream, no configuration change in progress.";
Log.e(TAG, err);
throw new ServiceSpecificException(ICameraService.ERROR_INVALID_OPERATION, err);
}
int index = mSurfaces.indexOfKey(streamId);
if (index < 0) {
Log.e(TAG, "Cannot delete stream, stream id " + streamId + " doesn't exist.");
return CameraBinderDecorator.BAD_VALUE;
String err = "Cannot delete stream, stream id " + streamId + " doesn't exist.";
Log.e(TAG, err);
throw new ServiceSpecificException(ICameraService.ERROR_ILLEGAL_ARGUMENT, err);
}
mSurfaces.removeAt(index);
}
return CameraBinderDecorator.NO_ERROR;
}
@Override
@@ -525,18 +532,21 @@ public class CameraDeviceUserShim implements ICameraDeviceUser {
Log.d(TAG, "createStream called.");
}
if (mLegacyDevice.isClosed()) {
Log.e(TAG, "Cannot create stream, device has been closed.");
return -ENODEV;
String err = "Cannot create stream, device has been closed.";
Log.e(TAG, err);
throw new ServiceSpecificException(ICameraService.ERROR_DISCONNECTED, err);
}
synchronized(mConfigureLock) {
if (!mConfiguring) {
Log.e(TAG, "Cannot create stream, beginConfigure hasn't been called yet.");
return CameraBinderDecorator.INVALID_OPERATION;
String err = "Cannot create stream, beginConfigure hasn't been called yet.";
Log.e(TAG, err);
throw new ServiceSpecificException(ICameraService.ERROR_INVALID_OPERATION, err);
}
if (outputConfiguration.getRotation() != OutputConfiguration.ROTATION_0) {
Log.e(TAG, "Cannot create stream, stream rotation is not supported.");
return CameraBinderDecorator.INVALID_OPERATION;
String err = "Cannot create stream, stream rotation is not supported.";
Log.e(TAG, err);
throw new ServiceSpecificException(ICameraService.ERROR_ILLEGAL_ARGUMENT, err);
}
int id = ++mSurfaceIdCounter;
mSurfaces.put(id, outputConfiguration.getSurface());
@@ -546,24 +556,27 @@ public class CameraDeviceUserShim implements ICameraDeviceUser {
@Override
public int createInputStream(int width, int height, int format) {
Log.e(TAG, "creating input stream is not supported on legacy devices");
return CameraBinderDecorator.INVALID_OPERATION;
String err = "Creating input stream is not supported on legacy devices";
Log.e(TAG, err);
throw new ServiceSpecificException(ICameraService.ERROR_INVALID_OPERATION, err);
}
@Override
public int getInputSurface(/*out*/ Surface surface) {
Log.e(TAG, "getting input surface is not supported on legacy devices");
return CameraBinderDecorator.INVALID_OPERATION;
public Surface getInputSurface() {
String err = "Getting input surface is not supported on legacy devices";
Log.e(TAG, err);
throw new ServiceSpecificException(ICameraService.ERROR_INVALID_OPERATION, err);
}
@Override
public int createDefaultRequest(int templateId, /*out*/CameraMetadataNative request) {
public CameraMetadataNative createDefaultRequest(int templateId) {
if (DEBUG) {
Log.d(TAG, "createDefaultRequest called.");
}
if (mLegacyDevice.isClosed()) {
Log.e(TAG, "Cannot create default request, device has been closed.");
return -ENODEV;
String err = "Cannot create default request, device has been closed.";
Log.e(TAG, err);
throw new ServiceSpecificException(ICameraService.ERROR_DISCONNECTED, err);
}
CameraMetadataNative template;
@@ -571,99 +584,96 @@ public class CameraDeviceUserShim implements ICameraDeviceUser {
template =
LegacyMetadataMapper.createRequestTemplate(mCameraCharacteristics, templateId);
} catch (IllegalArgumentException e) {
Log.e(TAG, "createDefaultRequest - invalid templateId specified");
return CameraBinderDecorator.BAD_VALUE;
String err = "createDefaultRequest - invalid templateId specified";
Log.e(TAG, err);
throw new ServiceSpecificException(ICameraService.ERROR_ILLEGAL_ARGUMENT, err);
}
request.swap(template);
return CameraBinderDecorator.NO_ERROR;
return template;
}
@Override
public int getCameraInfo(/*out*/CameraMetadataNative info) {
public CameraMetadataNative getCameraInfo() {
if (DEBUG) {
Log.d(TAG, "getCameraInfo called.");
}
// TODO: implement getCameraInfo.
Log.e(TAG, "getCameraInfo unimplemented.");
return CameraBinderDecorator.NO_ERROR;
return null;
}
@Override
public int waitUntilIdle() throws RemoteException {
public void waitUntilIdle() throws RemoteException {
if (DEBUG) {
Log.d(TAG, "waitUntilIdle called.");
}
if (mLegacyDevice.isClosed()) {
Log.e(TAG, "Cannot wait until idle, device has been closed.");
return -ENODEV;
String err = "Cannot wait until idle, device has been closed.";
Log.e(TAG, err);
throw new ServiceSpecificException(ICameraService.ERROR_DISCONNECTED, err);
}
synchronized(mConfigureLock) {
if (mConfiguring) {
Log.e(TAG, "Cannot wait until idle, configuration change in progress.");
return CameraBinderDecorator.INVALID_OPERATION;
String err = "Cannot wait until idle, configuration change in progress.";
Log.e(TAG, err);
throw new ServiceSpecificException(ICameraService.ERROR_INVALID_OPERATION, err);
}
}
mLegacyDevice.waitUntilIdle();
return CameraBinderDecorator.NO_ERROR;
}
@Override
public int flush(/*out*/LongParcelable lastFrameNumber) {
public long flush() {
if (DEBUG) {
Log.d(TAG, "flush called.");
}
if (mLegacyDevice.isClosed()) {
Log.e(TAG, "Cannot flush, device has been closed.");
return -ENODEV;
String err = "Cannot flush, device has been closed.";
Log.e(TAG, err);
throw new ServiceSpecificException(ICameraService.ERROR_DISCONNECTED, err);
}
synchronized(mConfigureLock) {
if (mConfiguring) {
Log.e(TAG, "Cannot flush, configuration change in progress.");
return CameraBinderDecorator.INVALID_OPERATION;
String err = "Cannot flush, configuration change in progress.";
Log.e(TAG, err);
throw new ServiceSpecificException(ICameraService.ERROR_INVALID_OPERATION, err);
}
}
long lastFrame = mLegacyDevice.flush();
if (lastFrameNumber != null) {
lastFrameNumber.setNumber(lastFrame);
}
return CameraBinderDecorator.NO_ERROR;
return mLegacyDevice.flush();
}
public int prepare(int streamId) {
public void prepare(int streamId) {
if (DEBUG) {
Log.d(TAG, "prepare called.");
}
if (mLegacyDevice.isClosed()) {
Log.e(TAG, "Cannot prepare stream, device has been closed.");
return -ENODEV;
String err = "Cannot prepare stream, device has been closed.";
Log.e(TAG, err);
throw new ServiceSpecificException(ICameraService.ERROR_DISCONNECTED, err);
}
// LEGACY doesn't support actual prepare, just signal success right away
mCameraCallbacks.onPrepared(streamId);
return CameraBinderDecorator.NO_ERROR;
}
public int prepare2(int maxCount, int streamId) {
public void prepare2(int maxCount, int streamId) {
// We don't support this in LEGACY mode.
return prepare(streamId);
prepare(streamId);
}
public int tearDown(int streamId) {
public void tearDown(int streamId) {
if (DEBUG) {
Log.d(TAG, "tearDown called.");
}
if (mLegacyDevice.isClosed()) {
Log.e(TAG, "Cannot tear down stream, device has been closed.");
return -ENODEV;
String err = "Cannot tear down stream, device has been closed.";
Log.e(TAG, err);
throw new ServiceSpecificException(ICameraService.ERROR_DISCONNECTED, err);
}
// LEGACY doesn't support actual teardown, so just a no-op
return CameraBinderDecorator.NO_ERROR;
}
@Override

View File

@@ -26,14 +26,13 @@ import android.hardware.camera2.impl.CaptureResultExtras;
import android.hardware.camera2.ICameraDeviceCallbacks;
import android.hardware.camera2.params.StreamConfigurationMap;
import android.hardware.camera2.utils.ArrayUtils;
import android.hardware.camera2.utils.CameraBinderDecorator;
import android.hardware.camera2.utils.LongParcelable;
import android.hardware.camera2.utils.SubmitInfo;
import android.hardware.camera2.impl.CameraMetadataNative;
import android.hardware.camera2.utils.CameraRuntimeException;
import android.os.ConditionVariable;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.RemoteException;
import android.os.ServiceSpecificException;
import android.util.Log;
import android.util.Pair;
import android.util.Size;
@@ -45,7 +44,6 @@ import java.util.Collection;
import java.util.List;
import static android.hardware.camera2.legacy.LegacyExceptionUtils.*;
import static android.hardware.camera2.utils.CameraBinderDecorator.*;
import static com.android.internal.util.Preconditions.*;
/**
@@ -357,9 +355,9 @@ public class LegacyCameraDevice implements AutoCloseable {
if (success) {
mConfiguredSurfaces = outputs != null ? new ArrayList<>(outputs) : null;
} else {
return CameraBinderDecorator.INVALID_OPERATION;
return LegacyExceptionUtils.INVALID_OPERATION;
}
return CameraBinderDecorator.NO_ERROR;
return LegacyExceptionUtils.NO_ERROR;
}
/**
@@ -367,17 +365,16 @@ public class LegacyCameraDevice implements AutoCloseable {
*
* @param requestList a list of capture requests to execute.
* @param repeating {@code true} if this burst is repeating.
* @param frameNumber an output argument that contains either the frame number of the last frame
* that will be returned for this request, or the frame number of the last
* frame that will be returned for the current repeating request if this
* burst is set to be repeating.
* @return the request id.
* @return the submission info, including the new request id, and the last frame number, which
* contains either the frame number of the last frame that will be returned for this request,
* or the frame number of the last frame that will be returned for the current repeating
* request if this burst is set to be repeating.
*/
public int submitRequestList(List<CaptureRequest> requestList, boolean repeating,
/*out*/LongParcelable frameNumber) {
if (requestList == null || requestList.isEmpty()) {
public SubmitInfo submitRequestList(CaptureRequest[] requestList, boolean repeating) {
if (requestList == null || requestList.length == 0) {
Log.e(TAG, "submitRequestList - Empty/null requests are not allowed");
return BAD_VALUE;
throw new ServiceSpecificException(BAD_VALUE,
"submitRequestList - Empty/null requests are not allowed");
}
List<Long> surfaceIds = (mConfiguredSurfaces == null) ? new ArrayList<Long>() :
@@ -388,28 +385,33 @@ public class LegacyCameraDevice implements AutoCloseable {
if (request.getTargets().isEmpty()) {
Log.e(TAG, "submitRequestList - "
+ "Each request must have at least one Surface target");
return BAD_VALUE;
throw new ServiceSpecificException(BAD_VALUE,
"submitRequestList - "
+ "Each request must have at least one Surface target");
}
for (Surface surface : request.getTargets()) {
if (surface == null) {
Log.e(TAG, "submitRequestList - Null Surface targets are not allowed");
return BAD_VALUE;
throw new ServiceSpecificException(BAD_VALUE,
"submitRequestList - Null Surface targets are not allowed");
} else if (mConfiguredSurfaces == null) {
Log.e(TAG, "submitRequestList - must configure " +
" device with valid surfaces before submitting requests");
return INVALID_OPERATION;
throw new ServiceSpecificException(INVALID_OPERATION,
"submitRequestList - must configure " +
" device with valid surfaces before submitting requests");
} else if (!containsSurfaceId(surface, surfaceIds)) {
Log.e(TAG, "submitRequestList - cannot use a surface that wasn't configured");
return BAD_VALUE;
throw new ServiceSpecificException(BAD_VALUE,
"submitRequestList - cannot use a surface that wasn't configured");
}
}
}
// TODO: further validation of request here
mIdle.close();
return mRequestThreadManager.submitCaptureRequests(requestList, repeating,
frameNumber);
return mRequestThreadManager.submitCaptureRequests(requestList, repeating);
}
/**
@@ -417,17 +419,14 @@ public class LegacyCameraDevice implements AutoCloseable {
*
* @param request the capture request to execute.
* @param repeating {@code true} if this request is repeating.
* @param frameNumber an output argument that contains either the frame number of the last frame
* that will be returned for this request, or the frame number of the last
* frame that will be returned for the current repeating request if this
* request is set to be repeating.
* @return the request id.
* @return the submission info, including the new request id, and the last frame number, which
* contains either the frame number of the last frame that will be returned for this request,
* or the frame number of the last frame that will be returned for the current repeating
* request if this burst is set to be repeating.
*/
public int submitRequest(CaptureRequest request, boolean repeating,
/*out*/LongParcelable frameNumber) {
ArrayList<CaptureRequest> requestList = new ArrayList<CaptureRequest>();
requestList.add(request);
return submitRequestList(requestList, repeating, frameNumber);
public SubmitInfo submitRequest(CaptureRequest request, boolean repeating) {
CaptureRequest[] requestList = { request };
return submitRequestList(requestList, repeating);
}
/**
@@ -493,7 +492,7 @@ public class LegacyCameraDevice implements AutoCloseable {
protected void finalize() throws Throwable {
try {
close();
} catch (CameraRuntimeException e) {
} catch (ServiceSpecificException e) {
Log.e(TAG, "Got error while trying to finalize, ignoring: " + e.getMessage());
} finally {
super.finalize();

View File

@@ -16,10 +16,11 @@
package android.hardware.camera2.legacy;
import android.hardware.camera2.utils.CameraBinderDecorator;
import android.hardware.ICameraService;
import android.os.ServiceSpecificException;
import android.util.AndroidException;
import static android.system.OsConstants.ENODEV;
import static android.system.OsConstants.*;
/**
* Utility class containing exception handling used solely by the compatibility mode shim.
@@ -27,6 +28,14 @@ import static android.system.OsConstants.ENODEV;
public class LegacyExceptionUtils {
private static final String TAG = "LegacyExceptionUtils";
public static final int NO_ERROR = 0;
public static final int PERMISSION_DENIED = -EPERM;
public static final int ALREADY_EXISTS = -EEXIST;
public static final int BAD_VALUE = -EINVAL;
public static final int DEAD_OBJECT = -ENOSYS;
public static final int INVALID_OPERATION = -EPIPE;
public static final int TIMED_OUT = -ETIMEDOUT;
/**
* Checked exception thrown when a BufferQueue has been abandoned by its consumer.
*/
@@ -58,8 +67,8 @@ public class LegacyExceptionUtils {
* @return {@code errorFlag} if the value was non-negative, throws otherwise.
*/
public static int throwOnError(int errorFlag) throws BufferQueueAbandonedException {
if (errorFlag == CameraBinderDecorator.NO_ERROR) {
return CameraBinderDecorator.NO_ERROR;
if (errorFlag == NO_ERROR) {
return NO_ERROR;
} else if (errorFlag == -ENODEV) {
throw new BufferQueueAbandonedException();
}
@@ -70,6 +79,59 @@ public class LegacyExceptionUtils {
return errorFlag;
}
/**
* Throw error codes returned by the camera service as exceptions.
*
* @param errorFlag error to throw as an exception.
*/
public static void throwOnServiceError(int errorFlag) {
int errorCode = ICameraService.ERROR_INVALID_OPERATION;
String errorMsg;
if (errorFlag >= NO_ERROR) {
return;
} else if (errorFlag == PERMISSION_DENIED) {
errorCode = ICameraService.ERROR_PERMISSION_DENIED;
errorMsg = "Lacking privileges to access camera service";
} else if (errorFlag == ALREADY_EXISTS) {
// This should be handled at the call site. Typically this isn't bad,
// just means we tried to do an operation that already completed.
return;
} else if (errorFlag == BAD_VALUE) {
errorCode = ICameraService.ERROR_ILLEGAL_ARGUMENT;
errorMsg = "Bad argument passed to camera service";
} else if (errorFlag == DEAD_OBJECT) {
errorCode = ICameraService.ERROR_DISCONNECTED;
errorMsg = "Camera service not available";
} else if (errorFlag == TIMED_OUT) {
errorCode = ICameraService.ERROR_INVALID_OPERATION;
errorMsg = "Operation timed out in camera service";
} else if (errorFlag == -EACCES) {
errorCode = ICameraService.ERROR_DISABLED;
errorMsg = "Camera disabled by policy";
} else if (errorFlag == -EBUSY) {
errorCode = ICameraService.ERROR_CAMERA_IN_USE;
errorMsg = "Camera already in use";
} else if (errorFlag == -EUSERS) {
errorCode = ICameraService.ERROR_MAX_CAMERAS_IN_USE;
errorMsg = "Maximum number of cameras in use";
} else if (errorFlag == -ENODEV) {
errorCode = ICameraService.ERROR_DISCONNECTED;
errorMsg = "Camera device not available";
} else if (errorFlag == -EOPNOTSUPP) {
errorCode = ICameraService.ERROR_DEPRECATED_HAL;
errorMsg = "Deprecated camera HAL does not support this";
} else if (errorFlag == INVALID_OPERATION) {
errorCode = ICameraService.ERROR_INVALID_OPERATION;
errorMsg = "Illegal state encountered in camera service.";
} else {
errorCode = ICameraService.ERROR_INVALID_OPERATION;
errorMsg = "Unknown camera device error " + errorFlag;
}
throw new ServiceSpecificException(errorCode, errorMsg);
}
private LegacyExceptionUtils() {
throw new AssertionError();
}

View File

@@ -16,7 +16,7 @@
package android.hardware.camera2.legacy;
import android.hardware.camera2.CaptureRequest;
import android.hardware.camera2.utils.LongParcelable;
import android.hardware.camera2.utils.SubmitInfo;
import android.util.Log;
import android.util.Pair;
@@ -111,31 +111,29 @@ public class RequestQueue {
*
* @param requests the burst of requests to add to the queue.
* @param repeating true if the burst is repeating.
* @param frameNumber an output argument that contains either the frame number of the last frame
* that will be returned for this request, or the frame number of the last
* frame that will be returned for the current repeating request if this
* burst is set to be repeating.
* @return the request id.
* @return the submission info, including the new request id, and the last frame number, which
* contains either the frame number of the last frame that will be returned for this request,
* or the frame number of the last frame that will be returned for the current repeating
* request if this burst is set to be repeating.
*/
public synchronized int submit(List<CaptureRequest> requests, boolean repeating,
/*out*/LongParcelable frameNumber) {
public synchronized SubmitInfo submit(CaptureRequest[] requests, boolean repeating) {
int requestId = mCurrentRequestId++;
BurstHolder burst = new BurstHolder(requestId, repeating, requests, mJpegSurfaceIds);
long ret = INVALID_FRAME;
long lastFrame = INVALID_FRAME;
if (burst.isRepeating()) {
Log.i(TAG, "Repeating capture request set.");
if (mRepeatingRequest != null) {
ret = (mCurrentRepeatingFrameNumber == INVALID_FRAME) ? INVALID_FRAME :
lastFrame = (mCurrentRepeatingFrameNumber == INVALID_FRAME) ? INVALID_FRAME :
mCurrentRepeatingFrameNumber - 1;
}
mCurrentRepeatingFrameNumber = INVALID_FRAME;
mRepeatingRequest = burst;
} else {
mRequestQueue.offer(burst);
ret = calculateLastFrame(burst.getRequestId());
lastFrame = calculateLastFrame(burst.getRequestId());
}
frameNumber.setNumber(ret);
return requestId;
SubmitInfo info = new SubmitInfo(requestId, lastFrame);
return info;
}
private long calculateLastFrame(int requestId) {

View File

@@ -21,7 +21,7 @@ import android.hardware.Camera;
import android.hardware.camera2.CameraCharacteristics;
import android.hardware.camera2.CaptureRequest;
import android.hardware.camera2.impl.CameraDeviceImpl;
import android.hardware.camera2.utils.LongParcelable;
import android.hardware.camera2.utils.SubmitInfo;
import android.hardware.camera2.utils.SizeAreaComparator;
import android.hardware.camera2.impl.CameraMetadataNative;
import android.os.ConditionVariable;
@@ -1008,21 +1008,19 @@ public class RequestThreadManager {
*
* @param requests the burst of requests to add to the queue.
* @param repeating true if the burst is repeating.
* @param frameNumber an output argument that contains either the frame number of the last frame
* that will be returned for this request, or the frame number of the last
* frame that will be returned for the current repeating request if this
* burst is set to be repeating.
* @return the request id.
* @return the submission info, including the new request id, and the last frame number, which
* contains either the frame number of the last frame that will be returned for this request,
* or the frame number of the last frame that will be returned for the current repeating
* request if this burst is set to be repeating.
*/
public int submitCaptureRequests(List<CaptureRequest> requests, boolean repeating,
/*out*/LongParcelable frameNumber) {
public SubmitInfo submitCaptureRequests(CaptureRequest[] requests, boolean repeating) {
Handler handler = mRequestThread.waitAndGetHandler();
int ret;
SubmitInfo info;
synchronized (mIdleLock) {
ret = mRequestQueue.submit(requests, repeating, frameNumber);
info = mRequestQueue.submit(requests, repeating);
handler.sendEmptyMessage(MSG_SUBMIT_CAPTURE_REQUEST);
}
return ret;
return info;
}
/**

View File

@@ -1,20 +0,0 @@
/*
* Copyright (C) 2015 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.params;
/** @hide */
parcelable OutputConfiguration;

View File

@@ -21,11 +21,11 @@ import android.annotation.SystemApi;
import android.hardware.camera2.CameraDevice;
import android.hardware.camera2.utils.HashCodeHelpers;
import android.hardware.camera2.utils.SurfaceUtils;
import android.os.Parcel;
import android.os.Parcelable;
import android.util.Log;
import android.util.Size;
import android.view.Surface;
import android.os.Parcel;
import android.os.Parcelable;
import static com.android.internal.util.Preconditions.*;

View File

@@ -0,0 +1,67 @@
/*
* Copyright (C) 2016 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.params;
import android.os.Parcel;
import android.os.Parcelable;
import android.util.Log;
/**
* A class for describing the vendor tags declared by a camera HAL module.
* Generally only used by the native side of
* android.hardware.camera2.impl.CameraMetadataNative
*
* @hide
*/
public final class VendorTagDescriptor implements Parcelable {
private VendorTagDescriptor(Parcel source) {
}
public static final Parcelable.Creator<VendorTagDescriptor> CREATOR =
new Parcelable.Creator<VendorTagDescriptor>() {
@Override
public VendorTagDescriptor createFromParcel(Parcel source) {
try {
VendorTagDescriptor vendorDescriptor = new VendorTagDescriptor(source);
return vendorDescriptor;
} catch (Exception e) {
Log.e(TAG, "Exception creating VendorTagDescriptor from parcel", e);
return null;
}
}
@Override
public VendorTagDescriptor[] newArray(int size) {
return new VendorTagDescriptor[size];
}
};
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
if (dest == null) {
throw new IllegalArgumentException("dest must not be null");
}
}
private static final String TAG = "VendorTagDescriptor";
}

View File

@@ -1,20 +0,0 @@
/*
* Copyright (C) 2013 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.utils;
/** @hide */
parcelable BinderHolder;

View File

@@ -1,74 +0,0 @@
/*
* Copyright (C) 2013 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.utils;
import android.os.Parcel;
import android.os.Parcelable;
import android.os.IBinder;
/**
* @hide
*/
public class BinderHolder implements Parcelable {
private IBinder mBinder = null;
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeStrongBinder(mBinder);
}
public void readFromParcel(Parcel src) {
mBinder = src.readStrongBinder();
}
public static final Parcelable.Creator<BinderHolder> CREATOR =
new Parcelable.Creator<BinderHolder>() {
@Override
public BinderHolder createFromParcel(Parcel in) {
return new BinderHolder(in);
}
@Override
public BinderHolder[] newArray(int size) {
return new BinderHolder[size];
}
};
public IBinder getBinder() {
return mBinder;
}
public void setBinder(IBinder binder) {
mBinder = binder;
}
public BinderHolder() {}
public BinderHolder(IBinder binder) {
mBinder = binder;
}
private BinderHolder(Parcel in) {
mBinder = in.readStrongBinder();
}
}

View File

@@ -1,162 +0,0 @@
/*
* Copyright (C) 2013 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.utils;
import static android.hardware.camera2.CameraAccessException.CAMERA_DISABLED;
import static android.hardware.camera2.CameraAccessException.CAMERA_DISCONNECTED;
import static android.hardware.camera2.CameraAccessException.CAMERA_IN_USE;
import static android.hardware.camera2.CameraAccessException.CAMERA_ERROR;
import static android.hardware.camera2.CameraAccessException.MAX_CAMERAS_IN_USE;
import static android.hardware.camera2.CameraAccessException.CAMERA_DEPRECATED_HAL;
import static android.system.OsConstants.*;
import android.os.DeadObjectException;
import android.os.RemoteException;
import java.lang.reflect.Method;
/**
* Translate camera device status_t return values into exceptions.
*
* @see android.hardware.camera2.utils.CameraBinderDecorator#newInstance
* @hide
*/
public class CameraBinderDecorator {
public static final int NO_ERROR = 0;
public static final int PERMISSION_DENIED = -EPERM;
public static final int ALREADY_EXISTS = -EEXIST;
public static final int BAD_VALUE = -EINVAL;
public static final int DEAD_OBJECT = -ENOSYS;
public static final int INVALID_OPERATION = -EPIPE;
public static final int TIMED_OUT = -ETIMEDOUT;
/**
* TODO: add as error codes in Errors.h
* - POLICY_PROHIBITS
* - RESOURCE_BUSY
* - NO_SUCH_DEVICE
* - NOT_SUPPORTED
* - TOO_MANY_USERS
*/
static class CameraBinderDecoratorListener implements Decorator.DecoratorListener {
@Override
public void onBeforeInvocation(Method m, Object[] args) {
}
@Override
public void onAfterInvocation(Method m, Object[] args, Object result) {
// int return type => status_t => convert to exception
if (m.getReturnType() == Integer.TYPE) {
int returnValue = (Integer) result;
throwOnError(returnValue);
}
}
@Override
public boolean onCatchException(Method m, Object[] args, Throwable t) {
if (t instanceof DeadObjectException) {
throw new CameraRuntimeException(CAMERA_DISCONNECTED,
"Process hosting the camera service has died unexpectedly",
t);
} else if (t instanceof RemoteException) {
throw new UnsupportedOperationException("An unknown RemoteException was thrown" +
" which should never happen.", t);
}
return false;
}
@Override
public void onFinally(Method m, Object[] args) {
}
}
/**
* Throw error codes returned by the camera service as exceptions.
*
* @param errorFlag error to throw as an exception.
*/
public static void throwOnError(int errorFlag) {
if (errorFlag == NO_ERROR) {
return;
} else if (errorFlag == PERMISSION_DENIED) {
throw new SecurityException("Lacking privileges to access camera service");
} else if (errorFlag == ALREADY_EXISTS) {
// This should be handled at the call site. Typically this isn't bad,
// just means we tried to do an operation that already completed.
return;
} else if (errorFlag == BAD_VALUE) {
throw new IllegalArgumentException("Bad argument passed to camera service");
} else if (errorFlag == DEAD_OBJECT) {
throw new CameraRuntimeException(CAMERA_DISCONNECTED);
} else if (errorFlag == TIMED_OUT) {
throw new CameraRuntimeException(CAMERA_ERROR,
"Operation timed out in camera service");
} else if (errorFlag == -EACCES) {
throw new CameraRuntimeException(CAMERA_DISABLED);
} else if (errorFlag == -EBUSY) {
throw new CameraRuntimeException(CAMERA_IN_USE);
} else if (errorFlag == -EUSERS) {
throw new CameraRuntimeException(MAX_CAMERAS_IN_USE);
} else if (errorFlag == -ENODEV) {
throw new CameraRuntimeException(CAMERA_DISCONNECTED);
} else if (errorFlag == -EOPNOTSUPP) {
throw new CameraRuntimeException(CAMERA_DEPRECATED_HAL);
} else if (errorFlag == INVALID_OPERATION) {
throw new CameraRuntimeException(CAMERA_ERROR,
"Illegal state encountered in camera service.");
}
/**
* Trap the rest of the negative return values. If we have known
* error codes i.e. ALREADY_EXISTS that aren't really runtime
* errors, then add them to the top switch statement
*/
if (errorFlag < 0) {
throw new CameraRuntimeException(CAMERA_ERROR,
String.format("Unknown camera device error %d", errorFlag));
}
}
/**
* <p>
* Wraps the type T with a proxy that will check 'status_t' return codes
* from the native side of the camera service, and throw Java exceptions
* automatically based on the code.
* </p>
* <p>
* In addition it also rewrites binder's RemoteException into either a
* CameraAccessException or an UnsupportedOperationException.
* </p>
* <p>
* As a result of calling any method on the proxy, RemoteException is
* guaranteed never to be thrown.
* </p>
*
* @param obj object that will serve as the target for all method calls
* @param <T> the type of the element you want to wrap. This must be an interface.
* @return a proxy that will intercept all invocations to obj
*/
public static <T> T newInstance(T obj) {
return Decorator.<T> newInstance(obj, new CameraBinderDecoratorListener());
}
}

View File

@@ -1,63 +0,0 @@
package android.hardware.camera2.utils;
import android.hardware.camera2.CameraAccessException;
/**
* @hide
*/
public class CameraRuntimeException extends RuntimeException {
private final int mReason;
private String mMessage;
private Throwable mCause;
public final int getReason() {
return mReason;
}
public CameraRuntimeException(int problem) {
super();
mReason = problem;
}
public CameraRuntimeException(int problem, String message) {
super(message);
mReason = problem;
mMessage = message;
}
public CameraRuntimeException(int problem, String message, Throwable cause) {
super(message, cause);
mReason = problem;
mMessage = message;
mCause = cause;
}
public CameraRuntimeException(int problem, Throwable cause) {
super(cause);
mReason = problem;
mCause = cause;
}
/**
* Recreate this exception as the CameraAccessException equivalent.
* @return CameraAccessException
*/
public CameraAccessException asChecked() {
CameraAccessException e;
if (mMessage != null && mCause != null) {
e = new CameraAccessException(mReason, mMessage, mCause);
} else if (mMessage != null) {
e = new CameraAccessException(mReason, mMessage);
} else if (mCause != null) {
e = new CameraAccessException(mReason, mCause);
} else {
e = new CameraAccessException(mReason);
}
// throw and catch, so java has a chance to fill out the stack trace
e.setStackTrace(this.getStackTrace());
return e;
}
}

View File

@@ -1,70 +0,0 @@
/*
* 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.utils;
import android.os.DeadObjectException;
import android.os.RemoteException;
import android.util.Log;
import java.lang.reflect.Method;
/**
* Translate camera service status_t return values into exceptions.
*
* @see android.hardware.camera2.utils.CameraBinderDecorator#newInstance
* @hide
*/
public class CameraServiceBinderDecorator extends CameraBinderDecorator {
private static final String TAG = "CameraServiceBinderDecorator";
static class CameraServiceBinderDecoratorListener
extends CameraBinderDecorator.CameraBinderDecoratorListener {
// Pass through remote exceptions, unlike CameraBinderDecorator
@Override
public boolean onCatchException(Method m, Object[] args, Throwable t) {
if (t instanceof DeadObjectException) {
// Can sometimes happen (camera service died)
// Pass on silently
} else if (t instanceof RemoteException) {
// Some other kind of remote exception - this is not normal, so let's at least
// note it before moving on
Log.e(TAG, "Unexpected RemoteException from camera service call.", t);
}
// All other exceptions also get sent onward
return false;
}
}
/**
* <p>
* Wraps the type T with a proxy that will check 'status_t' return codes
* from the native side of the camera service, and throw Java exceptions
* automatically based on the code.
* </p>
*
* @param obj object that will serve as the target for all method calls
* @param <T> the type of the element you want to wrap. This must be an interface.
* @return a proxy that will intercept all invocations to obj
*/
public static <T> T newInstance(T obj) {
return Decorator.<T> newInstance(obj, new CameraServiceBinderDecoratorListener());
}
}

View File

@@ -1,92 +0,0 @@
package android.hardware.camera2.utils;
import java.lang.reflect.*;
/**
* This is an implementation of the 'decorator' design pattern using Java's proxy mechanism.
*
* @see android.hardware.camera2.utils.Decorator#newInstance
*
* @hide
*/
public class Decorator<T> implements InvocationHandler {
public interface DecoratorListener {
/**
* This method is called before the target method is invoked
* @param args arguments to target method
* @param m Method being called
*/
void onBeforeInvocation(Method m, Object[] args);
/**
* This function is called after the target method is invoked
* if there were no uncaught exceptions
* @param args arguments to target method
* @param m Method being called
* @param result return value of target method
*/
void onAfterInvocation(Method m, Object[] args, Object result);
/**
* This method is called only if there was an exception thrown by the target method
* during its invocation.
*
* @param args arguments to target method
* @param m Method being called
* @param t Throwable that was thrown
* @return false to rethrow exception, true if the exception was handled
*/
boolean onCatchException(Method m, Object[] args, Throwable t);
/**
* This is called after the target method is invoked, regardless of whether or not
* there were any exceptions.
* @param args arguments to target method
* @param m Method being called
*/
void onFinally(Method m, Object[] args);
}
private final T mObject;
private final DecoratorListener mListener;
/**
* Create a decorator wrapping the specified object's method calls.
*
* @param obj the object whose method calls you want to intercept
* @param listener the decorator handler for intercepted method calls
* @param <T> the type of the element you want to wrap. This must be an interface.
* @return a wrapped interface-compatible T
*/
@SuppressWarnings("unchecked")
public static<T> T newInstance(T obj, DecoratorListener listener) {
return (T)java.lang.reflect.Proxy.newProxyInstance(
obj.getClass().getClassLoader(),
obj.getClass().getInterfaces(),
new Decorator<T>(obj, listener));
}
private Decorator(T obj, DecoratorListener listener) {
this.mObject = obj;
this.mListener = listener;
}
@Override
public Object invoke(Object proxy, Method m, Object[] args)
throws Throwable
{
Object result = null;
try {
mListener.onBeforeInvocation(m, args);
result = m.invoke(mObject, args);
mListener.onAfterInvocation(m, args, result);
} catch (InvocationTargetException e) {
Throwable t = e.getTargetException();
if (!mListener.onCatchException(m, args, t)) {
throw t;
}
} finally {
mListener.onFinally(m, args);
}
return result;
}
}

View File

@@ -1,20 +0,0 @@
/*
* 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.utils;
/** @hide */
parcelable LongParcelable;

View File

@@ -0,0 +1,106 @@
/*
* Copyright (C) 2015 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.utils;
import android.os.Parcel;
import android.os.Parcelable;
import android.hardware.camera2.ICameraDeviceUser;
/**
* The status information returned for a successful capture request submission.
*
* Includes the request ID for the newly submitted capture request, and the
* last frame number of either the previous repeating request (for repeating
* requests), or of the request(s) just submitted (for single-shot capture).
*
* @hide
*/
public class SubmitInfo implements Parcelable {
private int mRequestId;
private long mLastFrameNumber;
public SubmitInfo() {
mRequestId = -1;
mLastFrameNumber = ICameraDeviceUser.NO_IN_FLIGHT_REPEATING_FRAMES;
}
public SubmitInfo(int requestId, long lastFrameNumber) {
mRequestId = requestId;
mLastFrameNumber = lastFrameNumber;
}
public static final Parcelable.Creator<SubmitInfo> CREATOR =
new Parcelable.Creator<SubmitInfo>() {
@Override
public SubmitInfo createFromParcel(Parcel in) {
return new SubmitInfo(in);
}
@Override
public SubmitInfo[] newArray(int size) {
return new SubmitInfo[size];
}
};
private SubmitInfo(Parcel in) {
readFromParcel(in);
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(mRequestId);
dest.writeLong(mLastFrameNumber);
}
public void readFromParcel(Parcel in) {
mRequestId = in.readInt();
mLastFrameNumber = in.readLong();
}
/**
* Return the request ID for the submitted capture request/burst.
*
* This is used to track the completion status of the requested captures,
* and to cancel repeating requests.
*/
public int getRequestId() {
return mRequestId;
}
/**
* Return the last frame number for the submitted capture request/burst.
*
* For a repeating request, this is the last frame number of the _prior_
* repeating request, to indicate when to fire the sequence completion callback
* for the prior repeating request.
*
* For a single-shot capture, this is the last frame number of _this_
* burst, to indicate when to fire the sequence completion callback for the request itself.
*
* For a repeating request, may be NO_IN_FLIGHT_REPEATING_FRAMES, if no
* instances of a prior repeating request were actually issued to the camera device.
*/
public long getLastFrameNumber() {
return mLastFrameNumber;
}
}

View File

@@ -20,20 +20,23 @@ package android.os;
*
* <p>This exception includes an error code specific to the throwing
* service. This is mostly used by system services to indicate
* domain specific error conditions.
* domain specific error conditions.</p>
*
* <p>Since these exceptions are designed to be passed through Binder
* interfaces, and to be generated by native-code Binder services,
* they do not support exception chaining.</p>
*
* @hide
*/
public class ServiceSpecificException extends RuntimeException {
public final int errorCode;
ServiceSpecificException(int errorCode, String message) {
public ServiceSpecificException(int errorCode, String message) {
super(message);
this.errorCode = errorCode;
}
ServiceSpecificException(int errorCode) {
public ServiceSpecificException(int errorCode) {
this.errorCode = errorCode;
}
}

View File

@@ -1,20 +0,0 @@
/* //device/java/android/android/view/Surface.aidl
**
** Copyright 2007, 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.view;
parcelable Surface;

View File

@@ -190,7 +190,6 @@ LOCAL_C_INCLUDES += \
$(call include-path-for, bluedroid) \
$(call include-path-for, libhardware)/hardware \
$(call include-path-for, libhardware_legacy)/hardware_legacy \
$(TOP)/frameworks/av/include \
$(TOP)/frameworks/base/media/jni \
$(TOP)/system/core/base/include \
$(TOP)/system/core/include \

View File

@@ -33,9 +33,9 @@
#include "core_jni_helpers.h"
#include "android_runtime/android_hardware_camera2_CameraMetadata.h"
#include <android/hardware/ICameraService.h>
#include <binder/IServiceManager.h>
#include <camera/CameraMetadata.h>
#include <camera/ICameraService.h>
#include <camera/VendorTagDescriptor.h>
#include <nativehelper/ScopedUtfChars.h>
#include <nativehelper/ScopedPrimitiveArray.h>
@@ -906,32 +906,36 @@ static jint CameraMetadata_getTypeFromTag(JNIEnv *env, jobject thiz, jint tag) {
static jint CameraMetadata_setupGlobalVendorTagDescriptor(JNIEnv *env, jobject thiz) {
const String16 NAME("media.camera");
sp<ICameraService> cameraService;
sp<hardware::ICameraService> cameraService;
status_t err = getService(NAME, /*out*/&cameraService);
if (err != OK) {
ALOGE("%s: Failed to get camera service, received error %s (%d)", __FUNCTION__,
strerror(-err), err);
return err;
return hardware::ICameraService::ERROR_DISCONNECTED;
}
sp<VendorTagDescriptor> desc;
err = cameraService->getCameraVendorTagDescriptor(/*out*/desc);
sp<VendorTagDescriptor> desc = new VendorTagDescriptor();
binder::Status res = cameraService->getCameraVendorTagDescriptor(/*out*/desc.get());
if (err == -EOPNOTSUPP) {
if (res.serviceSpecificErrorCode() == hardware::ICameraService::ERROR_DEPRECATED_HAL) {
ALOGW("%s: Camera HAL too old; does not support vendor tags", __FUNCTION__);
VendorTagDescriptor::clearGlobalVendorTagDescriptor();
return OK;
} else if (err != OK) {
ALOGE("%s: Failed to setup vendor tag descriptors, received error %s (%d)",
__FUNCTION__, strerror(-err), err);
return err;
} else if (!res.isOk()) {
ALOGE("%s: Failed to setup vendor tag descriptors: %s: %s",
__FUNCTION__, res.serviceSpecificErrorCode(),
res.toString8().string());
return res.serviceSpecificErrorCode();
}
err = VendorTagDescriptor::setAsGlobalVendorTagDescriptor(desc);
return err;
if (err != OK) {
return hardware::ICameraService::ERROR_INVALID_OPERATION;
}
return OK;
}
} // extern "C"

View File

@@ -411,22 +411,27 @@ static jlong nativeReadFromParcel(JNIEnv* env, jclass clazz,
return 0;
}
android::view::Surface surfaceShim;
// Calling code in Surface.java has already read the name of the Surface
// from the Parcel
surfaceShim.readFromParcel(parcel, /*nameAlreadyRead*/true);
sp<Surface> self(reinterpret_cast<Surface *>(nativeObject));
sp<IBinder> binder(parcel->readStrongBinder());
// update the Surface only if the underlying IGraphicBufferProducer
// has changed.
if (self != NULL
&& (IInterface::asBinder(self->getIGraphicBufferProducer()) == binder)) {
if (self != nullptr
&& (IInterface::asBinder(self->getIGraphicBufferProducer()) ==
IInterface::asBinder(surfaceShim.graphicBufferProducer))) {
// same IGraphicBufferProducer, return ourselves
return jlong(self.get());
}
sp<Surface> sur;
sp<IGraphicBufferProducer> gbp(interface_cast<IGraphicBufferProducer>(binder));
if (gbp != NULL) {
if (surfaceShim.graphicBufferProducer != nullptr) {
// we have a new IGraphicBufferProducer, create a new Surface for it
sur = new Surface(gbp, true);
sur = new Surface(surfaceShim.graphicBufferProducer, true);
// and keep a reference before passing to java
sur->incStrong(&sRefBaseOwner);
}
@@ -447,7 +452,13 @@ static void nativeWriteToParcel(JNIEnv* env, jclass clazz,
return;
}
sp<Surface> self(reinterpret_cast<Surface *>(nativeObject));
parcel->writeStrongBinder( self != 0 ? IInterface::asBinder(self->getIGraphicBufferProducer()) : NULL);
android::view::Surface surfaceShim;
if (self != nullptr) {
surfaceShim.graphicBufferProducer = self->getIGraphicBufferProducer();
}
// Calling code in Surface.java has already written the name of the Surface
// to the Parcel
surfaceShim.writeToParcel(parcel, /*nameAlreadyWritten*/true);
}
static jint nativeGetWidth(JNIEnv* env, jclass clazz, jlong nativeObject) {

View File

@@ -64,7 +64,6 @@ LOCAL_C_INCLUDES += \
frameworks/av/media/mtp \
frameworks/native/include/media/openmax \
$(call include-path-for, libhardware)/hardware \
system/media/camera/include \
$(PV_INCLUDES) \
$(JNI_H_INCLUDE)

View File

@@ -26,7 +26,6 @@
#include <utils/Log.h>
#include <gui/Surface.h>
#include <camera/ICameraService.h>
#include <camera/Camera.h>
#include <media/mediarecorder.h>
#include <media/stagefright/PersistentSurface.h>

View File

@@ -60,10 +60,7 @@ public class MediaFrameworkUnitTestRunner extends InstrumentationTestRunner {
}
private void addCameraUnitTests(TestSuite suite) {
suite.addTestSuite(CameraUtilsDecoratorTest.class);
suite.addTestSuite(CameraUtilsRuntimeExceptionTest.class);
suite.addTestSuite(CameraUtilsUncheckedThrowTest.class);
suite.addTestSuite(CameraUtilsBinderDecoratorTest.class);
suite.addTestSuite(CameraUtilsTypeReferenceTest.class);
suite.addTestSuite(CameraMetadataTest.class);
}

View File

@@ -19,16 +19,16 @@ package com.android.mediaframeworktest.integration;
import android.hardware.CameraInfo;
import android.hardware.ICamera;
import android.hardware.ICameraClient;
import android.hardware.ICameraService;
import android.hardware.ICameraServiceListener;
import android.hardware.camera2.ICameraDeviceCallbacks;
import android.hardware.camera2.ICameraDeviceUser;
import android.hardware.camera2.impl.CameraMetadataNative;
import android.hardware.camera2.impl.CaptureResultExtras;
import android.hardware.camera2.utils.BinderHolder;
import android.hardware.camera2.utils.CameraBinderDecorator;
import android.os.Binder;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.ServiceSpecificException;
import android.test.AndroidTestCase;
import android.test.suitebuilder.annotation.SmallTest;
import android.util.Log;
@@ -84,14 +84,7 @@ public class CameraBinderTest extends AndroidTestCase {
public void testCameraInfo() throws Exception {
for (int cameraId = 0; cameraId < mUtils.getGuessedNumCameras(); ++cameraId) {
CameraInfo info = new CameraInfo();
info.info.facing = -1;
info.info.orientation = -1;
assertTrue(
"Camera service returned info for camera " + cameraId,
mUtils.getCameraService().getCameraInfo(cameraId, info) ==
CameraBinderTestUtils.NO_ERROR);
CameraInfo info = mUtils.getCameraService().getCameraInfo(cameraId);
assertTrue("Facing was not set for camera " + cameraId, info.info.facing != -1);
assertTrue("Orientation was not set for camera " + cameraId,
info.info.orientation != -1);
@@ -105,20 +98,17 @@ public class CameraBinderTest extends AndroidTestCase {
public void testGetLegacyParameters() throws Exception {
for (int cameraId = 0; cameraId < mUtils.getGuessedNumCameras(); ++cameraId) {
String[] parameters = new String[1];
assertEquals("Camera service returned parameters for camera " + cameraId,
CameraBinderTestUtils.NO_ERROR,
mUtils.getCameraService().getLegacyParameters(cameraId, /*out*/parameters));
assertNotNull(parameters[0]);
String parameters = mUtils.getCameraService().getLegacyParameters(cameraId);
assertNotNull(parameters);
assertTrue("Parameters should have at least one character in it",
parameters[0].length() > 0);
parameters.length() > 0);
int end = parameters[0].length();
int end = parameters.length();
if (end > MAX_PARAMETERS_LENGTH) {
end = MAX_PARAMETERS_LENGTH;
}
Log.v(TAG, "Camera " + cameraId + " parameters: " + parameters[0].substring(0, end));
Log.v(TAG, "Camera " + cameraId + " parameters: " + parameters.substring(0, end));
}
}
@@ -127,14 +117,8 @@ public class CameraBinderTest extends AndroidTestCase {
public void testSupportsCamera2Api() throws Exception {
for (int cameraId = 0; cameraId < mUtils.getGuessedNumCameras(); ++cameraId) {
int res = mUtils.getCameraService().supportsCameraApi(cameraId, API_VERSION_2);
boolean supports = mUtils.getCameraService().supportsCameraApi(cameraId, API_VERSION_2);
if (res != CameraBinderTestUtils.NO_ERROR && res != -android.system.OsConstants.EOPNOTSUPP) {
fail("Camera service returned bad value when queried if it supports camera2 api: "
+ res + " for camera ID " + cameraId);
}
boolean supports = res == CameraBinderTestUtils.NO_ERROR;
Log.v(TAG, "Camera " + cameraId + " supports api2: " + supports);
}
}
@@ -144,10 +128,10 @@ public class CameraBinderTest extends AndroidTestCase {
public void testSupportsCamera1Api() throws Exception {
for (int cameraId = 0; cameraId < mUtils.getGuessedNumCameras(); ++cameraId) {
int res = mUtils.getCameraService().supportsCameraApi(cameraId, API_VERSION_1);
assertEquals(
"Camera service returned bad value when queried if it supports camera1 api: "
+ res + " for camera ID " + cameraId, CameraBinderTestUtils.NO_ERROR, res);
boolean supports = mUtils.getCameraService().supportsCameraApi(cameraId, API_VERSION_1);
assertTrue(
"Camera service returned false when queried if it supports camera1 api " +
" for camera ID " + cameraId, supports);
}
}
@@ -169,11 +153,10 @@ public class CameraBinderTest extends AndroidTestCase {
String clientPackageName = getContext().getPackageName();
BinderHolder holder = new BinderHolder();
CameraBinderDecorator.newInstance(mUtils.getCameraService())
ICamera cameraUser = mUtils.getCameraService()
.connect(dummyCallbacks, cameraId, clientPackageName,
CameraBinderTestUtils.USE_CALLING_UID, holder);
ICamera cameraUser = ICamera.Stub.asInterface(holder.getBinder());
ICameraService.USE_CALLING_UID,
ICameraService.USE_CALLING_PID);
assertNotNull(String.format("Camera %s was null", cameraId), cameraUser);
Log.v(TAG, String.format("Camera %s connected", cameraId));
@@ -191,14 +174,11 @@ public class CameraBinderTest extends AndroidTestCase {
String clientPackageName = getContext().getPackageName();
BinderHolder holder = new BinderHolder();
try {
CameraBinderDecorator.newInstance(mUtils.getCameraService())
cameraUser = mUtils.getCameraService()
.connectLegacy(dummyCallbacks, cameraId, CAMERA_HAL_API_VERSION_1_0,
clientPackageName,
CameraBinderTestUtils.USE_CALLING_UID, holder);
cameraUser = ICamera.Stub.asInterface(holder.getBinder());
clientPackageName,
ICameraService.USE_CALLING_UID);
assertNotNull(String.format("Camera %s was null", cameraId), cameraUser);
Log.v(TAG, String.format("Camera %s connected as HAL1 legacy device", cameraId));
@@ -284,11 +264,11 @@ public class CameraBinderTest extends AndroidTestCase {
String clientPackageName = getContext().getPackageName();
BinderHolder holder = new BinderHolder();
CameraBinderDecorator.newInstance(mUtils.getCameraService())
.connectDevice(dummyCallbacks, cameraId,
clientPackageName, CameraBinderTestUtils.USE_CALLING_UID, holder);
ICameraDeviceUser cameraUser = ICameraDeviceUser.Stub.asInterface(holder.getBinder());
ICameraDeviceUser cameraUser =
mUtils.getCameraService().connectDevice(
dummyCallbacks, cameraId,
clientPackageName,
ICameraService.USE_CALLING_UID);
assertNotNull(String.format("Camera %s was null", cameraId), cameraUser);
Log.v(TAG, String.format("Camera %s connected", cameraId));
@@ -323,27 +303,33 @@ public class CameraBinderTest extends AndroidTestCase {
ICameraServiceListener listener = new DummyCameraServiceListener();
assertTrue(
"Listener was removed before added",
mUtils.getCameraService().removeListener(listener) ==
CameraBinderTestUtils.BAD_VALUE);
try {
mUtils.getCameraService().removeListener(listener);
fail("Listener was removed before added");
} catch (ServiceSpecificException e) {
assertEquals("Listener was removed before added",
e.errorCode, ICameraService.ERROR_ILLEGAL_ARGUMENT);
}
assertTrue("Listener was not added",
mUtils.getCameraService().addListener(listener) ==
CameraBinderTestUtils.NO_ERROR);
assertTrue(
"Listener was wrongly added again",
mUtils.getCameraService().addListener(listener) ==
CameraBinderTestUtils.ALREADY_EXISTS);
mUtils.getCameraService().addListener(listener);
assertTrue(
"Listener was not removed",
mUtils.getCameraService().removeListener(listener) ==
CameraBinderTestUtils.NO_ERROR);
assertTrue(
"Listener was wrongly removed again",
mUtils.getCameraService().removeListener(listener) ==
CameraBinderTestUtils.BAD_VALUE);
try {
mUtils.getCameraService().addListener(listener);
fail("Listener was wrongly added again");
} catch (ServiceSpecificException e) {
assertEquals("Listener was wrongly added again",
e.errorCode, ICameraService.ERROR_ALREADY_EXISTS);
}
mUtils.getCameraService().removeListener(listener);
try {
mUtils.getCameraService().removeListener(listener);
fail("Listener was wrongly removed twice");
} catch (ServiceSpecificException e) {
assertEquals("Listener was wrongly removed twice",
e.errorCode, ICameraService.ERROR_ILLEGAL_ARGUMENT);
}
}
}
}

View File

@@ -18,10 +18,6 @@ public class CameraBinderTestUtils {
static final String CAMERA_SERVICE_BINDER_NAME = "media.camera";
protected static final int USE_CALLING_UID = -1;
protected static final int BAD_VALUE = -EINVAL;
protected static final int INVALID_OPERATION = -ENOSYS;
protected static final int ALREADY_EXISTS = -EEXIST;
public static final int NO_ERROR = 0;
private final Context mContext;

View File

@@ -18,6 +18,7 @@ package com.android.mediaframeworktest.integration;
import android.graphics.ImageFormat;
import android.graphics.SurfaceTexture;
import android.hardware.ICameraService;
import android.hardware.camera2.CameraMetadata;
import android.hardware.camera2.CameraCaptureSession;
import android.hardware.camera2.CameraCharacteristics;
@@ -27,12 +28,13 @@ import android.hardware.camera2.ICameraDeviceUser;
import android.hardware.camera2.impl.CameraMetadataNative;
import android.hardware.camera2.impl.CaptureResultExtras;
import android.hardware.camera2.params.OutputConfiguration;
import android.hardware.camera2.utils.BinderHolder;
import android.hardware.camera2.utils.SubmitInfo;
import android.media.Image;
import android.media.ImageReader;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.RemoteException;
import android.os.ServiceSpecificException;
import android.os.SystemClock;
import android.test.AndroidTestCase;
import android.test.suitebuilder.annotation.SmallTest;
@@ -164,11 +166,10 @@ public class CameraDeviceBinderTest extends AndroidTestCase {
}
private CaptureRequest.Builder createDefaultBuilder(boolean needStream) throws Exception {
CameraMetadataNative metadata = new CameraMetadataNative();
CameraMetadataNative metadata = null;
assertTrue(metadata.isEmpty());
int status = mCameraUser.createDefaultRequest(TEMPLATE_PREVIEW, /* out */metadata);
assertEquals(CameraBinderTestUtils.NO_ERROR, status);
metadata = mCameraUser.createDefaultRequest(TEMPLATE_PREVIEW);
assertFalse(metadata.isEmpty());
CaptureRequest.Builder request = new CaptureRequest.Builder(metadata, /*reprocess*/false,
@@ -183,12 +184,13 @@ public class CameraDeviceBinderTest extends AndroidTestCase {
return request;
}
private int submitCameraRequest(CaptureRequest request, boolean streaming) throws Exception {
int requestId = mCameraUser.submitRequest(request, streaming, null);
private SubmitInfo submitCameraRequest(CaptureRequest request, boolean streaming) throws Exception {
SubmitInfo requestInfo = mCameraUser.submitRequest(request, streaming);
assertTrue(
"Request IDs should be non-negative (expected: >= 0, actual: " + requestId + ")",
requestId >= 0);
return requestId;
"Request IDs should be non-negative (expected: >= 0, actual: " +
requestInfo.getRequestId() + ")",
requestInfo.getRequestId() >= 0);
return requestInfo;
}
@Override
@@ -214,10 +216,8 @@ public class CameraDeviceBinderTest extends AndroidTestCase {
mMockCb = spy(dummyCallbacks);
BinderHolder holder = new BinderHolder();
mUtils.getCameraService().connectDevice(mMockCb, mCameraId,
clientPackageName, CameraBinderTestUtils.USE_CALLING_UID, holder);
mCameraUser = ICameraDeviceUser.Stub.asInterface(holder.getBinder());
mCameraUser = mUtils.getCameraService().connectDevice(mMockCb, mCameraId,
clientPackageName, ICameraService.USE_CALLING_UID);
assertNotNull(String.format("Camera %s was null", mCameraId), mCameraUser);
mHandlerThread = new HandlerThread(TAG);
mHandlerThread.start();
@@ -238,11 +238,10 @@ public class CameraDeviceBinderTest extends AndroidTestCase {
@SmallTest
public void testCreateDefaultRequest() throws Exception {
CameraMetadataNative metadata = new CameraMetadataNative();
CameraMetadataNative metadata = null;
assertTrue(metadata.isEmpty());
int status = mCameraUser.createDefaultRequest(TEMPLATE_PREVIEW, /* out */metadata);
assertEquals(CameraBinderTestUtils.NO_ERROR, status);
metadata = mCameraUser.createDefaultRequest(TEMPLATE_PREVIEW);
assertFalse(metadata.isEmpty());
}
@@ -252,18 +251,28 @@ public class CameraDeviceBinderTest extends AndroidTestCase {
int streamId = mCameraUser.createStream(mOutputConfiguration);
assertEquals(0, streamId);
assertEquals(CameraBinderTestUtils.ALREADY_EXISTS,
mCameraUser.createStream(mOutputConfiguration));
try {
mCameraUser.createStream(mOutputConfiguration);
fail("Creating same stream twice");
} catch (ServiceSpecificException e) {
assertEquals("Creating same stream twice",
e.errorCode, ICameraService.ERROR_ALREADY_EXISTS);
}
assertEquals(CameraBinderTestUtils.NO_ERROR, mCameraUser.deleteStream(streamId));
mCameraUser.deleteStream(streamId);
}
@SmallTest
public void testDeleteInvalidStream() throws Exception {
assertEquals(CameraBinderTestUtils.BAD_VALUE, mCameraUser.deleteStream(-1));
assertEquals(CameraBinderTestUtils.BAD_VALUE, mCameraUser.deleteStream(0));
assertEquals(CameraBinderTestUtils.BAD_VALUE, mCameraUser.deleteStream(1));
assertEquals(CameraBinderTestUtils.BAD_VALUE, mCameraUser.deleteStream(0xC0FFEE));
int[] badStreams = { -1, 0, 1, 0xC0FFEE };
for (int badStream : badStreams) {
try {
mCameraUser.deleteStream(badStream);
fail("Allowed bad stream delete");
} catch (ServiceSpecificException e) {
assertEquals(e.errorCode, ICameraService.ERROR_ILLEGAL_ARGUMENT);
}
}
}
@SmallTest
@@ -273,8 +282,13 @@ public class CameraDeviceBinderTest extends AndroidTestCase {
int streamId = mCameraUser.createStream(mOutputConfiguration);
assertEquals(0, streamId);
assertEquals(CameraBinderTestUtils.ALREADY_EXISTS,
mCameraUser.createStream(mOutputConfiguration));
try {
mCameraUser.createStream(mOutputConfiguration);
fail("Created same stream twice");
} catch (ServiceSpecificException e) {
assertEquals("Created same stream twice",
ICameraService.ERROR_ALREADY_EXISTS, e.errorCode);
}
// Create second stream with a different surface.
SurfaceTexture surfaceTexture = new SurfaceTexture(/* ignored */0);
@@ -286,8 +300,8 @@ public class CameraDeviceBinderTest extends AndroidTestCase {
assertEquals(1, streamId2);
// Clean up streams
assertEquals(CameraBinderTestUtils.NO_ERROR, mCameraUser.deleteStream(streamId));
assertEquals(CameraBinderTestUtils.NO_ERROR, mCameraUser.deleteStream(streamId2));
mCameraUser.deleteStream(streamId);
mCameraUser.deleteStream(streamId2);
}
@SmallTest
@@ -295,16 +309,25 @@ public class CameraDeviceBinderTest extends AndroidTestCase {
CaptureRequest.Builder builder = createDefaultBuilder(/* needStream */false);
CaptureRequest request1 = builder.build();
int status = mCameraUser.submitRequest(request1, /* streaming */false, null);
assertEquals("Expected submitRequest to return BAD_VALUE " +
"since we had 0 surface targets set.", CameraBinderTestUtils.BAD_VALUE, status);
try {
SubmitInfo requestInfo = mCameraUser.submitRequest(request1, /* streaming */false);
fail("Exception expected");
} catch(ServiceSpecificException e) {
assertEquals("Expected submitRequest to throw ServiceSpecificException with BAD_VALUE " +
"since we had 0 surface targets set.", ICameraService.ERROR_ILLEGAL_ARGUMENT,
e.errorCode);
}
builder.addTarget(mSurface);
CaptureRequest request2 = builder.build();
status = mCameraUser.submitRequest(request2, /* streaming */false, null);
assertEquals("Expected submitRequest to return BAD_VALUE since " +
"the target surface wasn't registered with createStream.",
CameraBinderTestUtils.BAD_VALUE, status);
try {
SubmitInfo requestInfo = mCameraUser.submitRequest(request2, /* streaming */false);
fail("Exception expected");
} catch(ServiceSpecificException e) {
assertEquals("Expected submitRequest to throw ILLEGAL_ARGUMENT " +
"ServiceSpecificException since the target wasn't registered with createStream.",
ICameraService.ERROR_ILLEGAL_ARGUMENT, e.errorCode);
}
}
@SmallTest
@@ -314,9 +337,10 @@ public class CameraDeviceBinderTest extends AndroidTestCase {
CaptureRequest request = builder.build();
// Submit valid request twice.
int requestId1 = submitCameraRequest(request, /* streaming */false);
int requestId2 = submitCameraRequest(request, /* streaming */false);
assertNotSame("Request IDs should be unique for multiple requests", requestId1, requestId2);
SubmitInfo requestInfo1 = submitCameraRequest(request, /* streaming */false);
SubmitInfo requestInfo2 = submitCameraRequest(request, /* streaming */false);
assertNotSame("Request IDs should be unique for multiple requests",
requestInfo1.getRequestId(), requestInfo2.getRequestId());
}
@@ -329,32 +353,35 @@ public class CameraDeviceBinderTest extends AndroidTestCase {
// Submit valid request once (non-streaming), and another time
// (streaming)
int requestId1 = submitCameraRequest(request, /* streaming */false);
SubmitInfo requestInfo1 = submitCameraRequest(request, /* streaming */false);
int requestIdStreaming = submitCameraRequest(request, /* streaming */true);
assertNotSame("Request IDs should be unique for multiple requests", requestId1,
requestIdStreaming);
SubmitInfo requestInfoStreaming = submitCameraRequest(request, /* streaming */true);
assertNotSame("Request IDs should be unique for multiple requests",
requestInfo1.getRequestId(),
requestInfoStreaming.getRequestId());
int status = mCameraUser.cancelRequest(-1, null);
assertEquals("Invalid request IDs should not be cancellable",
CameraBinderTestUtils.BAD_VALUE, status);
try {
long lastFrameNumber = mCameraUser.cancelRequest(-1);
fail("Expected exception");
} catch (ServiceSpecificException e) {
assertEquals("Invalid request IDs should not be cancellable",
ICameraService.ERROR_ILLEGAL_ARGUMENT, e.errorCode);
}
status = mCameraUser.cancelRequest(requestId1, null);
assertEquals("Non-streaming request IDs should not be cancellable",
CameraBinderTestUtils.BAD_VALUE, status);
status = mCameraUser.cancelRequest(requestIdStreaming, null);
assertEquals("Streaming request IDs should be cancellable", CameraBinderTestUtils.NO_ERROR,
status);
try {
long lastFrameNumber = mCameraUser.cancelRequest(requestInfo1.getRequestId());
fail("Expected exception");
} catch (ServiceSpecificException e) {
assertEquals("Non-streaming request IDs should not be cancellable",
ICameraService.ERROR_ILLEGAL_ARGUMENT, e.errorCode);
}
long lastFrameNumber = mCameraUser.cancelRequest(requestInfoStreaming.getRequestId());
}
@SmallTest
public void testCameraInfo() throws RemoteException {
CameraMetadataNative info = new CameraMetadataNative();
int status = mCameraUser.getCameraInfo(/*out*/info);
assertEquals(CameraBinderTestUtils.NO_ERROR, status);
CameraMetadataNative info = mCameraUser.getCameraInfo();
assertFalse(info.isEmpty());
assertNotNull(info.get(CameraCharacteristics.SCALER_AVAILABLE_FORMATS));
@@ -362,10 +389,7 @@ public class CameraDeviceBinderTest extends AndroidTestCase {
@SmallTest
public void testCameraCharacteristics() throws RemoteException {
CameraMetadataNative info = new CameraMetadataNative();
int status = mUtils.getCameraService().getCameraCharacteristics(mCameraId, /*out*/info);
assertEquals(CameraBinderTestUtils.NO_ERROR, status);
CameraMetadataNative info = mUtils.getCameraService().getCameraCharacteristics(mCameraId);
assertFalse(info.isEmpty());
assertNotNull(info.get(CameraCharacteristics.SCALER_AVAILABLE_FORMATS));
@@ -374,18 +398,19 @@ public class CameraDeviceBinderTest extends AndroidTestCase {
@SmallTest
public void testWaitUntilIdle() throws Exception {
CaptureRequest.Builder builder = createDefaultBuilder(/* needStream */true);
int requestIdStreaming = submitCameraRequest(builder.build(), /* streaming */true);
SubmitInfo requestInfoStreaming = submitCameraRequest(builder.build(), /* streaming */true);
// Test Bad case first: waitUntilIdle when there is active repeating request
int status = mCameraUser.waitUntilIdle();
assertEquals("waitUntilIdle is invalid operation when there is active repeating request",
CameraBinderTestUtils.INVALID_OPERATION, status);
try {
mCameraUser.waitUntilIdle();
} catch (ServiceSpecificException e) {
assertEquals("waitUntilIdle is invalid operation when there is active repeating request",
ICameraService.ERROR_INVALID_OPERATION, e.errorCode);
}
// Test good case, waitUntilIdle when there is no active repeating request
status = mCameraUser.cancelRequest(requestIdStreaming, null);
assertEquals(CameraBinderTestUtils.NO_ERROR, status);
status = mCameraUser.waitUntilIdle();
assertEquals(CameraBinderTestUtils.NO_ERROR, status);
long lastFrameNumber = mCameraUser.cancelRequest(requestInfoStreaming.getRequestId());
mCameraUser.waitUntilIdle();
}
@SmallTest
@@ -411,12 +436,12 @@ public class CameraDeviceBinderTest extends AndroidTestCase {
ArgumentCaptor<Long> timestamps = ArgumentCaptor.forClass(Long.class);
// Test both single request and streaming request.
int requestId1 = submitCameraRequest(request, /* streaming */false);
SubmitInfo requestInfo1 = submitCameraRequest(request, /* streaming */false);
verify(mMockCb, timeout(WAIT_FOR_COMPLETE_TIMEOUT_MS).times(1)).onCaptureStarted(
any(CaptureResultExtras.class),
anyLong());
int streamingId = submitCameraRequest(request, /* streaming */true);
SubmitInfo streamingInfo = submitCameraRequest(request, /* streaming */true);
verify(mMockCb, timeout(WAIT_FOR_COMPLETE_TIMEOUT_MS).atLeast(NUM_CALLBACKS_CHECKED))
.onCaptureStarted(
any(CaptureResultExtras.class),
@@ -436,22 +461,22 @@ public class CameraDeviceBinderTest extends AndroidTestCase {
CaptureRequest request = createDefaultBuilder(/* needStream */true).build();
// Try streaming
int streamingId = submitCameraRequest(request, /* streaming */true);
SubmitInfo streamingInfo = submitCameraRequest(request, /* streaming */true);
// Wait a bit to fill up the queue
SystemClock.sleep(WAIT_FOR_WORK_MS);
// Cancel and make sure we eventually quiesce
status = mCameraUser.cancelRequest(streamingId, null);
long lastFrameNumber = mCameraUser.cancelRequest(streamingInfo.getRequestId());
verify(mMockCb, timeout(WAIT_FOR_IDLE_TIMEOUT_MS).times(1)).onDeviceIdle();
// Submit a few capture requests
int requestId1 = submitCameraRequest(request, /* streaming */false);
int requestId2 = submitCameraRequest(request, /* streaming */false);
int requestId3 = submitCameraRequest(request, /* streaming */false);
int requestId4 = submitCameraRequest(request, /* streaming */false);
int requestId5 = submitCameraRequest(request, /* streaming */false);
SubmitInfo requestInfo1 = submitCameraRequest(request, /* streaming */false);
SubmitInfo requestInfo2 = submitCameraRequest(request, /* streaming */false);
SubmitInfo requestInfo3 = submitCameraRequest(request, /* streaming */false);
SubmitInfo requestInfo4 = submitCameraRequest(request, /* streaming */false);
SubmitInfo requestInfo5 = submitCameraRequest(request, /* streaming */false);
// And wait for more idle
verify(mMockCb, timeout(WAIT_FOR_IDLE_TIMEOUT_MS).times(2)).onDeviceIdle();
@@ -463,38 +488,34 @@ public class CameraDeviceBinderTest extends AndroidTestCase {
int status;
// Initial flush should work
status = mCameraUser.flush(null);
assertEquals(CameraBinderTestUtils.NO_ERROR, status);
long lastFrameNumber = mCameraUser.flush();
// Then set up a stream
CaptureRequest request = createDefaultBuilder(/* needStream */true).build();
// Flush should still be a no-op, really
status = mCameraUser.flush(null);
assertEquals(CameraBinderTestUtils.NO_ERROR, status);
lastFrameNumber = mCameraUser.flush();
// Submit a few capture requests
int requestId1 = submitCameraRequest(request, /* streaming */false);
int requestId2 = submitCameraRequest(request, /* streaming */false);
int requestId3 = submitCameraRequest(request, /* streaming */false);
int requestId4 = submitCameraRequest(request, /* streaming */false);
int requestId5 = submitCameraRequest(request, /* streaming */false);
SubmitInfo requestInfo1 = submitCameraRequest(request, /* streaming */false);
SubmitInfo requestInfo2 = submitCameraRequest(request, /* streaming */false);
SubmitInfo requestInfo3 = submitCameraRequest(request, /* streaming */false);
SubmitInfo requestInfo4 = submitCameraRequest(request, /* streaming */false);
SubmitInfo requestInfo5 = submitCameraRequest(request, /* streaming */false);
// Then flush and wait for idle
status = mCameraUser.flush(null);
assertEquals(CameraBinderTestUtils.NO_ERROR, status);
lastFrameNumber = mCameraUser.flush();
verify(mMockCb, timeout(WAIT_FOR_FLUSH_TIMEOUT_MS).times(1)).onDeviceIdle();
// Now a streaming request
int streamingId = submitCameraRequest(request, /* streaming */true);
SubmitInfo streamingInfo = submitCameraRequest(request, /* streaming */true);
// Wait a bit to fill up the queue
SystemClock.sleep(WAIT_FOR_WORK_MS);
// Then flush and wait for the idle callback
status = mCameraUser.flush(null);
assertEquals(CameraBinderTestUtils.NO_ERROR, status);
lastFrameNumber = mCameraUser.flush();
verify(mMockCb, timeout(WAIT_FOR_FLUSH_TIMEOUT_MS).times(2)).onDeviceIdle();

View File

@@ -1,173 +0,0 @@
/*
* Copyright (C) 2013 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 com.android.mediaframeworktest.unit;
import android.hardware.camera2.CameraAccessException;
import android.hardware.camera2.utils.CameraBinderDecorator;
import android.hardware.camera2.utils.CameraRuntimeException;
import android.os.DeadObjectException;
import android.os.RemoteException;
import android.os.TransactionTooLargeException;
import android.test.suitebuilder.annotation.SmallTest;
import static org.mockito.Mockito.*;
import static android.hardware.camera2.utils.CameraBinderDecorator.*;
import static android.hardware.camera2.CameraAccessException.*;
import static android.system.OsConstants.*;
import junit.framework.Assert;
public class CameraUtilsBinderDecoratorTest extends junit.framework.TestCase {
private interface ICameraBinderStereotype {
double doNothing();
// int is a 'status_t'
int doSomethingPositive();
int doSomethingNoError();
int doSomethingPermissionDenied();
int doSomethingAlreadyExists();
int doSomethingBadValue();
int doSomethingDeadObject() throws CameraRuntimeException;
int doSomethingBadPolicy() throws CameraRuntimeException;
int doSomethingDeviceBusy() throws CameraRuntimeException;
int doSomethingNoSuchDevice() throws CameraRuntimeException;
int doSomethingUnknownErrorCode();
int doSomethingThrowDeadObjectException() throws RemoteException;
int doSomethingThrowTransactionTooLargeException() throws RemoteException;
}
private static final double SOME_ARBITRARY_DOUBLE = 1.0;
private static final int SOME_ARBITRARY_POSITIVE_INT = 5;
private static final int SOME_ARBITRARY_NEGATIVE_INT = -0xC0FFEE;
@SmallTest
public void testStereotypes() {
ICameraBinderStereotype mock = mock(ICameraBinderStereotype.class);
try {
when(mock.doNothing()).thenReturn(SOME_ARBITRARY_DOUBLE);
when(mock.doSomethingPositive()).thenReturn(SOME_ARBITRARY_POSITIVE_INT);
when(mock.doSomethingNoError()).thenReturn(NO_ERROR);
when(mock.doSomethingPermissionDenied()).thenReturn(PERMISSION_DENIED);
when(mock.doSomethingAlreadyExists()).thenReturn(ALREADY_EXISTS);
when(mock.doSomethingBadValue()).thenReturn(BAD_VALUE);
when(mock.doSomethingDeadObject()).thenReturn(DEAD_OBJECT);
when(mock.doSomethingBadPolicy()).thenReturn(-EACCES);
when(mock.doSomethingDeviceBusy()).thenReturn(-EBUSY);
when(mock.doSomethingNoSuchDevice()).thenReturn(-ENODEV);
when(mock.doSomethingUnknownErrorCode()).thenReturn(SOME_ARBITRARY_NEGATIVE_INT);
when(mock.doSomethingThrowDeadObjectException()).thenThrow(new DeadObjectException());
when(mock.doSomethingThrowTransactionTooLargeException()).thenThrow(
new TransactionTooLargeException());
} catch (RemoteException e) {
Assert.fail("Unreachable");
}
ICameraBinderStereotype decoratedMock = CameraBinderDecorator.newInstance(mock);
// ignored by decorator because return type is double, not int
assertEquals(SOME_ARBITRARY_DOUBLE, decoratedMock.doNothing());
// pass through for positive values
assertEquals(SOME_ARBITRARY_POSITIVE_INT, decoratedMock.doSomethingPositive());
// pass through NO_ERROR
assertEquals(NO_ERROR, decoratedMock.doSomethingNoError());
try {
decoratedMock.doSomethingPermissionDenied();
Assert.fail("Should've thrown SecurityException");
} catch (SecurityException e) {
}
assertEquals(ALREADY_EXISTS, decoratedMock.doSomethingAlreadyExists());
try {
decoratedMock.doSomethingBadValue();
Assert.fail("Should've thrown IllegalArgumentException");
} catch (IllegalArgumentException e) {
}
try {
decoratedMock.doSomethingDeadObject();
Assert.fail("Should've thrown CameraRuntimeException");
} catch (CameraRuntimeException e) {
assertEquals(CAMERA_DISCONNECTED, e.getReason());
}
try {
decoratedMock.doSomethingBadPolicy();
Assert.fail("Should've thrown CameraRuntimeException");
} catch (CameraRuntimeException e) {
assertEquals(CAMERA_DISABLED, e.getReason());
}
try {
decoratedMock.doSomethingDeviceBusy();
Assert.fail("Should've thrown CameraRuntimeException");
} catch (CameraRuntimeException e) {
assertEquals(CAMERA_IN_USE, e.getReason());
}
try {
decoratedMock.doSomethingNoSuchDevice();
Assert.fail("Should've thrown CameraRuntimeException");
} catch (CameraRuntimeException e) {
assertEquals(CAMERA_DISCONNECTED, e.getReason());
}
try {
decoratedMock.doSomethingUnknownErrorCode();
Assert.fail("Should've thrown UnsupportedOperationException");
} catch (UnsupportedOperationException e) {
assertEquals(String.format("Unknown error %d",
SOME_ARBITRARY_NEGATIVE_INT), e.getMessage());
}
try {
decoratedMock.doSomethingThrowDeadObjectException();
Assert.fail("Should've thrown CameraRuntimeException");
} catch (CameraRuntimeException e) {
assertEquals(CAMERA_DISCONNECTED, e.getReason());
} catch (RemoteException e) {
Assert.fail("Should not throw a DeadObjectException directly, but rethrow");
}
try {
decoratedMock.doSomethingThrowTransactionTooLargeException();
Assert.fail("Should've thrown UnsupportedOperationException");
} catch (UnsupportedOperationException e) {
assertTrue(e.getCause() instanceof TransactionTooLargeException);
} catch (RemoteException e) {
Assert.fail("Should not throw a TransactionTooLargeException directly, but rethrow");
}
}
}

View File

@@ -1,171 +0,0 @@
/*
* Copyright (C) 2013 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 com.android.mediaframeworktest.unit;
import android.test.suitebuilder.annotation.SmallTest;
import android.hardware.camera2.utils.*;
import android.hardware.camera2.utils.Decorator.DecoratorListener;
import junit.framework.Assert;
import java.lang.reflect.Method;
/**
* adb shell am instrument -e class 'com.android.mediaframeworktest.unit.CameraUtilsDecoratorTest' \
* -w com.android.mediaframeworktest/.MediaFrameworkUnitTestRunner
*/
public class CameraUtilsDecoratorTest extends junit.framework.TestCase {
private DummyListener mDummyListener;
private DummyInterface mIface;
@Override
public void setUp() {
mDummyListener = new DummyListener();
mIface = Decorator.newInstance(new DummyImpl(), mDummyListener);
}
interface DummyInterface {
int addValues(int x, int y, int z);
void raiseException() throws Exception;
void raiseUnsupportedOperationException() throws UnsupportedOperationException;
}
class DummyImpl implements DummyInterface {
@Override
public int addValues(int x, int y, int z) {
return x + y + z;
}
@Override
public void raiseException() throws Exception {
throw new Exception("Test exception");
}
@Override
public void raiseUnsupportedOperationException() throws UnsupportedOperationException {
throw new UnsupportedOperationException("Test exception");
}
}
class DummyListener implements DecoratorListener {
public boolean beforeCalled = false;
public boolean afterCalled = false;
public boolean catchCalled = false;
public boolean finallyCalled = false;
public Object resultValue = null;
public boolean raiseException = false;
@Override
public void onBeforeInvocation(Method m, Object[] args) {
beforeCalled = true;
}
@Override
public void onAfterInvocation(Method m, Object[] args, Object result) {
afterCalled = true;
resultValue = result;
if (raiseException) {
throw new UnsupportedOperationException("Test exception");
}
}
@Override
public boolean onCatchException(Method m, Object[] args, Throwable t) {
catchCalled = true;
return false;
}
@Override
public void onFinally(Method m, Object[] args) {
finallyCalled = true;
}
};
@SmallTest
public void testDecorator() {
// TODO rewrite this using mocks
assertTrue(mIface.addValues(1, 2, 3) == 6);
assertTrue(mDummyListener.beforeCalled);
assertTrue(mDummyListener.afterCalled);
int resultValue = (Integer)mDummyListener.resultValue;
assertTrue(resultValue == 6);
assertTrue(mDummyListener.finallyCalled);
assertFalse(mDummyListener.catchCalled);
}
@SmallTest
public void testDecoratorExceptions() {
boolean gotExceptions = false;
try {
mIface.raiseException();
} catch (Exception e) {
gotExceptions = true;
assertTrue(e.getMessage() == "Test exception");
}
assertTrue(gotExceptions);
assertTrue(mDummyListener.beforeCalled);
assertFalse(mDummyListener.afterCalled);
assertTrue(mDummyListener.catchCalled);
assertTrue(mDummyListener.finallyCalled);
}
@SmallTest
public void testDecoratorUnsupportedOperationException() {
boolean gotExceptions = false;
try {
mIface.raiseUnsupportedOperationException();
} catch (UnsupportedOperationException e) {
gotExceptions = true;
assertTrue(e.getMessage() == "Test exception");
}
assertTrue(gotExceptions);
assertTrue(mDummyListener.beforeCalled);
assertFalse(mDummyListener.afterCalled);
assertTrue(mDummyListener.catchCalled);
assertTrue(mDummyListener.finallyCalled);
}
@SmallTest
public void testDecoratorRaisesException() {
boolean gotExceptions = false;
try {
mDummyListener.raiseException = true;
mIface.addValues(1, 2, 3);
Assert.fail("unreachable");
} catch (UnsupportedOperationException e) {
gotExceptions = true;
assertTrue(e.getMessage() == "Test exception");
}
assertTrue(gotExceptions);
assertTrue(mDummyListener.beforeCalled);
assertTrue(mDummyListener.afterCalled);
assertFalse(mDummyListener.catchCalled);
assertTrue(mDummyListener.finallyCalled);
}
}

View File

@@ -1,77 +0,0 @@
/*
* Copyright (C) 2013 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 com.android.mediaframeworktest.unit;
import android.hardware.camera2.CameraAccessException;
import android.hardware.camera2.utils.CameraRuntimeException;
import android.hardware.camera2.utils.UncheckedThrow;
import android.test.suitebuilder.annotation.SmallTest;
import junit.framework.Assert;
public class CameraUtilsRuntimeExceptionTest extends junit.framework.TestCase {
@SmallTest
public void testCameraRuntimeException1() {
try {
CameraRuntimeException runtimeExc = new CameraRuntimeException(12345);
throw runtimeExc.asChecked();
} catch (CameraAccessException e) {
assertEquals(12345, e.getReason());
assertNull(e.getMessage());
assertNull(e.getCause());
}
}
@SmallTest
public void testCameraRuntimeException2() {
try {
CameraRuntimeException runtimeExc = new CameraRuntimeException(12345, "Hello");
throw runtimeExc.asChecked();
} catch (CameraAccessException e) {
assertEquals(12345, e.getReason());
assertEquals("Hello", e.getMessage());
assertNull(e.getCause());
}
}
@SmallTest
public void testCameraRuntimeException3() {
Throwable cause = new IllegalStateException("For great justice");
try {
CameraRuntimeException runtimeExc = new CameraRuntimeException(12345, cause);
throw runtimeExc.asChecked();
} catch (CameraAccessException e) {
assertEquals(12345, e.getReason());
assertNull(e.getMessage());
assertEquals(cause, e.getCause());
}
}
@SmallTest
public void testCameraRuntimeException4() {
Throwable cause = new IllegalStateException("For great justice");
try {
CameraRuntimeException runtimeExc = new CameraRuntimeException(12345, "Hello", cause);
throw runtimeExc.asChecked();
} catch (CameraAccessException e) {
assertEquals(12345, e.getReason());
assertEquals("Hello", e.getMessage());
assertEquals(cause, e.getCause());
}
}
}

View File

@@ -60,10 +60,6 @@ public class CameraService extends SystemService
public static final String CAMERA_SERVICE_PROXY_BINDER_NAME = "media.camera.proxy";
// Event arguments to use with the camera service notifySystemEvent call:
public static final int NO_EVENT = 0; // NOOP
public static final int USER_SWITCHED = 1; // User changed, argument is the new user handle
// State arguments to use with the notifyCameraState call from camera service:
public static final int CAMERA_STATE_OPEN = 0;
public static final int CAMERA_STATE_ACTIVE = 1;
@@ -224,7 +220,7 @@ public class CameraService extends SystemService
if (mEnabledCameraUsers == null || !mEnabledCameraUsers.equals(currentUserHandles)) {
// Some user handles have been added or removed, update mediaserver.
mEnabledCameraUsers = currentUserHandles;
notifyMediaserverLocked(USER_SWITCHED, currentUserHandles);
notifyMediaserverLocked(ICameraService.EVENT_USER_SWITCHED, currentUserHandles);
}
}
@@ -244,7 +240,7 @@ public class CameraService extends SystemService
if (mEnabledCameraUsers == null) {
return;
}
if (notifyMediaserverLocked(USER_SWITCHED, mEnabledCameraUsers)) {
if (notifyMediaserverLocked(ICameraService.EVENT_USER_SWITCHED, mEnabledCameraUsers)) {
retries = 0;
}
}