diff --git a/core/api/current.txt b/core/api/current.txt index cc8b638d2e599..e06f87fdd78a2 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -18482,6 +18482,7 @@ package android.hardware.camera2 { method @NonNull public android.hardware.camera2.CameraExtensionCharacteristics getCameraExtensionCharacteristics(@NonNull String) throws android.hardware.camera2.CameraAccessException; method @NonNull public String[] getCameraIdList() throws android.hardware.camera2.CameraAccessException; method @NonNull public java.util.Set> getConcurrentCameraIds() throws android.hardware.camera2.CameraAccessException; + method public int getTorchStrengthLevel(@NonNull String) throws android.hardware.camera2.CameraAccessException; method @RequiresPermission(android.Manifest.permission.CAMERA) public boolean isConcurrentSessionConfigurationSupported(@NonNull java.util.Map) throws android.hardware.camera2.CameraAccessException; method @RequiresPermission(android.Manifest.permission.CAMERA) public void openCamera(@NonNull String, @NonNull android.hardware.camera2.CameraDevice.StateCallback, @Nullable android.os.Handler) throws android.hardware.camera2.CameraAccessException; method @RequiresPermission(android.Manifest.permission.CAMERA) public void openCamera(@NonNull String, @NonNull java.util.concurrent.Executor, @NonNull android.hardware.camera2.CameraDevice.StateCallback) throws android.hardware.camera2.CameraAccessException; @@ -18490,6 +18491,7 @@ package android.hardware.camera2 { method public void registerTorchCallback(@NonNull android.hardware.camera2.CameraManager.TorchCallback, @Nullable android.os.Handler); method public void registerTorchCallback(@NonNull java.util.concurrent.Executor, @NonNull android.hardware.camera2.CameraManager.TorchCallback); method public void setTorchMode(@NonNull String, boolean) throws android.hardware.camera2.CameraAccessException; + method public void turnOnTorchWithStrengthLevel(@NonNull String, int) throws android.hardware.camera2.CameraAccessException; method public void unregisterAvailabilityCallback(@NonNull android.hardware.camera2.CameraManager.AvailabilityCallback); method public void unregisterTorchCallback(@NonNull android.hardware.camera2.CameraManager.TorchCallback); } @@ -18507,6 +18509,7 @@ package android.hardware.camera2 { ctor public CameraManager.TorchCallback(); method public void onTorchModeChanged(@NonNull String, boolean); method public void onTorchModeUnavailable(@NonNull String); + method public void onTorchStrengthLevelChanged(@NonNull String, int); } public abstract class CameraMetadata { diff --git a/core/java/android/hardware/camera2/CameraManager.java b/core/java/android/hardware/camera2/CameraManager.java index 93f1d615b98bb..c12e8195eeb45 100644 --- a/core/java/android/hardware/camera2/CameraManager.java +++ b/core/java/android/hardware/camera2/CameraManager.java @@ -1035,6 +1035,95 @@ public final class CameraManager { CameraManagerGlobal.get().setTorchMode(cameraId, enabled); } + /** + * Set the brightness level of the flashlight associated with the given cameraId in torch + * mode. If the torch is OFF and torchStrength is >= 1, torch will turn ON with the + * strength level specified in torchStrength. + * + *

Use + * {@link android.hardware.camera2.CameraCharacteristics#FLASH_INFO_STRENGTH_MAXIMUM_LEVEL} + * to check whether the camera device supports flash unit strength control or not. If this value + * is greater than 1, applications can call this API to control the flashlight brightness level. + *

+ * + *

If {@link #turnOnTorchWithStrengthLevel} is called to change the brightness level of the + * flash unit {@link CameraManager.TorchCallback#onTorchStrengthLevelChanged} will be invoked. + * If the new desired strength level is same as previously set level, then this callback will + * not be invoked. + * If the torch is OFF and {@link #turnOnTorchWithStrengthLevel} is called with level >= 1, + * the torch will be turned ON with that brightness level. In this case + * {@link CameraManager.TorchCallback#onTorchModeChanged} will also be invoked. + *

+ * + *

When the torch is turned OFF via {@link #setTorchMode}, the flashlight brightness level + * will reset to default value + * {@link android.hardware.camera2.CameraCharacteristics#FLASH_INFO_STRENGTH_DEFAULT_LEVEL} + * In this case the {@link CameraManager.TorchCallback#onTorchStrengthLevelChanged} will not be + * invoked. + *

+ * + *

If torch is enabled via {@link #setTorchMode} after calling + * {@link #turnOnTorchWithStrengthLevel} with level N then the flash unit will have the + * brightness level N. + * Since multiple applications are free to call {@link #setTorchMode}, when the latest + * application that turned ON the torch mode exits, the torch mode will be turned OFF + * and in this case the brightness level will reset to default level. + *

+ * + * @param cameraId + * The unique identifier of the camera device that the flash unit belongs to. + * @param torchStrength + * The desired brightness level to be set for the flash unit in the range 1 to + * {@link android.hardware.camera2.CameraCharacteristics#FLASH_INFO_STRENGTH_MAXIMUM_LEVEL}. + * + * @throws CameraAccessException if it failed to access the flash unit. + * {@link CameraAccessException#CAMERA_IN_USE} will be thrown if the camera device + * is in use. {@link CameraAccessException#MAX_CAMERAS_IN_USE} will be thrown if + * other camera resources needed to turn on the torch mode are in use. + * {@link CameraAccessException#CAMERA_DISCONNECTED} will be thrown if camera + * service is not available. + * @throws IllegalArgumentException if cameraId was null, cameraId doesn't match any currently + * or previously available camera device, the camera device doesn't have a + * flash unit or if torchStrength is not within the range i.e. is greater than + * the maximum level + * {@link android.hardware.camera2.CameraCharacteristics#FLASH_INFO_STRENGTH_MAXIMUM_LEVEL} + * or <= 0. + * + */ + public void turnOnTorchWithStrengthLevel(@NonNull String cameraId, int torchStrength) + throws CameraAccessException { + if (CameraManagerGlobal.sCameraServiceDisabled) { + throw new IllegalArgumentException("No camera available on device"); + } + CameraManagerGlobal.get().turnOnTorchWithStrengthLevel(cameraId, torchStrength); + } + + /** + * Returns the brightness level of the flash unit associated with the cameraId. + * + * @param cameraId + * The unique identifier of the camera device that the flash unit belongs to. + * @return The brightness level of the flash unit associated with cameraId. + * When the torch is turned OFF, the strength level will reset to a default level + * {@link android.hardware.camera2.CameraCharacteristics#FLASH_INFO_STRENGTH_DEFAULT_LEVEL}. + * In this case the return value will be + * {@link android.hardware.camera2.CameraCharacteristics#FLASH_INFO_STRENGTH_DEFAULT_LEVEL} + * rather than 0. + * + * @throws CameraAccessException if it failed to access the flash unit. + * @throws IllegalArgumentException if cameraId was null, cameraId doesn't match any currently + * or previously available camera device, or the camera device doesn't have a + * flash unit. + * + */ + public int getTorchStrengthLevel(@NonNull String cameraId) + throws CameraAccessException { + if (CameraManagerGlobal.sCameraServiceDisabled) { + throw new IllegalArgumentException("No camera available on device."); + } + return CameraManagerGlobal.get().getTorchStrengthLevel(cameraId); + } + /** * A callback for camera devices becoming available or unavailable to open. * @@ -1239,6 +1328,24 @@ public final class CameraManager { public void onTorchModeChanged(@NonNull String cameraId, boolean enabled) { // default empty implementation } + + /** + * A camera's flash unit brightness level has been changed in torch mode via + * {@link #turnOnTorchWithStrengthLevel}. When the torch is turned OFF, this + * callback will not be triggered even though the torch strength level resets to + * default value + * {@link android.hardware.camera2.CameraCharacteristics#FLASH_INFO_STRENGTH_DEFAULT_LEVEL} + * + *

The default implementation of this method does nothing.

+ * + * @param cameraId The unique identifier of the camera whose flash unit brightness level has + * been changed. + * + * @param newStrengthLevel The brightness level of the flash unit that has been changed to. + */ + public void onTorchStrengthLevelChanged(@NonNull String cameraId, int newStrengthLevel) { + // default empty implementation + } } /** @@ -1642,6 +1749,10 @@ public final class CameraManager { public void onTorchStatusChanged(int status, String id) throws RemoteException { } @Override + public void onTorchStrengthLevelChanged(String id, int newStrengthLevel) + throws RemoteException { + } + @Override public void onCameraAccessPrioritiesChanged() { } @Override @@ -1825,6 +1936,57 @@ public final class CameraManager { } } + public void turnOnTorchWithStrengthLevel(String cameraId, int torchStrength) throws + CameraAccessException { + synchronized(mLock) { + + if (cameraId == null) { + throw new IllegalArgumentException("cameraId was null"); + } + + ICameraService cameraService = getCameraService(); + if (cameraService == null) { + throw new CameraAccessException(CameraAccessException.CAMERA_DISCONNECTED, + "Camera service is currently unavailable."); + } + + try { + cameraService.turnOnTorchWithStrengthLevel(cameraId, torchStrength, + mTorchClientBinder); + } catch(ServiceSpecificException e) { + throwAsPublicException(e); + } catch (RemoteException e) { + throw new CameraAccessException(CameraAccessException.CAMERA_DISCONNECTED, + "Camera service is currently unavailable."); + } + } + } + + public int getTorchStrengthLevel(String cameraId) throws CameraAccessException { + int torchStrength = 0; + synchronized(mLock) { + if (cameraId == null) { + throw new IllegalArgumentException("cameraId was null"); + } + + ICameraService cameraService = getCameraService(); + if (cameraService == null) { + throw new CameraAccessException(CameraAccessException.CAMERA_DISCONNECTED, + "Camera service is currently unavailable."); + } + + try { + torchStrength = cameraService.getTorchStrengthLevel(cameraId); + } catch(ServiceSpecificException e) { + throwAsPublicException(e); + } catch (RemoteException e) { + throw new CameraAccessException(CameraAccessException.CAMERA_DISCONNECTED, + "Camera service is currently unavailable."); + } + } + return torchStrength; + } + private void handleRecoverableSetupErrors(ServiceSpecificException e) { switch (e.errorCode) { case ICameraService.ERROR_DISCONNECTED: @@ -1984,6 +2146,18 @@ public final class CameraManager { } } + private void postSingleTorchStrengthLevelUpdate(final TorchCallback callback, + final Executor executor, final String id, final int newStrengthLevel) { + final long ident = Binder.clearCallingIdentity(); + try { + executor.execute(() -> { + callback.onTorchStrengthLevelChanged(id, newStrengthLevel); + }); + } finally { + Binder.restoreCallingIdentity(ident); + } + } + /** * Send the state of all known cameras to the provided listener, to initialize * the listener's knowledge of camera state. @@ -2167,6 +2341,22 @@ public final class CameraManager { } } // onTorchStatusChangedLocked + private void onTorchStrengthLevelChangedLocked(String cameraId, int newStrengthLevel) { + if (DEBUG) { + + Log.v(TAG, + String.format("Camera id %s has torch strength level changed to %d", + cameraId, newStrengthLevel)); + } + + final int callbackCount = mTorchCallbackMap.size(); + for (int i = 0; i < callbackCount; i++) { + final Executor executor = mTorchCallbackMap.valueAt(i); + final TorchCallback callback = mTorchCallbackMap.keyAt(i); + postSingleTorchStrengthLevelUpdate(callback, executor, cameraId, newStrengthLevel); + } + } // onTorchStrengthLevelChanged + /** * Register a callback to be notified about camera device availability with the * global listener singleton. @@ -2257,6 +2447,14 @@ public final class CameraManager { } } + @Override + public void onTorchStrengthLevelChanged(String cameraId, int newStrengthLevel) + throws RemoteException { + synchronized (mLock) { + onTorchStrengthLevelChangedLocked(cameraId, newStrengthLevel); + } + } + @Override public void onCameraAccessPrioritiesChanged() { synchronized (mLock) { diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraBinderTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraBinderTest.java index 6dc05ad010e6a..a2eae2c9579a7 100644 --- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraBinderTest.java +++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraBinderTest.java @@ -303,6 +303,11 @@ public class CameraBinderTest extends AndroidTestCase { public void onCameraClosed(String cameraId) { Log.v(TAG, String.format("Camera %s is closed", cameraId)); } + @Override + public void onTorchStrengthLevelChanged(String cameraId, int torchStrength) { + Log.v(TAG, String.format("Camera " + cameraId + " torch strength level changed to " + + torchStrength )); + } } /**