diff options
author | android-build-prod (mdb) <android-build-team-robot@google.com> | 2021-04-09 07:43:46 +0000 |
---|---|---|
committer | Gerrit Code Review <noreply-gerritcodereview@google.com> | 2021-04-09 07:43:46 +0000 |
commit | a9afbafa874d82fe037dbf6680c20d84624592eb (patch) | |
tree | 8954fbf27fd069b998a925927725381b01faa383 | |
parent | 17893f7667cf39bc1e94f77b6ad55cd10987594b (diff) | |
parent | 3bc7b0501ed9c52cf64e6084a4a67fd9213f7eac (diff) | |
download | support-snap-temp-L12800000867760435.tar.gz |
Merge "Merge cherrypicks of [1671245, 1671246] into androidx-camera-release" into androidx-camera-releasesnap-temp-L76800000867674383snap-temp-L12800000867760435
4 files changed, 121 insertions, 10 deletions
diff --git a/buildSrc/src/main/kotlin/androidx/build/LibraryVersions.kt b/buildSrc/src/main/kotlin/androidx/build/LibraryVersions.kt index a866bb76396..c7f0fb6a80a 100644 --- a/buildSrc/src/main/kotlin/androidx/build/LibraryVersions.kt +++ b/buildSrc/src/main/kotlin/androidx/build/LibraryVersions.kt @@ -35,7 +35,7 @@ object LibraryVersions { val BIOMETRIC = Version("1.2.0-alpha02") val BROWSER = Version("1.3.0-rc01") val BUILDSRC_TESTS = Version("1.0.0-alpha01") - val CAMERA = Version("1.0.0-rc04") + val CAMERA = Version("1.0.0-rc05") val CAMERA_EXTENSIONS = Version("1.0.0-alpha22") val CAMERA_PIPE = Version("1.0.0-alpha01") val CAMERA_VIDEO = Version("1.0.0-alpha01") diff --git a/camera/camera-core/src/main/java/androidx/camera/core/ImageCapture.java b/camera/camera-core/src/main/java/androidx/camera/core/ImageCapture.java index 442ea68b1b6..e100a24ea8c 100644 --- a/camera/camera-core/src/main/java/androidx/camera/core/ImageCapture.java +++ b/camera/camera-core/src/main/java/androidx/camera/core/ImageCapture.java @@ -112,6 +112,8 @@ import androidx.camera.core.impl.utils.futures.Futures; import androidx.camera.core.internal.IoConfig; import androidx.camera.core.internal.TargetConfig; import androidx.camera.core.internal.YuvToJpegProcessor; +import androidx.camera.core.internal.compat.quirk.DeviceQuirks; +import androidx.camera.core.internal.compat.quirk.ImageCaptureWashedOutImageQuirk; import androidx.camera.core.internal.compat.quirk.SoftwareJpegEncodingPreferredQuirk; import androidx.camera.core.internal.compat.workaround.ExifRotationAvailability; import androidx.camera.core.internal.utils.ImageUtil; @@ -300,6 +302,14 @@ public final class ImageCapture extends UseCase { */ private boolean mUseSoftwareJpeg = false; + /** + * Whether the torch flash will be used. + * + * <p>When the flag is set, torch will be opened and closed to replace the flash fired by flash + * mode. + */ + private final boolean mUseTorchFlash; + //////////////////////////////////////////////////////////////////////////////////////////// // [UseCase attached dynamic] - Can change but is only available when the UseCase is attached. //////////////////////////////////////////////////////////////////////////////////////////// @@ -348,6 +358,11 @@ public final class ImageCapture extends UseCase { } else { mEnableCheck3AConverged = false; // skip 3A convergence in MIN_LATENCY mode } + + mUseTorchFlash = DeviceQuirks.get(ImageCaptureWashedOutImageQuirk.class) != null; + if (mUseTorchFlash) { + Logger.d(TAG, "Open and close torch to replace the flash fired by flash mode."); + } } @UiThread @@ -1304,9 +1319,12 @@ public final class ImageCapture extends UseCase { .transformAsync(captureResult -> { state.mPreCaptureState = captureResult; triggerAfIfNeeded(state); - if (isAePrecaptureRequired(state)) { - // trigger AE precapture and await the result. - return triggerAePrecapture(state); + if (isFlashRequired(state)) { + if (mUseTorchFlash) { + return openTorch(state); + } else { + return triggerAePrecapture(state); + } } return Futures.immediateFuture(null); }, mExecutor) @@ -1321,10 +1339,37 @@ public final class ImageCapture extends UseCase { * <p>For example, cancel 3A scan, close torch if necessary. */ void postTakePicture(final TakePictureState state) { + closeTorch(state); cancelAfAeTrigger(state); unlockFlashMode(); } + @NonNull + private ListenableFuture<Void> openTorch(@NonNull TakePictureState state) { + CameraInternal camera = getCamera(); + if (camera != null && camera.getCameraInfo().getTorchState().getValue() == TorchState.ON) { + // Torch is already opened. + return Futures.immediateFuture(null); + } + + Logger.d(TAG, "openTorch"); + + // Create a new future in order to ignore any fail from CameraControl.enableTorch(). + return CallbackToFutureAdapter.getFuture(completer -> { + getCameraControl().enableTorch(state.mIsTorchOpened = true).addListener( + () -> completer.set(null), CameraXExecutors.directExecutor()); + return "openTorch"; + }); + } + + private void closeTorch(@NonNull TakePictureState state) { + if (state.mIsTorchOpened) { + // Add listener to avoid FutureReturnValueIgnored error. + getCameraControl().enableTorch(state.mIsTorchOpened = false).addListener(() -> { + }, CameraXExecutors.directExecutor()); + } + } + /** * Gets a capture result or not according to current configuration. * @@ -1357,7 +1402,7 @@ public final class ImageCapture extends UseCase { return Futures.immediateFuture(null); } - boolean isAePrecaptureRequired(TakePictureState state) { + boolean isFlashRequired(@NonNull TakePictureState state) { switch (getFlashMode()) { case FLASH_MODE_ON: return true; @@ -1370,9 +1415,7 @@ public final class ImageCapture extends UseCase { } ListenableFuture<Boolean> check3AConverged(TakePictureState state) { - // Skip the 3A converged check if enableCheck3AConverged is false and AE precapture is - // not triggered. - if (!mEnableCheck3AConverged && !state.mIsAePrecaptureTriggered) { + if (!mEnableCheck3AConverged && !state.mIsAePrecaptureTriggered && !state.mIsTorchOpened) { return Futures.immediateFuture(false); } @@ -1451,10 +1494,12 @@ public final class ImageCapture extends UseCase { } /** Issues a request to start auto exposure scan. */ - ListenableFuture<CameraCaptureResult> triggerAePrecapture(TakePictureState state) { + ListenableFuture<Void> triggerAePrecapture(TakePictureState state) { Logger.d(TAG, "triggerAePrecapture"); state.mIsAePrecaptureTriggered = true; - return getCameraControl().triggerAePrecapture(); + // Transform type from CameraCaptureResult to Void + return Futures.transform(getCameraControl().triggerAePrecapture(), captureResult -> null, + CameraXExecutors.directExecutor()); } /** Issues a request to cancel auto focus and/or auto exposure scan. */ @@ -2045,6 +2090,7 @@ public final class ImageCapture extends UseCase { */ static final class TakePictureState { CameraCaptureResult mPreCaptureState = EmptyCameraCaptureResult.create(); + boolean mIsTorchOpened = false; boolean mIsAfTriggered = false; boolean mIsAePrecaptureTriggered = false; } diff --git a/camera/camera-core/src/main/java/androidx/camera/core/internal/compat/quirk/DeviceQuirksLoader.java b/camera/camera-core/src/main/java/androidx/camera/core/internal/compat/quirk/DeviceQuirksLoader.java index 0a15ab7d60b..debf4f3f6c6 100644 --- a/camera/camera-core/src/main/java/androidx/camera/core/internal/compat/quirk/DeviceQuirksLoader.java +++ b/camera/camera-core/src/main/java/androidx/camera/core/internal/compat/quirk/DeviceQuirksLoader.java @@ -47,6 +47,10 @@ public class DeviceQuirksLoader { quirks.add(new ImageCaptureRotationOptionQuirk()); } + if (ImageCaptureWashedOutImageQuirk.load()) { + quirks.add(new ImageCaptureWashedOutImageQuirk()); + } + return quirks; } } diff --git a/camera/camera-core/src/main/java/androidx/camera/core/internal/compat/quirk/ImageCaptureWashedOutImageQuirk.java b/camera/camera-core/src/main/java/androidx/camera/core/internal/compat/quirk/ImageCaptureWashedOutImageQuirk.java new file mode 100644 index 00000000000..62fa918ea57 --- /dev/null +++ b/camera/camera-core/src/main/java/androidx/camera/core/internal/compat/quirk/ImageCaptureWashedOutImageQuirk.java @@ -0,0 +1,61 @@ +/* + * Copyright 2021 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 androidx.camera.core.internal.compat.quirk; + +import android.os.Build; + +import androidx.camera.core.impl.Quirk; + +import java.util.Arrays; +import java.util.List; +import java.util.Locale; + +/** + * Quirk that prevents from getting washed out image while taking picture with flash ON/AUTO mode. + * + * <p>See b/176399765 and b/181966663. + */ +public class ImageCaptureWashedOutImageQuirk implements Quirk { + + // List of devices with the issue. See b/181966663. + private static final List<String> DEVICE_MODELS = Arrays.asList( + // Galaxy S7 + "SM-G9300", + "SM-G930R", + "SM-G930A", + "SM-G930V", + "SM-G930T", + "SM-G930U", + "SM-G930P", + + // Galaxy S7+ + "SM-SC02H", + "SM-SCV33", + "SM-G9350", + "SM-G935R", + "SM-G935A", + "SM-G935V", + "SM-G935T", + "SM-G935U", + "SM-G935P" + ); + + static boolean load() { + return "SAMSUNG".equals(Build.BRAND.toUpperCase(Locale.US)) + && DEVICE_MODELS.contains(Build.MODEL.toUpperCase(Locale.US)); + } +} |