Loading api/current.txt +2 −0 Original line number Diff line number Diff line Loading @@ -17259,6 +17259,8 @@ package android.hardware.camera2 { method public void onCameraAccessPrioritiesChanged(); method public void onCameraAvailable(@NonNull String); method public void onCameraUnavailable(@NonNull String); method public void onPhysicalCameraAvailable(@NonNull String, @NonNull String); method public void onPhysicalCameraUnavailable(@NonNull String, @NonNull String); } public abstract static class CameraManager.TorchCallback { core/java/android/hardware/CameraStatus.java +3 −0 Original line number Diff line number Diff line Loading @@ -30,6 +30,7 @@ import android.os.Parcelable; public class CameraStatus implements Parcelable { public String cameraId; public int status; public String[] unavailablePhysicalCameras; @Override public int describeContents() { Loading @@ -40,11 +41,13 @@ public class CameraStatus implements Parcelable { public void writeToParcel(Parcel out, int flags) { out.writeString(cameraId); out.writeInt(status); out.writeStringArray(unavailablePhysicalCameras); } public void readFromParcel(Parcel in) { cameraId = in.readString(); status = in.readInt(); unavailablePhysicalCameras = in.readStringArray(); } public static final @android.annotation.NonNull Parcelable.Creator<CameraStatus> CREATOR = Loading core/java/android/hardware/camera2/CameraManager.java +147 −5 Original line number Diff line number Diff line Loading @@ -718,6 +718,52 @@ public final class CameraManager { public void onCameraAccessPrioritiesChanged() { // default empty implementation } /** * A physical camera has become available for use again. * * <p>By default, all of the physical cameras of a logical multi-camera are * available, so {@link #onPhysicalCameraAvailable} is not called for any of the physical * cameras of a logical multi-camera, when {@link #onCameraAvailable} for the logical * multi-camera is invoked. However, if some specific physical cameras are unavailable * to begin with, {@link #onPhysicalCameraUnavailable} may be invoked after * {@link #onCameraAvailable}.</p> * * <p>The default implementation of this method does nothing.</p> * * @param cameraId The unique identifier of the logical multi-camera. * @param physicalCameraId The unique identifier of the physical camera. * * @see #onCameraAvailable * @see #onPhysicalCameraUnavailable */ public void onPhysicalCameraAvailable(@NonNull String cameraId, @NonNull String physicalCameraId) { // default empty implementation } /** * A previously-available physical camera has become unavailable for use. * * <p>By default, all of the physical cameras of a logical multi-camera are * available, so {@link #onPhysicalCameraAvailable} is not called for any of the physical * cameras of a logical multi-camera, when {@link #onCameraAvailable} for the logical * multi-camera is invoked. If some specific physical cameras are unavailable * to begin with, {@link #onPhysicalCameraUnavailable} may be invoked after * {@link #onCameraAvailable}.</p> * * <p>The default implementation of this method does nothing.</p> * * @param cameraId The unique identifier of the logical multi-camera. * @param physicalCameraId The unique identifier of the physical camera. * * @see #onCameraAvailable * @see #onPhysicalCameraAvailable */ public void onPhysicalCameraUnavailable(@NonNull String cameraId, @NonNull String physicalCameraId) { // default empty implementation } } /** Loading Loading @@ -914,6 +960,9 @@ public final class CameraManager { private final ScheduledExecutorService mScheduler = Executors.newScheduledThreadPool(1); // Camera ID -> Status map private final ArrayMap<String, Integer> mDeviceStatus = new ArrayMap<String, Integer>(); // Camera ID -> (physical camera ID -> Status map) private final ArrayMap<String, ArrayList<String>> mUnavailablePhysicalDevices = new ArrayMap<String, ArrayList<String>>(); // Registered availablility callbacks and their executors private final ArrayMap<AvailabilityCallback, Executor> mCallbackMap = Loading Loading @@ -1003,6 +1052,14 @@ public final class CameraManager { CameraStatus[] cameraStatuses = cameraService.addListener(this); for (CameraStatus c : cameraStatuses) { onStatusChangedLocked(c.status, c.cameraId); if (c.unavailablePhysicalCameras != null) { for (String unavailPhysicalCamera : c.unavailablePhysicalCameras) { onPhysicalCameraStatusChangedLocked( ICameraServiceListener.STATUS_NOT_PRESENT, c.cameraId, unavailPhysicalCamera); } } } mCameraService = cameraService; } catch(ServiceSpecificException e) { Loading Loading @@ -1086,6 +1143,10 @@ public final class CameraManager { public void onStatusChanged(int status, String id) throws RemoteException { } @Override public void onPhysicalCameraStatusChanged(int status, String id, String physicalId) throws RemoteException { } @Override public void onTorchStatusChanged(int status, String id) throws RemoteException { } @Override Loading Loading @@ -1236,7 +1297,7 @@ public final class CameraManager { } private void postSingleUpdate(final AvailabilityCallback callback, final Executor executor, final String id, final int status) { final String id, final String physicalId, final int status) { if (isAvailable(status)) { final long ident = Binder.clearCallingIdentity(); try { Loading @@ -1244,7 +1305,11 @@ public final class CameraManager { new Runnable() { @Override public void run() { if (physicalId == null) { callback.onCameraAvailable(id); } else { callback.onPhysicalCameraAvailable(id, physicalId); } } }); } finally { Loading @@ -1257,7 +1322,11 @@ public final class CameraManager { new Runnable() { @Override public void run() { if (physicalId == null) { callback.onCameraUnavailable(id); } else { callback.onPhysicalCameraUnavailable(id, physicalId); } } }); } finally { Loading Loading @@ -1304,7 +1373,16 @@ public final class CameraManager { for (int i = 0; i < mDeviceStatus.size(); i++) { String id = mDeviceStatus.keyAt(i); Integer status = mDeviceStatus.valueAt(i); postSingleUpdate(callback, executor, id, status); postSingleUpdate(callback, executor, id, null /*physicalId*/, status); // Send the NOT_PRESENT state for unavailable physical cameras if (isAvailable(status) && mUnavailablePhysicalDevices.containsKey(id)) { ArrayList<String> unavailableIds = mUnavailablePhysicalDevices.get(id); for (String unavailableId : unavailableIds) { postSingleUpdate(callback, executor, id, unavailableId, ICameraServiceListener.STATUS_NOT_PRESENT); } } } } Loading @@ -1323,8 +1401,12 @@ public final class CameraManager { Integer oldStatus; if (status == ICameraServiceListener.STATUS_NOT_PRESENT) { oldStatus = mDeviceStatus.remove(id); mUnavailablePhysicalDevices.remove(id); } else { oldStatus = mDeviceStatus.put(id, status); if (oldStatus == null) { mUnavailablePhysicalDevices.put(id, new ArrayList<String>()); } } if (oldStatus != null && oldStatus == status) { Loading Loading @@ -1366,10 +1448,62 @@ public final class CameraManager { Executor executor = mCallbackMap.valueAt(i); final AvailabilityCallback callback = mCallbackMap.keyAt(i); postSingleUpdate(callback, executor, id, status); postSingleUpdate(callback, executor, id, null /*physicalId*/, status); } } // onStatusChangedLocked private void onPhysicalCameraStatusChangedLocked(int status, String id, String physicalId) { if (DEBUG) { Log.v(TAG, String.format("Camera id %s physical camera id %s has status " + "changed to 0x%x", id, physicalId, status)); } if (!validStatus(status)) { Log.e(TAG, String.format( "Ignoring invalid device %s physical device %s status 0x%x", id, physicalId, status)); return; } //TODO: Do we need to treat this as error? if (!mDeviceStatus.containsKey(id) || !isAvailable(mDeviceStatus.get(id)) || !mUnavailablePhysicalDevices.containsKey(id)) { Log.e(TAG, String.format("Camera %s is not available. Ignore physical camera " + "status change", id)); return; } ArrayList<String> unavailablePhysicalDevices = mUnavailablePhysicalDevices.get(id); if (!isAvailable(status) && !unavailablePhysicalDevices.contains(physicalId)) { unavailablePhysicalDevices.add(physicalId); } else if (isAvailable(status) && unavailablePhysicalDevices.contains(physicalId)) { unavailablePhysicalDevices.remove(physicalId); } else { if (DEBUG) { Log.v(TAG, String.format( "Physical camera device status was previously available (%b), " + " and is now again available (%b)" + "so no new client visible update will be sent", !unavailablePhysicalDevices.contains(physicalId), isAvailable(status))); } return; } final int callbackCount = mCallbackMap.size(); for (int i = 0; i < callbackCount; i++) { Executor executor = mCallbackMap.valueAt(i); final AvailabilityCallback callback = mCallbackMap.keyAt(i); postSingleUpdate(callback, executor, id, physicalId, status); } } // onPhysicalCameraStatusChangedLocked private void updateTorchCallbackLocked(TorchCallback callback, Executor executor) { for (int i = 0; i < mTorchStatus.size(); i++) { String id = mTorchStatus.keyAt(i); Loading Loading @@ -1477,6 +1611,14 @@ public final class CameraManager { } } @Override public void onPhysicalCameraStatusChanged(int status, String cameraId, String physicalCameraId) throws RemoteException { synchronized (mLock) { onPhysicalCameraStatusChangedLocked(status, cameraId, physicalCameraId); } } @Override public void onTorchStatusChanged(int status, String cameraId) throws RemoteException { synchronized (mLock) { Loading core/java/android/hardware/camera2/CameraMetadata.java +13 −7 Original line number Diff line number Diff line Loading @@ -865,14 +865,20 @@ public abstract class CameraMetadata<TKey> { * <p>The camera device is a logical camera backed by two or more physical cameras.</p> * <p>In API level 28, the physical cameras must also be exposed to the application via * {@link android.hardware.camera2.CameraManager#getCameraIdList }.</p> * <p>Starting from API level 29, some or all physical cameras may not be independently * exposed to the application, in which case the physical camera IDs will not be * available in {@link android.hardware.camera2.CameraManager#getCameraIdList }. But the * <p>Starting from API level 29:</p> * <ul> * <li>Some or all physical cameras may not be independently exposed to the application, * in which case the physical camera IDs will not be available in * {@link android.hardware.camera2.CameraManager#getCameraIdList }. But the * application can still query the physical cameras' characteristics by calling * {@link android.hardware.camera2.CameraManager#getCameraCharacteristics }. Additionally, * if a physical camera is hidden from camera ID list, the mandatory stream combinations * for that physical camera must be supported through the logical camera using physical * streams.</p> * {@link android.hardware.camera2.CameraManager#getCameraCharacteristics }.</li> * <li>If a physical camera is hidden from camera ID list, the mandatory stream * combinations for that physical camera must be supported through the logical camera * using physical streams. One exception is that in API level 30, a physical camera * may become unavailable via * {@link CameraManager.AvailabilityCallback#onPhysicalCameraUnavailable } * callback.</li> * </ul> * <p>Combinations of logical and physical streams, or physical streams from different * physical cameras are not guaranteed. However, if the camera device supports * {@link CameraDevice#isSessionConfigurationSupported }, Loading media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraBinderTest.java +6 −0 Original line number Diff line number Diff line Loading @@ -311,6 +311,12 @@ public class CameraBinderTest extends AndroidTestCase { cameraId, status)); } @Override public void onPhysicalCameraStatusChanged(int status, String cameraId, String physicalCameraId) throws RemoteException { Log.v(TAG, String.format("Camera %s : %s has status changed to 0x%x", cameraId, physicalCameraId, status)); } @Override public void onCameraAccessPrioritiesChanged() { Log.v(TAG, "Camera access permission change"); } Loading Loading
api/current.txt +2 −0 Original line number Diff line number Diff line Loading @@ -17259,6 +17259,8 @@ package android.hardware.camera2 { method public void onCameraAccessPrioritiesChanged(); method public void onCameraAvailable(@NonNull String); method public void onCameraUnavailable(@NonNull String); method public void onPhysicalCameraAvailable(@NonNull String, @NonNull String); method public void onPhysicalCameraUnavailable(@NonNull String, @NonNull String); } public abstract static class CameraManager.TorchCallback {
core/java/android/hardware/CameraStatus.java +3 −0 Original line number Diff line number Diff line Loading @@ -30,6 +30,7 @@ import android.os.Parcelable; public class CameraStatus implements Parcelable { public String cameraId; public int status; public String[] unavailablePhysicalCameras; @Override public int describeContents() { Loading @@ -40,11 +41,13 @@ public class CameraStatus implements Parcelable { public void writeToParcel(Parcel out, int flags) { out.writeString(cameraId); out.writeInt(status); out.writeStringArray(unavailablePhysicalCameras); } public void readFromParcel(Parcel in) { cameraId = in.readString(); status = in.readInt(); unavailablePhysicalCameras = in.readStringArray(); } public static final @android.annotation.NonNull Parcelable.Creator<CameraStatus> CREATOR = Loading
core/java/android/hardware/camera2/CameraManager.java +147 −5 Original line number Diff line number Diff line Loading @@ -718,6 +718,52 @@ public final class CameraManager { public void onCameraAccessPrioritiesChanged() { // default empty implementation } /** * A physical camera has become available for use again. * * <p>By default, all of the physical cameras of a logical multi-camera are * available, so {@link #onPhysicalCameraAvailable} is not called for any of the physical * cameras of a logical multi-camera, when {@link #onCameraAvailable} for the logical * multi-camera is invoked. However, if some specific physical cameras are unavailable * to begin with, {@link #onPhysicalCameraUnavailable} may be invoked after * {@link #onCameraAvailable}.</p> * * <p>The default implementation of this method does nothing.</p> * * @param cameraId The unique identifier of the logical multi-camera. * @param physicalCameraId The unique identifier of the physical camera. * * @see #onCameraAvailable * @see #onPhysicalCameraUnavailable */ public void onPhysicalCameraAvailable(@NonNull String cameraId, @NonNull String physicalCameraId) { // default empty implementation } /** * A previously-available physical camera has become unavailable for use. * * <p>By default, all of the physical cameras of a logical multi-camera are * available, so {@link #onPhysicalCameraAvailable} is not called for any of the physical * cameras of a logical multi-camera, when {@link #onCameraAvailable} for the logical * multi-camera is invoked. If some specific physical cameras are unavailable * to begin with, {@link #onPhysicalCameraUnavailable} may be invoked after * {@link #onCameraAvailable}.</p> * * <p>The default implementation of this method does nothing.</p> * * @param cameraId The unique identifier of the logical multi-camera. * @param physicalCameraId The unique identifier of the physical camera. * * @see #onCameraAvailable * @see #onPhysicalCameraAvailable */ public void onPhysicalCameraUnavailable(@NonNull String cameraId, @NonNull String physicalCameraId) { // default empty implementation } } /** Loading Loading @@ -914,6 +960,9 @@ public final class CameraManager { private final ScheduledExecutorService mScheduler = Executors.newScheduledThreadPool(1); // Camera ID -> Status map private final ArrayMap<String, Integer> mDeviceStatus = new ArrayMap<String, Integer>(); // Camera ID -> (physical camera ID -> Status map) private final ArrayMap<String, ArrayList<String>> mUnavailablePhysicalDevices = new ArrayMap<String, ArrayList<String>>(); // Registered availablility callbacks and their executors private final ArrayMap<AvailabilityCallback, Executor> mCallbackMap = Loading Loading @@ -1003,6 +1052,14 @@ public final class CameraManager { CameraStatus[] cameraStatuses = cameraService.addListener(this); for (CameraStatus c : cameraStatuses) { onStatusChangedLocked(c.status, c.cameraId); if (c.unavailablePhysicalCameras != null) { for (String unavailPhysicalCamera : c.unavailablePhysicalCameras) { onPhysicalCameraStatusChangedLocked( ICameraServiceListener.STATUS_NOT_PRESENT, c.cameraId, unavailPhysicalCamera); } } } mCameraService = cameraService; } catch(ServiceSpecificException e) { Loading Loading @@ -1086,6 +1143,10 @@ public final class CameraManager { public void onStatusChanged(int status, String id) throws RemoteException { } @Override public void onPhysicalCameraStatusChanged(int status, String id, String physicalId) throws RemoteException { } @Override public void onTorchStatusChanged(int status, String id) throws RemoteException { } @Override Loading Loading @@ -1236,7 +1297,7 @@ public final class CameraManager { } private void postSingleUpdate(final AvailabilityCallback callback, final Executor executor, final String id, final int status) { final String id, final String physicalId, final int status) { if (isAvailable(status)) { final long ident = Binder.clearCallingIdentity(); try { Loading @@ -1244,7 +1305,11 @@ public final class CameraManager { new Runnable() { @Override public void run() { if (physicalId == null) { callback.onCameraAvailable(id); } else { callback.onPhysicalCameraAvailable(id, physicalId); } } }); } finally { Loading @@ -1257,7 +1322,11 @@ public final class CameraManager { new Runnable() { @Override public void run() { if (physicalId == null) { callback.onCameraUnavailable(id); } else { callback.onPhysicalCameraUnavailable(id, physicalId); } } }); } finally { Loading Loading @@ -1304,7 +1373,16 @@ public final class CameraManager { for (int i = 0; i < mDeviceStatus.size(); i++) { String id = mDeviceStatus.keyAt(i); Integer status = mDeviceStatus.valueAt(i); postSingleUpdate(callback, executor, id, status); postSingleUpdate(callback, executor, id, null /*physicalId*/, status); // Send the NOT_PRESENT state for unavailable physical cameras if (isAvailable(status) && mUnavailablePhysicalDevices.containsKey(id)) { ArrayList<String> unavailableIds = mUnavailablePhysicalDevices.get(id); for (String unavailableId : unavailableIds) { postSingleUpdate(callback, executor, id, unavailableId, ICameraServiceListener.STATUS_NOT_PRESENT); } } } } Loading @@ -1323,8 +1401,12 @@ public final class CameraManager { Integer oldStatus; if (status == ICameraServiceListener.STATUS_NOT_PRESENT) { oldStatus = mDeviceStatus.remove(id); mUnavailablePhysicalDevices.remove(id); } else { oldStatus = mDeviceStatus.put(id, status); if (oldStatus == null) { mUnavailablePhysicalDevices.put(id, new ArrayList<String>()); } } if (oldStatus != null && oldStatus == status) { Loading Loading @@ -1366,10 +1448,62 @@ public final class CameraManager { Executor executor = mCallbackMap.valueAt(i); final AvailabilityCallback callback = mCallbackMap.keyAt(i); postSingleUpdate(callback, executor, id, status); postSingleUpdate(callback, executor, id, null /*physicalId*/, status); } } // onStatusChangedLocked private void onPhysicalCameraStatusChangedLocked(int status, String id, String physicalId) { if (DEBUG) { Log.v(TAG, String.format("Camera id %s physical camera id %s has status " + "changed to 0x%x", id, physicalId, status)); } if (!validStatus(status)) { Log.e(TAG, String.format( "Ignoring invalid device %s physical device %s status 0x%x", id, physicalId, status)); return; } //TODO: Do we need to treat this as error? if (!mDeviceStatus.containsKey(id) || !isAvailable(mDeviceStatus.get(id)) || !mUnavailablePhysicalDevices.containsKey(id)) { Log.e(TAG, String.format("Camera %s is not available. Ignore physical camera " + "status change", id)); return; } ArrayList<String> unavailablePhysicalDevices = mUnavailablePhysicalDevices.get(id); if (!isAvailable(status) && !unavailablePhysicalDevices.contains(physicalId)) { unavailablePhysicalDevices.add(physicalId); } else if (isAvailable(status) && unavailablePhysicalDevices.contains(physicalId)) { unavailablePhysicalDevices.remove(physicalId); } else { if (DEBUG) { Log.v(TAG, String.format( "Physical camera device status was previously available (%b), " + " and is now again available (%b)" + "so no new client visible update will be sent", !unavailablePhysicalDevices.contains(physicalId), isAvailable(status))); } return; } final int callbackCount = mCallbackMap.size(); for (int i = 0; i < callbackCount; i++) { Executor executor = mCallbackMap.valueAt(i); final AvailabilityCallback callback = mCallbackMap.keyAt(i); postSingleUpdate(callback, executor, id, physicalId, status); } } // onPhysicalCameraStatusChangedLocked private void updateTorchCallbackLocked(TorchCallback callback, Executor executor) { for (int i = 0; i < mTorchStatus.size(); i++) { String id = mTorchStatus.keyAt(i); Loading Loading @@ -1477,6 +1611,14 @@ public final class CameraManager { } } @Override public void onPhysicalCameraStatusChanged(int status, String cameraId, String physicalCameraId) throws RemoteException { synchronized (mLock) { onPhysicalCameraStatusChangedLocked(status, cameraId, physicalCameraId); } } @Override public void onTorchStatusChanged(int status, String cameraId) throws RemoteException { synchronized (mLock) { Loading
core/java/android/hardware/camera2/CameraMetadata.java +13 −7 Original line number Diff line number Diff line Loading @@ -865,14 +865,20 @@ public abstract class CameraMetadata<TKey> { * <p>The camera device is a logical camera backed by two or more physical cameras.</p> * <p>In API level 28, the physical cameras must also be exposed to the application via * {@link android.hardware.camera2.CameraManager#getCameraIdList }.</p> * <p>Starting from API level 29, some or all physical cameras may not be independently * exposed to the application, in which case the physical camera IDs will not be * available in {@link android.hardware.camera2.CameraManager#getCameraIdList }. But the * <p>Starting from API level 29:</p> * <ul> * <li>Some or all physical cameras may not be independently exposed to the application, * in which case the physical camera IDs will not be available in * {@link android.hardware.camera2.CameraManager#getCameraIdList }. But the * application can still query the physical cameras' characteristics by calling * {@link android.hardware.camera2.CameraManager#getCameraCharacteristics }. Additionally, * if a physical camera is hidden from camera ID list, the mandatory stream combinations * for that physical camera must be supported through the logical camera using physical * streams.</p> * {@link android.hardware.camera2.CameraManager#getCameraCharacteristics }.</li> * <li>If a physical camera is hidden from camera ID list, the mandatory stream * combinations for that physical camera must be supported through the logical camera * using physical streams. One exception is that in API level 30, a physical camera * may become unavailable via * {@link CameraManager.AvailabilityCallback#onPhysicalCameraUnavailable } * callback.</li> * </ul> * <p>Combinations of logical and physical streams, or physical streams from different * physical cameras are not guaranteed. However, if the camera device supports * {@link CameraDevice#isSessionConfigurationSupported }, Loading
media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraBinderTest.java +6 −0 Original line number Diff line number Diff line Loading @@ -311,6 +311,12 @@ public class CameraBinderTest extends AndroidTestCase { cameraId, status)); } @Override public void onPhysicalCameraStatusChanged(int status, String cameraId, String physicalCameraId) throws RemoteException { Log.v(TAG, String.format("Camera %s : %s has status changed to 0x%x", cameraId, physicalCameraId, status)); } @Override public void onCameraAccessPrioritiesChanged() { Log.v(TAG, "Camera access permission change"); } Loading