aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorleo huang <leohuang@google.com>2021-03-29 16:00:21 +0800
committerandroid-build-prod (mdb) <android-build-team-robot@google.com>2021-04-09 07:43:12 +0000
commitbe4f6848ffb712b52822bb40cd213dec195263af (patch)
tree7dd9828a366fb41aca227ab6222e1c7d5733e730
parent17893f7667cf39bc1e94f77b6ad55cd10987594b (diff)
downloadsupport-be4f6848ffb712b52822bb40cd213dec195263af.tar.gz
Fix ImageCapture with flash On/Auto takes washed out images on Samsung Galaxy S7
The issue is device specific. The workaround is to open and close torch to take pciture instead of using the flash fired by flash mode. Relnote: "Fixed ImageCapture with flash On/Auto takes washed out images on Samsung Galaxy S7." Bug: 176399765 Test: manually test Change-Id: I30001bdfb0fc773e9705d63a2f60a8402c55187c (cherry picked from commit c421fc81e97ccdb5fb46de581d44e91ce26cf409)
-rw-r--r--camera/camera-core/src/main/java/androidx/camera/core/ImageCapture.java64
-rw-r--r--camera/camera-core/src/main/java/androidx/camera/core/internal/compat/quirk/DeviceQuirksLoader.java4
-rw-r--r--camera/camera-core/src/main/java/androidx/camera/core/internal/compat/quirk/ImageCaptureWashedOutImageQuirk.java61
3 files changed, 120 insertions, 9 deletions
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));
+ }
+}