Loading api/current.txt +2 −1 Original line number Diff line number Diff line Loading @@ -10653,7 +10653,7 @@ package android.hardware.location { package android.hardware.photography { public class CameraAccessException extends android.util.AndroidException { public class CameraAccessException extends java.lang.Exception { ctor public CameraAccessException(int); ctor public CameraAccessException(int, java.lang.String); ctor public CameraAccessException(int, java.lang.String, java.lang.Throwable); Loading @@ -10666,6 +10666,7 @@ package android.hardware.photography { } public final class CameraDevice implements java.lang.AutoCloseable { ctor public CameraDevice(); method public void capture(android.hardware.photography.CaptureRequest, android.hardware.photography.CameraDevice.CaptureListener) throws android.hardware.photography.CameraAccessException; method public void captureBurst(java.util.List<android.hardware.photography.CaptureRequest>, android.hardware.photography.CameraDevice.CaptureListener) throws android.hardware.photography.CameraAccessException; method public void close(); core/java/android/app/ContextImpl.java +3 −3 Original line number Diff line number Diff line Loading @@ -549,9 +549,9 @@ class ContextImpl extends Context { return new AppOpsManager(ctx, service); }}); registerService(CAMERA_SERVICE, new ServiceFetcher() { public Object createService(ContextImpl ctx) { return new CameraManager(ctx); registerService(CAMERA_SERVICE, new StaticServiceFetcher() { public Object createStaticService() { return new CameraManager(); } }); Loading core/java/android/hardware/photography/CameraAccessException.java +3 −27 Original line number Diff line number Diff line Loading @@ -16,8 +16,6 @@ package android.hardware.photography; import android.util.AndroidException; /** * <p><code>CameraAccessException</code> is thrown if a camera device could not * be queried or opened by the {@link CameraManager}, or if the connection to an Loading @@ -26,7 +24,7 @@ import android.util.AndroidException; * @see CameraManager * @see CameraDevice */ public class CameraAccessException extends AndroidException { public class CameraAccessException extends Exception { /** * The camera device is in use already */ Loading @@ -53,10 +51,7 @@ public class CameraAccessException extends AndroidException { */ public static final int CAMERA_DISCONNECTED = 4; // Make the eclipse warning about serializable exceptions go away private static final long serialVersionUID = 5630338637471475675L; // randomly generated private final int mReason; private int mReason; /** * The reason for the failure to access the camera. Loading @@ -71,7 +66,6 @@ public class CameraAccessException extends AndroidException { } public CameraAccessException(int problem) { super(getDefaultMessage(problem)); mReason = problem; } Loading @@ -86,25 +80,7 @@ public class CameraAccessException extends AndroidException { } public CameraAccessException(int problem, Throwable cause) { super(getDefaultMessage(problem), cause); super(cause); mReason = problem; } private static String getDefaultMessage(int problem) { switch (problem) { case CAMERA_IN_USE: return "The camera device is in use already"; case MAX_CAMERAS_IN_USE: return "The system-wide limit for number of open cameras has been reached, " + "and more camera devices cannot be opened until previous instances " + "are closed."; case CAMERA_DISABLED: return "The camera is disabled due to a device policy, and cannot be opened."; case CAMERA_DISCONNECTED: return "The camera device is removable and has been disconnected from the Android" + " device, or the camera service has shut down the connection due to a " + "higher-priority access request for the camera device."; } return null; } } core/java/android/hardware/photography/CameraDevice.java +0 −12 Original line number Diff line number Diff line Loading @@ -17,10 +17,8 @@ package android.hardware.photography; import android.graphics.ImageFormat; import android.os.IBinder; import android.renderscript.Allocation; import android.renderscript.RenderScript; import android.util.Log; import android.view.Surface; import java.lang.AutoCloseable; Loading Loading @@ -103,8 +101,6 @@ public final class CameraDevice implements AutoCloseable { */ public static final int TEMPLATE_MANUAL = 5; private static final String TAG = "CameraDevice"; /** * Get the static properties for this camera. These are identical to the * properties returned by {@link CameraManager#getCameraProperties}. Loading Loading @@ -455,7 +451,6 @@ public final class CameraDevice implements AutoCloseable { * the camera device interface will throw a {@link IllegalStateException}, * except for calls to close(). */ @Override public void close() { } Loading Loading @@ -557,11 +552,4 @@ public final class CameraDevice implements AutoCloseable { public void onCameraDeviceError(CameraDevice camera, int error); } /** * @hide */ public CameraDevice(IBinder binder) { Log.e(TAG, "CameraDevice constructor not implemented yet"); } } core/java/android/hardware/photography/CameraManager.java +7 −234 Original line number Diff line number Diff line Loading @@ -16,22 +16,6 @@ package android.hardware.photography; import android.content.Context; import android.hardware.ICameraService; import android.hardware.ICameraServiceListener; import android.hardware.IProCameraUser; import android.hardware.photography.utils.CameraBinderDecorator; import android.hardware.photography.utils.CameraRuntimeException; import android.os.Binder; import android.os.IBinder; import android.os.RemoteException; import android.os.ServiceManager; import android.util.Log; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; /** * <p>An interface for iterating, listing, and connecting to * {@link CameraDevice CameraDevices}.</p> Loading @@ -47,41 +31,10 @@ import java.util.HashSet; */ public final class CameraManager { /** * This should match the ICameraService definition */ private static final String CAMERA_SERVICE_BINDER_NAME = "media.camera"; private static final int USE_CALLING_UID = -1; private final ICameraService mCameraService; private ArrayList<String> mDeviceIdList; private HashSet<CameraListener> mListenerSet; private final Context mContext; private final Object mLock = new Object(); /** * @hide */ public CameraManager(Context context) { mContext = context; IBinder cameraServiceBinder = ServiceManager.getService(CAMERA_SERVICE_BINDER_NAME); ICameraService cameraServiceRaw = ICameraService.Stub.asInterface(cameraServiceBinder); /** * Wrap the camera service in a decorator which automatically translates return codes * into exceptions, and RemoteExceptions into other exceptions. */ mCameraService = CameraBinderDecorator.newInstance(cameraServiceRaw); try { mCameraService.addListener(new CameraServiceListener()); } catch(CameraRuntimeException e) { throw new IllegalStateException("Failed to register a camera service listener", e.asChecked()); } catch (RemoteException e) { // impossible } public CameraManager() { } /** Loading @@ -92,37 +45,25 @@ public final class CameraManager { * * @return The list of currently connected camera devices. */ public String[] getDeviceIdList() throws CameraAccessException { synchronized (mLock) { return (String[]) getOrCreateDeviceIdListLocked().toArray(); } public String[] getDeviceIdList() { return null; } /** * Register a listener to be notified about camera device availability. * * Registering a listener more than once has no effect. * * @param listener the new listener to send camera availability notices to. * @param listener the new listener to send camera availablity notices to. */ public void registerCameraListener(CameraListener listener) { synchronized (mLock) { mListenerSet.add(listener); } } /** * Remove a previously-added listener; the listener will no longer receive * connection and disconnection callbacks. * * Removing a listener that isn't registered has no effect. * * @param listener the listener to remove from the notification list */ public void unregisterCameraListener(CameraListener listener) { synchronized (mLock) { mListenerSet.remove(listener); } } /** Loading @@ -143,18 +84,7 @@ public final class CameraManager { */ public CameraProperties getCameraProperties(String cameraId) throws CameraAccessException { synchronized (mLock) { if (!getOrCreateDeviceIdListLocked().contains(cameraId)) { throw new IllegalArgumentException(String.format("Camera id %s does not match any" + " currently connected camera device", cameraId)); } } // TODO: implement and call a service function to get the capabilities on C++ side // TODO: get properties from service return new CameraProperties(); throw new IllegalArgumentException(); } /** Loading @@ -177,33 +107,7 @@ public final class CameraManager { * @see android.app.admin.DevicePolicyManager#setCameraDisabled */ public CameraDevice openCamera(String cameraId) throws CameraAccessException { try { IProCameraUser cameraUser; synchronized (mLock) { // TODO: Use ICameraDevice or some such instead of this... cameraUser = mCameraService.connectPro(null, Integer.parseInt(cameraId), mContext.getPackageName(), USE_CALLING_UID); } return new CameraDevice(cameraUser.asBinder()); } catch (NumberFormatException e) { throw new IllegalArgumentException("Expected cameraId to be numeric, but it was: " + cameraId); } catch (CameraRuntimeException e) { if (e.getReason() == CameraAccessException.CAMERA_DISCONNECTED) { throw new IllegalArgumentException("Invalid camera ID specified -- " + "perhaps the camera was physically disconnected", e); } else { throw e.asChecked(); } } catch (RemoteException e) { // impossible return null; } throw new IllegalArgumentException(); } /** Loading Loading @@ -231,135 +135,4 @@ public final class CameraManager { */ public void onCameraUnavailable(String cameraId); } private ArrayList<String> getOrCreateDeviceIdListLocked() throws CameraAccessException { if (mDeviceIdList == null) { int numCameras = 0; try { numCameras = mCameraService.getNumberOfCameras(); } catch(CameraRuntimeException e) { throw e.asChecked(); } catch (RemoteException e) { // impossible return null; } mDeviceIdList = new ArrayList<String>(); for (int i = 0; i < numCameras; ++i) { // Non-removable cameras use integers starting at 0 for their // identifiers mDeviceIdList.add(String.valueOf(i)); } } return mDeviceIdList; } // TODO: this class needs unit tests // TODO: extract class into top level private class CameraServiceListener extends Binder implements ICameraServiceListener { // 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; // Camera ID -> Status map private final HashMap<String, Integer> mDeviceStatus = new HashMap<String, Integer>(); private static final String TAG = "CameraServiceListener"; @Override public IBinder asBinder() { return this; } private boolean isAvailable(int status) { switch (status) { case STATUS_PRESENT: return true; default: return false; } } private boolean validStatus(int status) { switch (status) { case STATUS_NOT_PRESENT: case STATUS_PRESENT: case STATUS_ENUMERATING: case STATUS_NOT_AVAILABLE: return true; default: return false; } } @Override public void onStatusChanged(int status, int cameraId) throws RemoteException { synchronized(CameraManager.this) { Log.v(TAG, String.format("Camera id %d has status changed to 0x%x", cameraId, status)); String id = String.valueOf(cameraId); if (!validStatus(status)) { Log.e(TAG, String.format("Ignoring invalid device %d status 0x%x", cameraId, status)); return; } Integer oldStatus = mDeviceStatus.put(id, status); if (oldStatus == status) { Log.v(TAG, String.format( "Device status changed to 0x%x, which is what it already was", status)); return; } // TODO: consider abstracting out this state minimization + transition // into a separate // more easily testable class // i.e. (new State()).addState(STATE_AVAILABLE) // .addState(STATE_NOT_AVAILABLE) // .addTransition(STATUS_PRESENT, STATE_AVAILABLE), // .addTransition(STATUS_NOT_PRESENT, STATE_NOT_AVAILABLE) // .addTransition(STATUS_ENUMERATING, STATE_NOT_AVAILABLE); // .addTransition(STATUS_NOT_AVAILABLE, STATE_NOT_AVAILABLE); // Translate all the statuses to either 'available' or 'not available' // available -> available => no new update // not available -> not available => no new update if (oldStatus != null && isAvailable(status) == isAvailable(oldStatus)) { Log.v(TAG, String.format( "Device status was previously available (%d), " + " and is now again available (%d)" + "so no new client visible update will be sent", isAvailable(status), isAvailable(status))); return; } for (CameraListener listener : mListenerSet) { if (isAvailable(status)) { listener.onCameraAvailable(id); } else { listener.onCameraUnavailable(id); } } // for } // synchronized } // onStatusChanged } // CameraServiceListener } // CameraManager Loading
api/current.txt +2 −1 Original line number Diff line number Diff line Loading @@ -10653,7 +10653,7 @@ package android.hardware.location { package android.hardware.photography { public class CameraAccessException extends android.util.AndroidException { public class CameraAccessException extends java.lang.Exception { ctor public CameraAccessException(int); ctor public CameraAccessException(int, java.lang.String); ctor public CameraAccessException(int, java.lang.String, java.lang.Throwable); Loading @@ -10666,6 +10666,7 @@ package android.hardware.photography { } public final class CameraDevice implements java.lang.AutoCloseable { ctor public CameraDevice(); method public void capture(android.hardware.photography.CaptureRequest, android.hardware.photography.CameraDevice.CaptureListener) throws android.hardware.photography.CameraAccessException; method public void captureBurst(java.util.List<android.hardware.photography.CaptureRequest>, android.hardware.photography.CameraDevice.CaptureListener) throws android.hardware.photography.CameraAccessException; method public void close();
core/java/android/app/ContextImpl.java +3 −3 Original line number Diff line number Diff line Loading @@ -549,9 +549,9 @@ class ContextImpl extends Context { return new AppOpsManager(ctx, service); }}); registerService(CAMERA_SERVICE, new ServiceFetcher() { public Object createService(ContextImpl ctx) { return new CameraManager(ctx); registerService(CAMERA_SERVICE, new StaticServiceFetcher() { public Object createStaticService() { return new CameraManager(); } }); Loading
core/java/android/hardware/photography/CameraAccessException.java +3 −27 Original line number Diff line number Diff line Loading @@ -16,8 +16,6 @@ package android.hardware.photography; import android.util.AndroidException; /** * <p><code>CameraAccessException</code> is thrown if a camera device could not * be queried or opened by the {@link CameraManager}, or if the connection to an Loading @@ -26,7 +24,7 @@ import android.util.AndroidException; * @see CameraManager * @see CameraDevice */ public class CameraAccessException extends AndroidException { public class CameraAccessException extends Exception { /** * The camera device is in use already */ Loading @@ -53,10 +51,7 @@ public class CameraAccessException extends AndroidException { */ public static final int CAMERA_DISCONNECTED = 4; // Make the eclipse warning about serializable exceptions go away private static final long serialVersionUID = 5630338637471475675L; // randomly generated private final int mReason; private int mReason; /** * The reason for the failure to access the camera. Loading @@ -71,7 +66,6 @@ public class CameraAccessException extends AndroidException { } public CameraAccessException(int problem) { super(getDefaultMessage(problem)); mReason = problem; } Loading @@ -86,25 +80,7 @@ public class CameraAccessException extends AndroidException { } public CameraAccessException(int problem, Throwable cause) { super(getDefaultMessage(problem), cause); super(cause); mReason = problem; } private static String getDefaultMessage(int problem) { switch (problem) { case CAMERA_IN_USE: return "The camera device is in use already"; case MAX_CAMERAS_IN_USE: return "The system-wide limit for number of open cameras has been reached, " + "and more camera devices cannot be opened until previous instances " + "are closed."; case CAMERA_DISABLED: return "The camera is disabled due to a device policy, and cannot be opened."; case CAMERA_DISCONNECTED: return "The camera device is removable and has been disconnected from the Android" + " device, or the camera service has shut down the connection due to a " + "higher-priority access request for the camera device."; } return null; } }
core/java/android/hardware/photography/CameraDevice.java +0 −12 Original line number Diff line number Diff line Loading @@ -17,10 +17,8 @@ package android.hardware.photography; import android.graphics.ImageFormat; import android.os.IBinder; import android.renderscript.Allocation; import android.renderscript.RenderScript; import android.util.Log; import android.view.Surface; import java.lang.AutoCloseable; Loading Loading @@ -103,8 +101,6 @@ public final class CameraDevice implements AutoCloseable { */ public static final int TEMPLATE_MANUAL = 5; private static final String TAG = "CameraDevice"; /** * Get the static properties for this camera. These are identical to the * properties returned by {@link CameraManager#getCameraProperties}. Loading Loading @@ -455,7 +451,6 @@ public final class CameraDevice implements AutoCloseable { * the camera device interface will throw a {@link IllegalStateException}, * except for calls to close(). */ @Override public void close() { } Loading Loading @@ -557,11 +552,4 @@ public final class CameraDevice implements AutoCloseable { public void onCameraDeviceError(CameraDevice camera, int error); } /** * @hide */ public CameraDevice(IBinder binder) { Log.e(TAG, "CameraDevice constructor not implemented yet"); } }
core/java/android/hardware/photography/CameraManager.java +7 −234 Original line number Diff line number Diff line Loading @@ -16,22 +16,6 @@ package android.hardware.photography; import android.content.Context; import android.hardware.ICameraService; import android.hardware.ICameraServiceListener; import android.hardware.IProCameraUser; import android.hardware.photography.utils.CameraBinderDecorator; import android.hardware.photography.utils.CameraRuntimeException; import android.os.Binder; import android.os.IBinder; import android.os.RemoteException; import android.os.ServiceManager; import android.util.Log; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; /** * <p>An interface for iterating, listing, and connecting to * {@link CameraDevice CameraDevices}.</p> Loading @@ -47,41 +31,10 @@ import java.util.HashSet; */ public final class CameraManager { /** * This should match the ICameraService definition */ private static final String CAMERA_SERVICE_BINDER_NAME = "media.camera"; private static final int USE_CALLING_UID = -1; private final ICameraService mCameraService; private ArrayList<String> mDeviceIdList; private HashSet<CameraListener> mListenerSet; private final Context mContext; private final Object mLock = new Object(); /** * @hide */ public CameraManager(Context context) { mContext = context; IBinder cameraServiceBinder = ServiceManager.getService(CAMERA_SERVICE_BINDER_NAME); ICameraService cameraServiceRaw = ICameraService.Stub.asInterface(cameraServiceBinder); /** * Wrap the camera service in a decorator which automatically translates return codes * into exceptions, and RemoteExceptions into other exceptions. */ mCameraService = CameraBinderDecorator.newInstance(cameraServiceRaw); try { mCameraService.addListener(new CameraServiceListener()); } catch(CameraRuntimeException e) { throw new IllegalStateException("Failed to register a camera service listener", e.asChecked()); } catch (RemoteException e) { // impossible } public CameraManager() { } /** Loading @@ -92,37 +45,25 @@ public final class CameraManager { * * @return The list of currently connected camera devices. */ public String[] getDeviceIdList() throws CameraAccessException { synchronized (mLock) { return (String[]) getOrCreateDeviceIdListLocked().toArray(); } public String[] getDeviceIdList() { return null; } /** * Register a listener to be notified about camera device availability. * * Registering a listener more than once has no effect. * * @param listener the new listener to send camera availability notices to. * @param listener the new listener to send camera availablity notices to. */ public void registerCameraListener(CameraListener listener) { synchronized (mLock) { mListenerSet.add(listener); } } /** * Remove a previously-added listener; the listener will no longer receive * connection and disconnection callbacks. * * Removing a listener that isn't registered has no effect. * * @param listener the listener to remove from the notification list */ public void unregisterCameraListener(CameraListener listener) { synchronized (mLock) { mListenerSet.remove(listener); } } /** Loading @@ -143,18 +84,7 @@ public final class CameraManager { */ public CameraProperties getCameraProperties(String cameraId) throws CameraAccessException { synchronized (mLock) { if (!getOrCreateDeviceIdListLocked().contains(cameraId)) { throw new IllegalArgumentException(String.format("Camera id %s does not match any" + " currently connected camera device", cameraId)); } } // TODO: implement and call a service function to get the capabilities on C++ side // TODO: get properties from service return new CameraProperties(); throw new IllegalArgumentException(); } /** Loading @@ -177,33 +107,7 @@ public final class CameraManager { * @see android.app.admin.DevicePolicyManager#setCameraDisabled */ public CameraDevice openCamera(String cameraId) throws CameraAccessException { try { IProCameraUser cameraUser; synchronized (mLock) { // TODO: Use ICameraDevice or some such instead of this... cameraUser = mCameraService.connectPro(null, Integer.parseInt(cameraId), mContext.getPackageName(), USE_CALLING_UID); } return new CameraDevice(cameraUser.asBinder()); } catch (NumberFormatException e) { throw new IllegalArgumentException("Expected cameraId to be numeric, but it was: " + cameraId); } catch (CameraRuntimeException e) { if (e.getReason() == CameraAccessException.CAMERA_DISCONNECTED) { throw new IllegalArgumentException("Invalid camera ID specified -- " + "perhaps the camera was physically disconnected", e); } else { throw e.asChecked(); } } catch (RemoteException e) { // impossible return null; } throw new IllegalArgumentException(); } /** Loading Loading @@ -231,135 +135,4 @@ public final class CameraManager { */ public void onCameraUnavailable(String cameraId); } private ArrayList<String> getOrCreateDeviceIdListLocked() throws CameraAccessException { if (mDeviceIdList == null) { int numCameras = 0; try { numCameras = mCameraService.getNumberOfCameras(); } catch(CameraRuntimeException e) { throw e.asChecked(); } catch (RemoteException e) { // impossible return null; } mDeviceIdList = new ArrayList<String>(); for (int i = 0; i < numCameras; ++i) { // Non-removable cameras use integers starting at 0 for their // identifiers mDeviceIdList.add(String.valueOf(i)); } } return mDeviceIdList; } // TODO: this class needs unit tests // TODO: extract class into top level private class CameraServiceListener extends Binder implements ICameraServiceListener { // 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; // Camera ID -> Status map private final HashMap<String, Integer> mDeviceStatus = new HashMap<String, Integer>(); private static final String TAG = "CameraServiceListener"; @Override public IBinder asBinder() { return this; } private boolean isAvailable(int status) { switch (status) { case STATUS_PRESENT: return true; default: return false; } } private boolean validStatus(int status) { switch (status) { case STATUS_NOT_PRESENT: case STATUS_PRESENT: case STATUS_ENUMERATING: case STATUS_NOT_AVAILABLE: return true; default: return false; } } @Override public void onStatusChanged(int status, int cameraId) throws RemoteException { synchronized(CameraManager.this) { Log.v(TAG, String.format("Camera id %d has status changed to 0x%x", cameraId, status)); String id = String.valueOf(cameraId); if (!validStatus(status)) { Log.e(TAG, String.format("Ignoring invalid device %d status 0x%x", cameraId, status)); return; } Integer oldStatus = mDeviceStatus.put(id, status); if (oldStatus == status) { Log.v(TAG, String.format( "Device status changed to 0x%x, which is what it already was", status)); return; } // TODO: consider abstracting out this state minimization + transition // into a separate // more easily testable class // i.e. (new State()).addState(STATE_AVAILABLE) // .addState(STATE_NOT_AVAILABLE) // .addTransition(STATUS_PRESENT, STATE_AVAILABLE), // .addTransition(STATUS_NOT_PRESENT, STATE_NOT_AVAILABLE) // .addTransition(STATUS_ENUMERATING, STATE_NOT_AVAILABLE); // .addTransition(STATUS_NOT_AVAILABLE, STATE_NOT_AVAILABLE); // Translate all the statuses to either 'available' or 'not available' // available -> available => no new update // not available -> not available => no new update if (oldStatus != null && isAvailable(status) == isAvailable(oldStatus)) { Log.v(TAG, String.format( "Device status was previously available (%d), " + " and is now again available (%d)" + "so no new client visible update will be sent", isAvailable(status), isAvailable(status))); return; } for (CameraListener listener : mListenerSet) { if (isAvailable(status)) { listener.onCameraAvailable(id); } else { listener.onCameraUnavailable(id); } } // for } // synchronized } // onStatusChanged } // CameraServiceListener } // CameraManager