aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTreehugger Robot <treehugger-gerrit@google.com>2022-09-26 20:49:20 +0000
committerGerrit Code Review <noreply-gerritcodereview@google.com>2022-09-26 20:49:20 +0000
commit7063952a472076b1af836bb006bcdc7bc7250737 (patch)
tree576ad111e7f9e3cf938676f5e1ce5bb51defb4d4
parent55bebb0c37140ddd7613218ff21e083140209714 (diff)
parent653bc8823a20986c5c307cded95afb223ebd9991 (diff)
downloadsupport-7063952a472076b1af836bb006bcdc7bc7250737.tar.gz
Merge "Remove EffectBundle and update CameraEffect" into androidx-main
-rw-r--r--camera/camera-core/src/androidTest/java/androidx/camera/core/processing/DefaultSurfaceProcessorTest.kt4
-rw-r--r--camera/camera-core/src/main/java/androidx/camera/core/CameraEffect.java159
-rw-r--r--camera/camera-core/src/main/java/androidx/camera/core/EffectBundle.java114
-rw-r--r--camera/camera-core/src/main/java/androidx/camera/core/ImageProcessor.java (renamed from camera/camera-core/src/main/java/androidx/camera/core/ImageEffect.java)8
-rw-r--r--camera/camera-core/src/main/java/androidx/camera/core/Preview.java2
-rw-r--r--camera/camera-core/src/main/java/androidx/camera/core/SurfaceProcessor.java12
-rw-r--r--camera/camera-core/src/main/java/androidx/camera/core/UseCaseGroup.java33
-rw-r--r--camera/camera-core/src/main/java/androidx/camera/core/internal/CameraUseCaseAdapter.java56
-rw-r--r--camera/camera-core/src/test/java/androidx/camera/core/EffectBundleTest.kt65
-rw-r--r--camera/camera-core/src/test/java/androidx/camera/core/internal/CameraUseCaseAdapterTest.kt22
-rw-r--r--camera/camera-core/src/test/java/androidx/camera/core/processing/SettableSurfaceTest.kt4
-rw-r--r--camera/camera-core/src/test/java/androidx/camera/core/processing/SurfaceOutputImplTest.kt4
-rw-r--r--camera/camera-core/src/test/java/androidx/camera/core/processing/SurfaceProcessorNodeTest.kt2
-rw-r--r--camera/camera-lifecycle/src/androidTest/java/androidx/camera/lifecycle/LifecycleCameraRepositoryTest.java48
-rw-r--r--camera/camera-lifecycle/src/androidTest/java/androidx/camera/lifecycle/ProcessCameraProviderTest.kt11
-rw-r--r--camera/camera-lifecycle/src/main/java/androidx/camera/lifecycle/LifecycleCameraRepository.java9
-rw-r--r--camera/camera-lifecycle/src/main/java/androidx/camera/lifecycle/ProcessCameraProvider.java14
-rw-r--r--camera/camera-video/src/main/java/androidx/camera/video/VideoCapture.java4
-rw-r--r--camera/camera-view/src/androidTest/java/androidx/camera/view/CameraControllerDeviceTest.kt27
-rw-r--r--camera/camera-view/src/main/java/androidx/camera/view/CameraController.java23
-rw-r--r--camera/integration-tests/viewtestapp/src/androidTest/java/androidx/camera/integration/view/CameraControllerFragmentTest.kt6
-rw-r--r--camera/integration-tests/viewtestapp/src/main/java/androidx/camera/integration/view/CameraControllerFragment.java19
-rw-r--r--camera/integration-tests/viewtestapp/src/main/java/androidx/camera/integration/view/ToneMappingPreviewEffect.kt31
23 files changed, 323 insertions, 354 deletions
diff --git a/camera/camera-core/src/androidTest/java/androidx/camera/core/processing/DefaultSurfaceProcessorTest.kt b/camera/camera-core/src/androidTest/java/androidx/camera/core/processing/DefaultSurfaceProcessorTest.kt
index 49f2220a216..79a9f91fc19 100644
--- a/camera/camera-core/src/androidTest/java/androidx/camera/core/processing/DefaultSurfaceProcessorTest.kt
+++ b/camera/camera-core/src/androidTest/java/androidx/camera/core/processing/DefaultSurfaceProcessorTest.kt
@@ -20,8 +20,8 @@ import android.graphics.Rect
import android.hardware.camera2.CameraDevice.TEMPLATE_PREVIEW
import android.util.Size
import android.view.Surface
+import androidx.camera.core.CameraEffect
import androidx.camera.core.SurfaceOutput.GlTransformOptions.USE_SURFACE_TEXTURE_TRANSFORM
-import androidx.camera.core.SurfaceProcessor
import androidx.camera.core.SurfaceRequest
import androidx.camera.core.impl.DeferrableSurface
import androidx.camera.core.impl.ImageFormatConstants
@@ -304,7 +304,7 @@ class DefaultSurfaceProcessorTest {
private fun createSurfaceOutput(surface: Surface = mock(Surface::class.java)) =
SurfaceOutputImpl(
surface,
- SurfaceProcessor.PREVIEW,
+ CameraEffect.PREVIEW,
ImageFormatConstants.INTERNAL_DEFINED_IMAGE_FORMAT_PRIVATE,
Size(WIDTH, HEIGHT),
USE_SURFACE_TEXTURE_TRANSFORM,
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/CameraEffect.java b/camera/camera-core/src/main/java/androidx/camera/core/CameraEffect.java
index 2445aa0a098..4d7c8ea771a 100644
--- a/camera/camera-core/src/main/java/androidx/camera/core/CameraEffect.java
+++ b/camera/camera-core/src/main/java/androidx/camera/core/CameraEffect.java
@@ -13,34 +13,177 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
package androidx.camera.core;
+import static androidx.camera.core.impl.utils.executor.CameraXExecutors.mainThreadExecutor;
+import static androidx.core.util.Preconditions.checkState;
+
+import android.os.Build;
+
import androidx.annotation.IntDef;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.annotation.RequiresApi;
import androidx.annotation.RestrictTo;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import java.util.concurrent.Executor;
/**
- * The effect interface which all other effects are built on top of.
+ * A CameraX post-processing effects.
*
- * <p>A CameraEffect provides functionality to inject post processing to camera output.
+ * <p>A {@link CameraEffect} class contains two types of information, the processor and the
+ * configuration.
+ * <ul>
+ * <li> The processor is an implementation of a CameraX interface e.g. {@link SurfaceProcessor}.
+ * It consumes original camera frames from CameraX, applies the effect, and returns the processed
+ * frames back to CameraX.
+ * <li> The configuration provides information on how the processor should be injected into the
+ * CameraX pipeline. For example, the target {@link UseCase}s where the effect should be applied.
+ * </ul>
*
* @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
-public interface CameraEffect {
+@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
+public class CameraEffect {
/**
- * Bitmask options for the targets of the effect.
+ * Bitmask options for the effect targets.
*
* @hide
*/
@Retention(RetentionPolicy.SOURCE)
@RestrictTo(RestrictTo.Scope.LIBRARY)
- @IntDef(flag = true, value = {SurfaceProcessor.PREVIEW, SurfaceProcessor.VIDEO_CAPTURE,
- ImageEffect.IMAGE_CAPTURE})
- @interface Targets {
+ @IntDef(flag = true, value = {PREVIEW, VIDEO_CAPTURE, IMAGE_CAPTURE})
+ public @interface Targets {
+ }
+
+ /**
+ * Bitmask option to indicate that CameraX should apply this effect to {@link Preview}.
+ */
+ public static final int PREVIEW = 1;
+
+ /**
+ * Bitmask option to indicate that CameraX should apply this effect to {@code VideoCapture}.
+ */
+ public static final int VIDEO_CAPTURE = 1 << 1;
+
+ /**
+ * Bitmask option to indicate that CameraX should apply this effect to {@link ImageCapture}.
+ */
+ public static final int IMAGE_CAPTURE = 1 << 2;
+
+ @Targets
+ private final int mTargets;
+ @NonNull
+ private final Executor mProcessorExecutor;
+ @Nullable
+ private final SurfaceProcessor mSurfaceProcessor;
+
+ /**
+ * Private constructor as a workaround to allow @Nullable annotation on final fields.
+ */
+ @SuppressWarnings("UnusedMethod") // TODO: remove once we add {@link ImageProcessor}.
+ private CameraEffect(@Targets int targets) {
+ mTargets = targets;
+ mProcessorExecutor = mainThreadExecutor();
+ mSurfaceProcessor = null;
+ }
+
+ /**
+ * @param targets the target {@link UseCase} to which this effect should be applied.
+ * @param processorExecutor the {@link Executor} on which the processor will be invoked.
+ * @param surfaceProcessor a {@link SurfaceProcessor} implementation.
+ */
+ protected CameraEffect(
+ @Targets int targets,
+ @NonNull Executor processorExecutor,
+ @NonNull SurfaceProcessor surfaceProcessor) {
+ mTargets = targets;
+ mProcessorExecutor = processorExecutor;
+ mSurfaceProcessor = surfaceProcessor;
+ }
+
+ /**
+ * Ges the target {@link UseCase}s of this effect.
+ */
+ @Targets
+ public int getTargets() {
+ return mTargets;
+ }
+
+ /**
+ * Gets the {@link Executor} for calling processors.
+ *
+ * <p>This method returns the value set via {@link Builder#setSurfaceProcessor}.
+ */
+ @NonNull
+ public Executor getProcessorExecutor() {
+ return mProcessorExecutor;
+ }
+
+ /**
+ * Gets the {@link SurfaceProcessor} associated with this effect.
+ *
+ * <p>This method returns the value set via {@link Builder#setSurfaceProcessor}.
+ */
+ @Nullable
+ public SurfaceProcessor getSurfaceProcessor() {
+ return mSurfaceProcessor;
+ }
+
+ /**
+ * Builder class for {@link CameraEffect}.
+ */
+ public static class Builder {
+ @Targets
+ private final int mTargets;
+ @Nullable
+ private Executor mProcessorExecutor;
+ @Nullable
+ private SurfaceProcessor mSurfaceProcessor;
+
+ /**
+ * @param targets the target {@link UseCase} of the Effect. e.g. if the
+ * value is {@link #PREVIEW}, CameraX will apply the effect to
+ * {@link Preview}.
+ */
+ public Builder(@Targets int targets) {
+ mTargets = targets;
+ }
+
+ /**
+ * Sets a {@link SurfaceProcessor} for the effect.
+ *
+ * <p>Once the effect is active, CameraX will send original camera frames to the
+ * {@link SurfaceProcessor} on the {@link Executor}, and deliver the processed output
+ * frames to the app.
+ *
+ * @param executor on which the {@link SurfaceProcessor} will be invoked.
+ * @param processor the post processor to be injected into CameraX pipeline.
+ */
+ @NonNull
+ public Builder setSurfaceProcessor(@NonNull Executor executor,
+ @NonNull SurfaceProcessor processor) {
+ mProcessorExecutor = executor;
+ mSurfaceProcessor = processor;
+ return this;
+ }
+
+ /**
+ * Builds a {@link CameraEffect} instance.
+ *
+ * <p>CameraX supports a selected set of configuration/processor combinations. This method
+ * throws a {@link UnsupportedOperationException} if the current combination is not
+ * supported.
+ */
+ @NonNull
+ public CameraEffect build() {
+ checkState(mProcessorExecutor != null && mSurfaceProcessor != null,
+ "Must set a processor.");
+ return new CameraEffect(mTargets, mProcessorExecutor, mSurfaceProcessor);
+ }
}
}
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/EffectBundle.java b/camera/camera-core/src/main/java/androidx/camera/core/EffectBundle.java
deleted file mode 100644
index ba6b61f8db6..00000000000
--- a/camera/camera-core/src/main/java/androidx/camera/core/EffectBundle.java
+++ /dev/null
@@ -1,114 +0,0 @@
-/*
- * Copyright 2022 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;
-
-import static androidx.camera.core.SurfaceProcessor.PREVIEW;
-import static androidx.core.util.Preconditions.checkArgument;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.RestrictTo;
-
-import java.util.HashMap;
-import java.util.Map;
-import java.util.concurrent.Executor;
-
-/**
- * A bundle of {@link CameraEffect}s and their targets.
- *
- * @hide
- */
-@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
-public class EffectBundle {
-
- private final Map<Integer, CameraEffect> mEffects;
-
- private final Executor mExecutor;
-
- EffectBundle(@NonNull Map<Integer, CameraEffect> effects, @NonNull Executor executor) {
- mEffects = effects;
- mExecutor = executor;
- }
-
- /**
- * Gets the {@link CameraEffect} and their targets.
- */
- @NonNull
- public Map<Integer, CameraEffect> getEffects() {
- return new HashMap<>(mEffects);
- }
-
- /**
- * Gets the {@link Executor} used for calling the {@link CameraEffect}.
- */
- @NonNull
- public Executor getExecutor() {
- return mExecutor;
- }
-
- /**
- * Builder class for {@link EffectBundle}.
- */
- public static class Builder {
-
- private final Map<Integer, CameraEffect> mEffects;
- private final Executor mExecutor;
-
- /**
- * Creates a {@link EffectBundle} builder.
- *
- * @param executor on which the {@link CameraEffect}s will be invoked.
- */
- public Builder(@NonNull Executor executor) {
- mEffects = new HashMap<>();
- mExecutor = executor;
- }
-
- /**
- * Adds a {@link CameraEffect} with its targets.
- *
- * @param targets on which the effect will be applied. CameraX only supports
- * {@link SurfaceProcessor#PREVIEW} for now.
- * @param cameraEffect the effect implementation.
- * @throws IllegalArgumentException if the configuration is illegal.
- */
- @NonNull
- public Builder addEffect(
- @CameraEffect.Targets int targets,
- @NonNull CameraEffect cameraEffect) {
- checkArgument(!mEffects.containsKey(targets), "The target already has an effect");
- checkArgument(targets == PREVIEW, "Only allows PREVIEW target.");
- if (cameraEffect instanceof SurfaceProcessor) {
- mEffects.put(targets, cameraEffect);
- } else {
- throw new UnsupportedOperationException(
- "CameraX only supports SurfaceProcessor for now.");
- }
- return this;
- }
-
- /**
- * Builds the {@link EffectBundle}.
- *
- * @throws IllegalArgumentException if the bundle contains no effect.
- */
- @NonNull
- public EffectBundle build() {
- checkArgument(mEffects.size() > 0, "The bundle cannot be empty");
- return new EffectBundle(new HashMap<>(mEffects), mExecutor);
- }
- }
-}
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/ImageEffect.java b/camera/camera-core/src/main/java/androidx/camera/core/ImageProcessor.java
index 9e32538e1c0..03d7ef7bcd5 100644
--- a/camera/camera-core/src/main/java/androidx/camera/core/ImageEffect.java
+++ b/camera/camera-core/src/main/java/androidx/camera/core/ImageProcessor.java
@@ -24,12 +24,6 @@ import androidx.annotation.RestrictTo;
* @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
-public interface ImageEffect extends CameraEffect {
-
- /**
- * Bitmask option to indicate that CameraX applies this effect to {@link ImageCapture}.
- */
- int IMAGE_CAPTURE = 1 << 2;
-
+public interface ImageProcessor {
// TODO(b/229629890): create the public interface for post-processing images.
}
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/Preview.java b/camera/camera-core/src/main/java/androidx/camera/core/Preview.java
index 062cdea7e05..dab5cfd59d2 100644
--- a/camera/camera-core/src/main/java/androidx/camera/core/Preview.java
+++ b/camera/camera-core/src/main/java/androidx/camera/core/Preview.java
@@ -312,7 +312,7 @@ public final class Preview extends UseCase {
// Create nodes and edges.
mNode = new SurfaceProcessorNode(camera, USE_SURFACE_TEXTURE_TRANSFORM, mSurfaceProcessor);
SettableSurface cameraSurface = new SettableSurface(
- SurfaceProcessor.PREVIEW,
+ CameraEffect.PREVIEW,
resolution,
ImageFormat.PRIVATE,
new Matrix(),
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/SurfaceProcessor.java b/camera/camera-core/src/main/java/androidx/camera/core/SurfaceProcessor.java
index fd55b33575f..56e6aec64ec 100644
--- a/camera/camera-core/src/main/java/androidx/camera/core/SurfaceProcessor.java
+++ b/camera/camera-core/src/main/java/androidx/camera/core/SurfaceProcessor.java
@@ -34,17 +34,7 @@ import androidx.core.util.Consumer;
* @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
-public interface SurfaceProcessor extends CameraEffect {
-
- /**
- * Bitmask option to indicate that CameraX applies this effect to {@link Preview}.
- */
- int PREVIEW = 1;
-
- /**
- * Bitmask option to indicate that CameraX applies this effect to {@code VideoCapture}.
- */
- int VIDEO_CAPTURE = 1 << 1;
+public interface SurfaceProcessor {
/**
* Invoked when CameraX requires an input {@link Surface} for reading original frames.
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/UseCaseGroup.java b/camera/camera-core/src/main/java/androidx/camera/core/UseCaseGroup.java
index d5a76f28e36..3848aa571c1 100644
--- a/camera/camera-core/src/main/java/androidx/camera/core/UseCaseGroup.java
+++ b/camera/camera-core/src/main/java/androidx/camera/core/UseCaseGroup.java
@@ -37,21 +37,18 @@ import java.util.List;
*/
@RequiresApi(21) // TODO(b/200306659): Remove and replace with annotation on package-info.java
public final class UseCaseGroup {
-
@Nullable
private final ViewPort mViewPort;
-
@NonNull
private final List<UseCase> mUseCases;
-
@NonNull
- private final EffectBundle mEffectBundle;
+ private final List<CameraEffect> mEffects;
UseCaseGroup(@Nullable ViewPort viewPort, @NonNull List<UseCase> useCases,
- @NonNull EffectBundle effectBundle) {
+ @NonNull List<CameraEffect> effects) {
mViewPort = viewPort;
mUseCases = useCases;
- mEffectBundle = effectBundle;
+ mEffects = effects;
}
/**
@@ -71,30 +68,27 @@ public final class UseCaseGroup {
}
/**
- * Gets the {@link EffectBundle}.
+ * Gets the {@link CameraEffect}s.
*
* @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
@NonNull
- public EffectBundle getEffectBundle() {
- return mEffectBundle;
+ public List<CameraEffect> getEffects() {
+ return mEffects;
}
/**
* A builder for generating {@link UseCaseGroup}.
*/
public static final class Builder {
-
private ViewPort mViewPort;
-
private final List<UseCase> mUseCases;
-
- @Nullable
- private EffectBundle mEffectBundle;
+ private final List<CameraEffect> mEffects;
public Builder() {
mUseCases = new ArrayList<>();
+ mEffects = new ArrayList<>();
}
/**
@@ -107,17 +101,17 @@ public final class UseCaseGroup {
}
/**
- * Sets the {@link EffectBundle} for the {@link UseCase}s.
+ * Adds a {@link CameraEffect} to the collection
*
- * <p>Once set, CameraX will use the {@link SurfaceProcessor}s to process the outputs of
+ * <p>Once added, CameraX will use the {@link CameraEffect}s to process the outputs of
* the {@link UseCase}s.
*
* @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
@NonNull
- public Builder setEffectBundle(@NonNull EffectBundle effectBundle) {
- mEffectBundle = effectBundle;
+ public Builder addEffect(@NonNull CameraEffect cameraEffect) {
+ mEffects.add(cameraEffect);
return this;
}
@@ -136,8 +130,7 @@ public final class UseCaseGroup {
@NonNull
public UseCaseGroup build() {
checkArgument(!mUseCases.isEmpty(), "UseCase must not be empty.");
- return new UseCaseGroup(mViewPort, mUseCases, mEffectBundle);
+ return new UseCaseGroup(mViewPort, mUseCases, mEffects);
}
}
-
}
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/internal/CameraUseCaseAdapter.java b/camera/camera-core/src/main/java/androidx/camera/core/internal/CameraUseCaseAdapter.java
index a19cccb74e0..a2da5d91edb 100644
--- a/camera/camera-core/src/main/java/androidx/camera/core/internal/CameraUseCaseAdapter.java
+++ b/camera/camera-core/src/main/java/androidx/camera/core/internal/CameraUseCaseAdapter.java
@@ -16,6 +16,9 @@
package androidx.camera.core.internal;
+import static java.util.Collections.emptyList;
+import static java.util.Objects.requireNonNull;
+
import android.graphics.Matrix;
import android.graphics.Rect;
import android.graphics.RectF;
@@ -33,11 +36,9 @@ import androidx.camera.core.CameraControl;
import androidx.camera.core.CameraEffect;
import androidx.camera.core.CameraInfo;
import androidx.camera.core.CameraSelector;
-import androidx.camera.core.EffectBundle;
import androidx.camera.core.ImageCapture;
import androidx.camera.core.Logger;
import androidx.camera.core.Preview;
-import androidx.camera.core.SurfaceProcessor;
import androidx.camera.core.UseCase;
import androidx.camera.core.ViewPort;
import androidx.camera.core.impl.AttachedSurfaceInfo;
@@ -52,19 +53,16 @@ import androidx.camera.core.impl.SurfaceConfig;
import androidx.camera.core.impl.UseCaseConfig;
import androidx.camera.core.impl.UseCaseConfigFactory;
import androidx.camera.core.impl.utils.executor.CameraXExecutors;
-import androidx.camera.core.processing.SurfaceProcessorInternal;
import androidx.camera.core.processing.SurfaceProcessorWithExecutor;
import androidx.core.util.Preconditions;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
-import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
-import java.util.concurrent.Executor;
/**
* A {@link CameraInternal} adapter which checks that the UseCases to make sure that the resolutions
@@ -97,8 +95,8 @@ public final class CameraUseCaseAdapter implements Camera {
private ViewPort mViewPort;
@GuardedBy("mLock")
- @Nullable
- private EffectBundle mEffectBundle;
+ @NonNull
+ private List<CameraEffect> mEffects = emptyList();
// Additional configs to apply onto the UseCases when added to this Camera
@GuardedBy("mLock")
@@ -176,9 +174,9 @@ public final class CameraUseCaseAdapter implements Camera {
/**
* Set the effects that will be used for the {@link UseCase} attached to the camera.
*/
- public void setEffectBundle(@Nullable EffectBundle effectBundle) {
+ public void setEffects(@Nullable List<CameraEffect> effects) {
synchronized (mLock) {
- mEffectBundle = effectBundle;
+ mEffects = effects;
}
}
@@ -202,8 +200,8 @@ public final class CameraUseCaseAdapter implements Camera {
}
List<UseCase> allUseCases = new ArrayList<>(mUseCases);
- List<UseCase> requiredExtraUseCases = Collections.emptyList();
- List<UseCase> removedExtraUseCases = Collections.emptyList();
+ List<UseCase> requiredExtraUseCases = emptyList();
+ List<UseCase> removedExtraUseCases = emptyList();
if (isCoexistingPreviewImageCaptureRequired()) {
// Collects all use cases that will be finally bound by the application
@@ -244,7 +242,7 @@ public final class CameraUseCaseAdapter implements Camera {
throw new CameraException(e.getMessage());
}
updateViewPort(suggestedResolutionsMap, useCases);
- updateEffects(mEffectBundle, useCases);
+ updateEffects(mEffects, useCases);
// Saves the updated extra use cases set after confirming the use case combination
// can be supported.
@@ -293,7 +291,7 @@ public final class CameraUseCaseAdapter implements Camera {
try {
// Calls addUseCases with empty list to add required extra fake use case.
- addUseCases(Collections.emptyList());
+ addUseCases(emptyList());
} catch (CameraException e) {
// This should not happen because the extra fake use case should be only
// added to replace the removed one which the use case combination can be
@@ -442,27 +440,25 @@ public final class CameraUseCaseAdapter implements Camera {
}
@VisibleForTesting
- static void updateEffects(@Nullable EffectBundle effectBundle,
+ static void updateEffects(@NonNull List<CameraEffect> effects,
@NonNull Collection<UseCase> useCases) {
- Map<Integer, CameraEffect> effectsWithExecutors = new HashMap<>();
- // Wrap external effects with the executor to make sure they are thread safe.
- if (effectBundle != null) {
- Executor executor = effectBundle.getExecutor();
- for (Map.Entry<Integer, CameraEffect> entry : effectBundle.getEffects().entrySet()) {
- CameraEffect effect = entry.getValue();
- int targets = entry.getKey();
- if (effect instanceof SurfaceProcessor) {
- effectsWithExecutors.put(targets, new SurfaceProcessorWithExecutor(
- (SurfaceProcessor) effect, executor));
- }
- }
+ Map<Integer, CameraEffect> effectsByTargets = new HashMap<>();
+ for (CameraEffect effect : effects) {
+ effectsByTargets.put(effect.getTargets(), effect);
}
+
// Set effects on the UseCases. This also removes existing effects if necessary.
for (UseCase useCase : useCases) {
if (useCase instanceof Preview) {
- ((Preview) useCase).setProcessor(
- (SurfaceProcessorInternal) effectsWithExecutors.get(
- SurfaceProcessor.PREVIEW));
+ Preview preview = ((Preview) useCase);
+ CameraEffect effect = effectsByTargets.get(CameraEffect.PREVIEW);
+ if (effect == null) {
+ preview.setProcessor(null);
+ continue;
+ }
+ preview.setProcessor(new SurfaceProcessorWithExecutor(
+ requireNonNull(effect.getSurfaceProcessor()),
+ effect.getProcessorExecutor()));
}
}
}
@@ -649,7 +645,7 @@ public final class CameraUseCaseAdapter implements Camera {
Map<UseCase, ConfigPair> configs = getConfigs(Arrays.asList(useCases),
mCameraConfig.getUseCaseConfigFactory(), mUseCaseConfigFactory);
calculateSuggestedResolutions(mCameraInternal.getCameraInfoInternal(),
- Arrays.asList(useCases), Collections.emptyList(), configs);
+ Arrays.asList(useCases), emptyList(), configs);
} catch (IllegalArgumentException e) {
return false;
}
diff --git a/camera/camera-core/src/test/java/androidx/camera/core/EffectBundleTest.kt b/camera/camera-core/src/test/java/androidx/camera/core/EffectBundleTest.kt
deleted file mode 100644
index de2b34687c5..00000000000
--- a/camera/camera-core/src/test/java/androidx/camera/core/EffectBundleTest.kt
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * Copyright 2022 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
-
-import android.os.Build
-import androidx.camera.core.SurfaceProcessor.PREVIEW
-import androidx.camera.core.impl.utils.executor.CameraXExecutors.mainThreadExecutor
-import androidx.camera.testing.fakes.FakeSurfaceProcessor
-import com.google.common.truth.Truth.assertThat
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.robolectric.RobolectricTestRunner
-import org.robolectric.annotation.Config
-import org.robolectric.annotation.internal.DoNotInstrument
-
-/**
- * Unit tests for [EffectBundle].
- */
-@RunWith(RobolectricTestRunner::class)
-@DoNotInstrument
-@Config(minSdk = Build.VERSION_CODES.LOLLIPOP)
-class EffectBundleTest {
-
- @Test(expected = IllegalArgumentException::class)
- fun noEffect_throwsException() {
- EffectBundle.Builder(mainThreadExecutor()).build()
- }
-
- @Test(expected = IllegalArgumentException::class)
- fun addMoreThanOnePreviewEffect_throwsException() {
- val surfaceProcessor = FakeSurfaceProcessor(mainThreadExecutor())
- EffectBundle.Builder(mainThreadExecutor())
- .addEffect(PREVIEW, surfaceProcessor)
- .addEffect(PREVIEW, surfaceProcessor)
- }
-
- @Test
- fun addPreviewEffect_hasPreviewEffect() {
- // Arrange.
- val surfaceProcessor =
- FakeSurfaceProcessor(mainThreadExecutor())
- // Act.
- val effectBundle = EffectBundle.Builder(mainThreadExecutor())
- .addEffect(PREVIEW, surfaceProcessor)
- .build()
- // Assert.
- assertThat(effectBundle.effects.values.first() as SurfaceProcessor).isEqualTo(
- surfaceProcessor
- )
- }
-} \ No newline at end of file
diff --git a/camera/camera-core/src/test/java/androidx/camera/core/internal/CameraUseCaseAdapterTest.kt b/camera/camera-core/src/test/java/androidx/camera/core/internal/CameraUseCaseAdapterTest.kt
index bd9048ea2a1..0444977a39e 100644
--- a/camera/camera-core/src/test/java/androidx/camera/core/internal/CameraUseCaseAdapterTest.kt
+++ b/camera/camera-core/src/test/java/androidx/camera/core/internal/CameraUseCaseAdapterTest.kt
@@ -22,10 +22,10 @@ import android.os.Build
import android.util.Rational
import android.util.Size
import android.view.Surface
-import androidx.camera.core.EffectBundle
+import androidx.camera.core.CameraEffect
+import androidx.camera.core.CameraEffect.PREVIEW
import androidx.camera.core.ImageCapture
import androidx.camera.core.Preview
-import androidx.camera.core.SurfaceProcessor.PREVIEW
import androidx.camera.core.UseCase
import androidx.camera.core.ViewPort
import androidx.camera.core.impl.CameraConfig
@@ -70,7 +70,7 @@ private const val CAMERA_ID = "0"
class CameraUseCaseAdapterTest {
private lateinit var surfaceProcessor: FakeSurfaceProcessor
- private lateinit var effectBundle: EffectBundle
+ private lateinit var effects: List<CameraEffect>
private lateinit var executor: ExecutorService
private lateinit var fakeCameraDeviceSurfaceManager: FakeCameraDeviceSurfaceManager
@@ -86,7 +86,9 @@ class CameraUseCaseAdapterTest {
fakeCameraSet.add(fakeCamera)
surfaceProcessor = FakeSurfaceProcessor(mainThreadExecutor())
executor = Executors.newSingleThreadExecutor()
- effectBundle = EffectBundle.Builder(executor).addEffect(PREVIEW, surfaceProcessor).build()
+ effects = listOf(
+ CameraEffect.Builder(PREVIEW).setSurfaceProcessor(executor, surfaceProcessor).build()
+ )
}
@After
@@ -339,8 +341,8 @@ class CameraUseCaseAdapterTest {
assertThat(fakeUseCase.sensorToBufferTransformMatrix).isEqualTo(Matrix().apply {
// From 4032x3024 to 4032x3022 with Crop Inside, no scale and Y shift 1.
setValues(floatArrayOf(/*scaleX=*/1f, 0f, /*translateX=*/0f,
- 0f, /*scaleY=*/1f, /*translateY=*/-1f,
- 0f, 0f, 1f))
+ 0f, /*scaleY=*/1f, /*translateY=*/-1f,
+ 0f, 0f, 1f))
})
}
@@ -617,14 +619,14 @@ class CameraUseCaseAdapterTest {
fun updateEffects_effectsAddedAndRemoved() {
// Arrange.
val preview = Preview.Builder().setSessionOptionUnpacker { _, _ -> }.build()
- // Act: update use cases with effects bundle
- CameraUseCaseAdapter.updateEffects(effectBundle, listOf(preview))
+ // Act: update use cases with effects.
+ CameraUseCaseAdapter.updateEffects(effects, listOf(preview))
// Assert: preview has processor wrapped with the right executor.
val previewProcessor = preview.processor as SurfaceProcessorWithExecutor
assertThat(previewProcessor.processor).isEqualTo(surfaceProcessor)
assertThat(previewProcessor.executor).isEqualTo(executor)
- // Act: update again with null effects bundle
- CameraUseCaseAdapter.updateEffects(null, listOf(preview))
+ // Act: update again with no effects.
+ CameraUseCaseAdapter.updateEffects(listOf(), listOf(preview))
// Assert: preview no longer has processors.
assertThat(preview.processor).isNull()
}
diff --git a/camera/camera-core/src/test/java/androidx/camera/core/processing/SettableSurfaceTest.kt b/camera/camera-core/src/test/java/androidx/camera/core/processing/SettableSurfaceTest.kt
index a409ec67fe8..64bebab04ad 100644
--- a/camera/camera-core/src/test/java/androidx/camera/core/processing/SettableSurfaceTest.kt
+++ b/camera/camera-core/src/test/java/androidx/camera/core/processing/SettableSurfaceTest.kt
@@ -24,9 +24,9 @@ import android.os.Build
import android.os.Looper.getMainLooper
import android.util.Size
import android.view.Surface
+import androidx.camera.core.CameraEffect
import androidx.camera.core.SurfaceOutput
import androidx.camera.core.SurfaceOutput.GlTransformOptions.USE_SURFACE_TEXTURE_TRANSFORM
-import androidx.camera.core.SurfaceProcessor
import androidx.camera.core.SurfaceRequest
import androidx.camera.core.SurfaceRequest.Result.RESULT_REQUEST_CANCELLED
import androidx.camera.core.SurfaceRequest.TransformationInfo
@@ -70,7 +70,7 @@ class SettableSurfaceTest {
@Before
fun setUp() {
settableSurface = SettableSurface(
- SurfaceProcessor.PREVIEW, Size(640, 480), ImageFormat.PRIVATE,
+ CameraEffect.PREVIEW, Size(640, 480), ImageFormat.PRIVATE,
Matrix(), true, Rect(), 0, false
)
fakeSurfaceTexture = SurfaceTexture(0)
diff --git a/camera/camera-core/src/test/java/androidx/camera/core/processing/SurfaceOutputImplTest.kt b/camera/camera-core/src/test/java/androidx/camera/core/processing/SurfaceOutputImplTest.kt
index e6d0b85a12d..621eb1de70f 100644
--- a/camera/camera-core/src/test/java/androidx/camera/core/processing/SurfaceOutputImplTest.kt
+++ b/camera/camera-core/src/test/java/androidx/camera/core/processing/SurfaceOutputImplTest.kt
@@ -22,9 +22,9 @@ import android.os.Build
import android.os.Looper
import android.util.Size
import android.view.Surface
+import androidx.camera.core.CameraEffect
import androidx.camera.core.SurfaceOutput.GlTransformOptions
import androidx.camera.core.SurfaceOutput.GlTransformOptions.USE_SURFACE_TEXTURE_TRANSFORM
-import androidx.camera.core.SurfaceProcessor
import androidx.camera.core.impl.utils.TransformUtils.sizeToRect
import androidx.camera.core.impl.utils.executor.CameraXExecutors.mainThreadExecutor
import com.google.common.truth.Truth.assertThat
@@ -46,7 +46,7 @@ import org.robolectric.annotation.internal.DoNotInstrument
class SurfaceOutputImplTest {
companion object {
- private const val TARGET = SurfaceProcessor.PREVIEW
+ private const val TARGET = CameraEffect.PREVIEW
private const val FORMAT = PixelFormat.RGBA_8888
private val OUTPUT_SIZE = Size(640, 480)
private val INPUT_SIZE = Size(640, 480)
diff --git a/camera/camera-core/src/test/java/androidx/camera/core/processing/SurfaceProcessorNodeTest.kt b/camera/camera-core/src/test/java/androidx/camera/core/processing/SurfaceProcessorNodeTest.kt
index abbbda5c6de..0724a8ddb21 100644
--- a/camera/camera-core/src/test/java/androidx/camera/core/processing/SurfaceProcessorNodeTest.kt
+++ b/camera/camera-core/src/test/java/androidx/camera/core/processing/SurfaceProcessorNodeTest.kt
@@ -23,10 +23,10 @@ import android.os.Build
import android.os.Looper.getMainLooper
import android.util.Size
import android.view.Surface
+import androidx.camera.core.CameraEffect.PREVIEW
import androidx.camera.core.SurfaceOutput.GlTransformOptions
import androidx.camera.core.SurfaceOutput.GlTransformOptions.APPLY_CROP_ROTATE_AND_MIRRORING
import androidx.camera.core.SurfaceOutput.GlTransformOptions.USE_SURFACE_TEXTURE_TRANSFORM
-import androidx.camera.core.SurfaceProcessor.PREVIEW
import androidx.camera.core.SurfaceRequest
import androidx.camera.core.SurfaceRequest.TransformationInfo
import androidx.camera.core.impl.utils.TransformUtils.is90or270
diff --git a/camera/camera-lifecycle/src/androidTest/java/androidx/camera/lifecycle/LifecycleCameraRepositoryTest.java b/camera/camera-lifecycle/src/androidTest/java/androidx/camera/lifecycle/LifecycleCameraRepositoryTest.java
index 65416c37ca7..972d36c8bc9 100644
--- a/camera/camera-lifecycle/src/androidTest/java/androidx/camera/lifecycle/LifecycleCameraRepositoryTest.java
+++ b/camera/camera-lifecycle/src/androidTest/java/androidx/camera/lifecycle/LifecycleCameraRepositoryTest.java
@@ -18,6 +18,8 @@ package androidx.camera.lifecycle;
import static com.google.common.truth.Truth.assertThat;
+import static java.util.Collections.emptyList;
+
import androidx.camera.core.impl.CameraInternal;
import androidx.camera.core.internal.CameraUseCaseAdapter;
import androidx.camera.testing.fakes.FakeCamera;
@@ -116,7 +118,7 @@ public final class LifecycleCameraRepositoryTest {
public void lifecycleCameraIsNotActive_bindUseCase_whenLifecycleIsNotStarted() {
LifecycleCamera lifecycleCamera = mRepository.createLifecycleCamera(mLifecycle,
mCameraUseCaseAdapter);
- mRepository.bindToLifecycleCamera(lifecycleCamera, null, null,
+ mRepository.bindToLifecycleCamera(lifecycleCamera, null, emptyList(),
Collections.singletonList(new FakeUseCase()));
// LifecycleCamera is inactive before the lifecycle state becomes ON_START.
assertThat(lifecycleCamera.isActive()).isFalse();
@@ -126,7 +128,7 @@ public final class LifecycleCameraRepositoryTest {
public void lifecycleCameraIsActive_lifecycleStartedAfterBindUseCase() {
LifecycleCamera lifecycleCamera = mRepository.createLifecycleCamera(mLifecycle,
mCameraUseCaseAdapter);
- mRepository.bindToLifecycleCamera(lifecycleCamera, null, null,
+ mRepository.bindToLifecycleCamera(lifecycleCamera, null, emptyList(),
Collections.singletonList(new FakeUseCase()));
mLifecycle.start();
// LifecycleCamera is active after the lifecycle state becomes ON_START.
@@ -138,7 +140,7 @@ public final class LifecycleCameraRepositoryTest {
LifecycleCamera lifecycleCamera = mRepository.createLifecycleCamera(mLifecycle,
mCameraUseCaseAdapter);
mLifecycle.start();
- mRepository.bindToLifecycleCamera(lifecycleCamera, null, null,
+ mRepository.bindToLifecycleCamera(lifecycleCamera, null, emptyList(),
Collections.singletonList(new FakeUseCase()));
// LifecycleCamera is active after binding a use case when lifecycle state is ON_START.
@@ -150,13 +152,13 @@ public final class LifecycleCameraRepositoryTest {
// Creates first LifecycleCamera with use case bound.
LifecycleCamera lifecycleCamera0 = mRepository.createLifecycleCamera(
mLifecycle, mCameraUseCaseAdapter);
- mRepository.bindToLifecycleCamera(lifecycleCamera0, null, null,
+ mRepository.bindToLifecycleCamera(lifecycleCamera0, null, emptyList(),
Collections.singletonList(new FakeUseCase()));
// Creates second LifecycleCamera with use case bound to the same Lifecycle.
LifecycleCamera lifecycleCamera1 = mRepository.createLifecycleCamera(mLifecycle,
createNewCameraUseCaseAdapter());
- mRepository.bindToLifecycleCamera(lifecycleCamera1, null, null,
+ mRepository.bindToLifecycleCamera(lifecycleCamera1, null, emptyList(),
Collections.singletonList(new FakeUseCase()));
}
@@ -167,7 +169,7 @@ public final class LifecycleCameraRepositoryTest {
mCameraUseCaseAdapter);
mLifecycle.start();
FakeUseCase useCase = new FakeUseCase();
- mRepository.bindToLifecycleCamera(lifecycleCamera, null, null,
+ mRepository.bindToLifecycleCamera(lifecycleCamera, null, emptyList(),
Collections.singletonList(useCase));
// Unbinds the use case that was bound previously.
@@ -186,7 +188,7 @@ public final class LifecycleCameraRepositoryTest {
mLifecycle.start();
FakeUseCase useCase0 = new FakeUseCase();
FakeUseCase useCase1 = new FakeUseCase();
- mRepository.bindToLifecycleCamera(lifecycleCamera, null, null,
+ mRepository.bindToLifecycleCamera(lifecycleCamera, null, emptyList(),
Arrays.asList(useCase0, useCase1));
// Only unbinds one use case but another one is kept in the LifecycleCamera.
@@ -203,7 +205,7 @@ public final class LifecycleCameraRepositoryTest {
LifecycleCamera lifecycleCamera = mRepository.createLifecycleCamera(mLifecycle,
mCameraUseCaseAdapter);
mLifecycle.start();
- mRepository.bindToLifecycleCamera(lifecycleCamera, null, null,
+ mRepository.bindToLifecycleCamera(lifecycleCamera, null, emptyList(),
Collections.singletonList(new FakeUseCase()));
// Unbinds all use cases from all LifecycleCamera by the unbindAll() API.
@@ -219,7 +221,7 @@ public final class LifecycleCameraRepositoryTest {
LifecycleCamera lifecycleCamera0 = mRepository.createLifecycleCamera(mLifecycle,
mCameraUseCaseAdapter);
mLifecycle.start();
- mRepository.bindToLifecycleCamera(lifecycleCamera0, null, null,
+ mRepository.bindToLifecycleCamera(lifecycleCamera0, null, emptyList(),
Collections.singletonList(new FakeUseCase()));
// Starts second lifecycle with use case bound.
@@ -227,7 +229,7 @@ public final class LifecycleCameraRepositoryTest {
LifecycleCamera lifecycleCamera1 = mRepository.createLifecycleCamera(lifecycle1,
createNewCameraUseCaseAdapter());
lifecycle1.start();
- mRepository.bindToLifecycleCamera(lifecycleCamera1, null, null,
+ mRepository.bindToLifecycleCamera(lifecycleCamera1, null, emptyList(),
Collections.singletonList(new FakeUseCase()));
// The previous LifecycleCamera becomes inactive after new LifecycleCamera becomes active.
@@ -242,7 +244,7 @@ public final class LifecycleCameraRepositoryTest {
LifecycleCamera lifecycleCamera0 = mRepository.createLifecycleCamera(mLifecycle,
mCameraUseCaseAdapter);
mLifecycle.start();
- mRepository.bindToLifecycleCamera(lifecycleCamera0, null, null,
+ mRepository.bindToLifecycleCamera(lifecycleCamera0, null, emptyList(),
Collections.singletonList(new FakeUseCase()));
// Starts second lifecycle with use case bound.
@@ -250,11 +252,11 @@ public final class LifecycleCameraRepositoryTest {
LifecycleCamera lifecycleCamera1 = mRepository.createLifecycleCamera(lifecycle1,
createNewCameraUseCaseAdapter());
lifecycle1.start();
- mRepository.bindToLifecycleCamera(lifecycleCamera1, null, null,
+ mRepository.bindToLifecycleCamera(lifecycleCamera1, null, emptyList(),
Collections.singletonList(new FakeUseCase()));
// Binds new use case to the next most recent active LifecycleCamera.
- mRepository.bindToLifecycleCamera(lifecycleCamera0, null, null,
+ mRepository.bindToLifecycleCamera(lifecycleCamera0, null, emptyList(),
Collections.singletonList(new FakeUseCase()));
// The next most recent active LifecycleCamera becomes active after binding new use case.
@@ -270,7 +272,7 @@ public final class LifecycleCameraRepositoryTest {
LifecycleCamera lifecycleCamera0 = mRepository.createLifecycleCamera(mLifecycle,
mCameraUseCaseAdapter);
mLifecycle.start();
- mRepository.bindToLifecycleCamera(lifecycleCamera0, null, null,
+ mRepository.bindToLifecycleCamera(lifecycleCamera0, null, emptyList(),
Collections.singletonList(new FakeUseCase()));
// Starts second lifecycle with use case bound.
@@ -279,7 +281,7 @@ public final class LifecycleCameraRepositoryTest {
createNewCameraUseCaseAdapter());
lifecycle1.start();
FakeUseCase useCase = new FakeUseCase();
- mRepository.bindToLifecycleCamera(lifecycleCamera1, null, null,
+ mRepository.bindToLifecycleCamera(lifecycleCamera1, null, emptyList(),
Collections.singletonList(useCase));
// Unbinds use case from the most recent active LifecycleCamera.
@@ -298,7 +300,7 @@ public final class LifecycleCameraRepositoryTest {
LifecycleCamera lifecycleCamera = mRepository.createLifecycleCamera(
mLifecycle, mCameraUseCaseAdapter);
FakeUseCase useCase = new FakeUseCase();
- mRepository.bindToLifecycleCamera(lifecycleCamera, null, null,
+ mRepository.bindToLifecycleCamera(lifecycleCamera, null, emptyList(),
Collections.singletonList(useCase));
assertThat(useCase.isDetached()).isFalse();
@@ -321,7 +323,7 @@ public final class LifecycleCameraRepositoryTest {
// Starts first lifecycle and check LifecycleCamera active state is true.
LifecycleCamera firstLifecycleCamera = mRepository.createLifecycleCamera(
mLifecycle, mCameraUseCaseAdapter);
- mRepository.bindToLifecycleCamera(firstLifecycleCamera, null, null,
+ mRepository.bindToLifecycleCamera(firstLifecycleCamera, null, emptyList(),
Collections.singletonList(new FakeUseCase()));
mLifecycle.start();
assertThat(firstLifecycleCamera.isActive()).isTrue();
@@ -330,7 +332,7 @@ public final class LifecycleCameraRepositoryTest {
FakeLifecycleOwner secondLifecycle = new FakeLifecycleOwner();
LifecycleCamera secondLifecycleCamera = mRepository.createLifecycleCamera(secondLifecycle,
createNewCameraUseCaseAdapter());
- mRepository.bindToLifecycleCamera(secondLifecycleCamera, null, null,
+ mRepository.bindToLifecycleCamera(secondLifecycleCamera, null, emptyList(),
Collections.singletonList(new FakeUseCase()));
secondLifecycle.start();
assertThat(secondLifecycleCamera.isActive()).isTrue();
@@ -342,7 +344,7 @@ public final class LifecycleCameraRepositoryTest {
// Starts first lifecycle and check LifecycleCamera active state is true.
LifecycleCamera firstLifecycleCamera = mRepository.createLifecycleCamera(
mLifecycle, mCameraUseCaseAdapter);
- mRepository.bindToLifecycleCamera(firstLifecycleCamera, null, null,
+ mRepository.bindToLifecycleCamera(firstLifecycleCamera, null, emptyList(),
Collections.singletonList(new FakeUseCase()));
mLifecycle.start();
assertThat(firstLifecycleCamera.isActive()).isTrue();
@@ -351,7 +353,7 @@ public final class LifecycleCameraRepositoryTest {
FakeLifecycleOwner secondLifecycle = new FakeLifecycleOwner();
LifecycleCamera secondLifecycleCamera = mRepository.createLifecycleCamera(secondLifecycle,
createNewCameraUseCaseAdapter());
- mRepository.bindToLifecycleCamera(secondLifecycleCamera, null, null,
+ mRepository.bindToLifecycleCamera(secondLifecycleCamera, null, emptyList(),
Collections.singletonList(new FakeUseCase()));
secondLifecycle.start();
assertThat(secondLifecycleCamera.isActive()).isTrue();
@@ -368,7 +370,7 @@ public final class LifecycleCameraRepositoryTest {
// Starts first LifecycleCamera with use case bound.
LifecycleCamera firstLifecycleCamera = mRepository.createLifecycleCamera(
mLifecycle, mCameraUseCaseAdapter);
- mRepository.bindToLifecycleCamera(firstLifecycleCamera, null, null,
+ mRepository.bindToLifecycleCamera(firstLifecycleCamera, null, emptyList(),
Collections.singletonList(new FakeUseCase()));
mLifecycle.start();
assertThat(firstLifecycleCamera.isActive()).isTrue();
@@ -395,7 +397,7 @@ public final class LifecycleCameraRepositoryTest {
// Starts second LifecycleCamera with use case bound to the same Lifecycle.
LifecycleCamera lifecycleCamera1 = mRepository.createLifecycleCamera(
mLifecycle, createNewCameraUseCaseAdapter());
- mRepository.bindToLifecycleCamera(lifecycleCamera1, null, null,
+ mRepository.bindToLifecycleCamera(lifecycleCamera1, null, emptyList(),
Collections.singletonList(new FakeUseCase()));
// Starts third LifecycleCamera with no use case bound to the same Lifecycle.
@@ -450,7 +452,7 @@ public final class LifecycleCameraRepositoryTest {
// Starts LifecycleCamera with use case bound.
LifecycleCamera lifecycleCamera = mRepository.createLifecycleCamera(
mLifecycle, mCameraUseCaseAdapter);
- mRepository.bindToLifecycleCamera(lifecycleCamera, null, null,
+ mRepository.bindToLifecycleCamera(lifecycleCamera, null, emptyList(),
Collections.singletonList(new FakeUseCase()));
mLifecycle.start();
assertThat(lifecycleCamera.isActive()).isTrue();
diff --git a/camera/camera-lifecycle/src/androidTest/java/androidx/camera/lifecycle/ProcessCameraProviderTest.kt b/camera/camera-lifecycle/src/androidTest/java/androidx/camera/lifecycle/ProcessCameraProviderTest.kt
index 0bb2cbe7708..2f7d239b85b 100644
--- a/camera/camera-lifecycle/src/androidTest/java/androidx/camera/lifecycle/ProcessCameraProviderTest.kt
+++ b/camera/camera-lifecycle/src/androidTest/java/androidx/camera/lifecycle/ProcessCameraProviderTest.kt
@@ -22,11 +22,11 @@ import android.content.ContextWrapper
import android.content.pm.PackageManager
import androidx.annotation.OptIn
import androidx.annotation.RequiresApi
+import androidx.camera.core.CameraEffect
+import androidx.camera.core.CameraEffect.PREVIEW
import androidx.camera.core.CameraSelector
import androidx.camera.core.CameraXConfig
-import androidx.camera.core.EffectBundle
import androidx.camera.core.Preview
-import androidx.camera.core.SurfaceProcessor.PREVIEW
import androidx.camera.core.UseCaseGroup
import androidx.camera.core.impl.CameraFactory
import androidx.camera.core.impl.utils.executor.CameraXExecutors.mainThreadExecutor
@@ -80,11 +80,10 @@ class ProcessCameraProviderTest {
// Arrange.
ProcessCameraProvider.configureInstance(FakeAppConfig.create())
val surfaceProcessor = FakeSurfaceProcessor(mainThreadExecutor())
- val effectBundle =
- EffectBundle.Builder(mainThreadExecutor()).addEffect(PREVIEW, surfaceProcessor).build()
+ val effect = CameraEffect.Builder(PREVIEW)
+ .setSurfaceProcessor(mainThreadExecutor(), surfaceProcessor).build()
val preview = Preview.Builder().setSessionOptionUnpacker { _, _ -> }.build()
- val useCaseGroup = UseCaseGroup.Builder().addUseCase(preview)
- .setEffectBundle(effectBundle).build()
+ val useCaseGroup = UseCaseGroup.Builder().addUseCase(preview).addEffect(effect).build()
runBlocking(MainScope().coroutineContext) {
// Act.
diff --git a/camera/camera-lifecycle/src/main/java/androidx/camera/lifecycle/LifecycleCameraRepository.java b/camera/camera-lifecycle/src/main/java/androidx/camera/lifecycle/LifecycleCameraRepository.java
index 8fc8a6ba9bc..706c842ac4b 100644
--- a/camera/camera-lifecycle/src/main/java/androidx/camera/lifecycle/LifecycleCameraRepository.java
+++ b/camera/camera-lifecycle/src/main/java/androidx/camera/lifecycle/LifecycleCameraRepository.java
@@ -20,7 +20,7 @@ import androidx.annotation.GuardedBy;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;
-import androidx.camera.core.EffectBundle;
+import androidx.camera.core.CameraEffect;
import androidx.camera.core.UseCase;
import androidx.camera.core.ViewPort;
import androidx.camera.core.impl.CameraInternal;
@@ -39,6 +39,7 @@ import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
+import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -250,14 +251,14 @@ final class LifecycleCameraRepository {
*
* @param lifecycleCamera The LifecycleCamera which the use cases will be bound to.
* @param viewPort The viewport which represents the visible camera sensor rect.
- * @param effectBundle The effects applied to the camera outputs.
+ * @param effects The effects applied to the camera outputs.
* @param useCases The use cases to bind to a lifecycle.
* @throws IllegalArgumentException If multiple LifecycleCameras with use cases are
* registered to the same LifecycleOwner. Or all use cases will exceed the capability of the
* camera after binding them to the LifecycleCamera.
*/
void bindToLifecycleCamera(@NonNull LifecycleCamera lifecycleCamera,
- @Nullable ViewPort viewPort, @Nullable EffectBundle effectBundle,
+ @Nullable ViewPort viewPort, @NonNull List<CameraEffect> effects,
@NonNull Collection<UseCase> useCases) {
synchronized (mLock) {
Preconditions.checkArgument(!useCases.isEmpty());
@@ -278,7 +279,7 @@ final class LifecycleCameraRepository {
try {
lifecycleCamera.getCameraUseCaseAdapter().setViewPort(viewPort);
- lifecycleCamera.getCameraUseCaseAdapter().setEffectBundle(effectBundle);
+ lifecycleCamera.getCameraUseCaseAdapter().setEffects(effects);
lifecycleCamera.bind(useCases);
} catch (CameraUseCaseAdapter.CameraException e) {
throw new IllegalArgumentException(e.getMessage());
diff --git a/camera/camera-lifecycle/src/main/java/androidx/camera/lifecycle/ProcessCameraProvider.java b/camera/camera-lifecycle/src/main/java/androidx/camera/lifecycle/ProcessCameraProvider.java
index 066a237cf98..33dabcac7b8 100644
--- a/camera/camera-lifecycle/src/main/java/androidx/camera/lifecycle/ProcessCameraProvider.java
+++ b/camera/camera-lifecycle/src/main/java/androidx/camera/lifecycle/ProcessCameraProvider.java
@@ -16,6 +16,8 @@
package androidx.camera.lifecycle;
+import static java.util.Collections.emptyList;
+
import android.app.Application;
import android.content.Context;
import android.os.Handler;
@@ -28,13 +30,13 @@ import androidx.annotation.RequiresApi;
import androidx.annotation.RestrictTo;
import androidx.annotation.RestrictTo.Scope;
import androidx.camera.core.Camera;
+import androidx.camera.core.CameraEffect;
import androidx.camera.core.CameraFilter;
import androidx.camera.core.CameraInfo;
import androidx.camera.core.CameraInfoUnavailableException;
import androidx.camera.core.CameraSelector;
import androidx.camera.core.CameraX;
import androidx.camera.core.CameraXConfig;
-import androidx.camera.core.EffectBundle;
import androidx.camera.core.ImageAnalysis;
import androidx.camera.core.ImageCapture;
import androidx.camera.core.InitializationException;
@@ -358,7 +360,7 @@ public final class ProcessCameraProvider implements LifecycleCameraProvider {
public Camera bindToLifecycle(@NonNull LifecycleOwner lifecycleOwner,
@NonNull CameraSelector cameraSelector,
@NonNull UseCase... useCases) {
- return bindToLifecycle(lifecycleOwner, cameraSelector, null, null, useCases);
+ return bindToLifecycle(lifecycleOwner, cameraSelector, null, emptyList(), useCases);
}
/**
@@ -380,7 +382,7 @@ public final class ProcessCameraProvider implements LifecycleCameraProvider {
@NonNull CameraSelector cameraSelector,
@NonNull UseCaseGroup useCaseGroup) {
return bindToLifecycle(lifecycleOwner, cameraSelector,
- useCaseGroup.getViewPort(), useCaseGroup.getEffectBundle(),
+ useCaseGroup.getViewPort(), useCaseGroup.getEffects(),
useCaseGroup.getUseCases().toArray(new UseCase[0]));
}
@@ -433,7 +435,7 @@ public final class ProcessCameraProvider implements LifecycleCameraProvider {
* @param cameraSelector The camera selector which determines the camera to use for set of
* use cases.
* @param viewPort The viewPort which represents the visible camera sensor rect.
- * @param effectBundle The effects applied to the camera outputs.
+ * @param effects The effects applied to the camera outputs.
* @param useCases The use cases to bind to a lifecycle.
* @return The {@link Camera} instance which is determined by the camera selector and
* internal requirements.
@@ -448,7 +450,7 @@ public final class ProcessCameraProvider implements LifecycleCameraProvider {
@NonNull LifecycleOwner lifecycleOwner,
@NonNull CameraSelector cameraSelector,
@Nullable ViewPort viewPort,
- @Nullable EffectBundle effectBundle,
+ @NonNull List<CameraEffect> effects,
@NonNull UseCase... useCases) {
Threads.checkMainThread();
// TODO(b/153096869): override UseCase's target rotation.
@@ -534,7 +536,7 @@ public final class ProcessCameraProvider implements LifecycleCameraProvider {
}
mLifecycleCameraRepository.bindToLifecycleCamera(lifecycleCameraToBind, viewPort,
- effectBundle, Arrays.asList(useCases));
+ effects, Arrays.asList(useCases));
return lifecycleCameraToBind;
}
diff --git a/camera/camera-video/src/main/java/androidx/camera/video/VideoCapture.java b/camera/camera-video/src/main/java/androidx/camera/video/VideoCapture.java
index b23e20e60b9..94d174604a6 100644
--- a/camera/camera-video/src/main/java/androidx/camera/video/VideoCapture.java
+++ b/camera/camera-video/src/main/java/androidx/camera/video/VideoCapture.java
@@ -16,6 +16,7 @@
package androidx.camera.video;
+import static androidx.camera.core.CameraEffect.VIDEO_CAPTURE;
import static androidx.camera.core.SurfaceOutput.GlTransformOptions.APPLY_CROP_ROTATE_AND_MIRRORING;
import static androidx.camera.core.impl.ImageOutputConfig.OPTION_DEFAULT_RESOLUTION;
import static androidx.camera.core.impl.ImageOutputConfig.OPTION_MAX_RESOLUTION;
@@ -65,7 +66,6 @@ import androidx.camera.core.AspectRatio;
import androidx.camera.core.CameraSelector;
import androidx.camera.core.ImageCapture;
import androidx.camera.core.Logger;
-import androidx.camera.core.SurfaceProcessor;
import androidx.camera.core.SurfaceRequest;
import androidx.camera.core.UseCase;
import androidx.camera.core.ViewPort;
@@ -501,7 +501,7 @@ public final class VideoCapture<T extends VideoOutput> extends UseCase {
VideoCapabilities.from(camera.getCameraInfo()), timebase, mediaSpec,
resolution, targetFpsRange));
SettableSurface cameraSurface = new SettableSurface(
- SurfaceProcessor.VIDEO_CAPTURE,
+ VIDEO_CAPTURE,
resolution,
ImageFormat.PRIVATE,
getSensorToBufferTransformMatrix(),
diff --git a/camera/camera-view/src/androidTest/java/androidx/camera/view/CameraControllerDeviceTest.kt b/camera/camera-view/src/androidTest/java/androidx/camera/view/CameraControllerDeviceTest.kt
index 8abbab7489d..e61af75126f 100644
--- a/camera/camera-view/src/androidTest/java/androidx/camera/view/CameraControllerDeviceTest.kt
+++ b/camera/camera-view/src/androidTest/java/androidx/camera/view/CameraControllerDeviceTest.kt
@@ -22,13 +22,13 @@ import android.provider.MediaStore
import android.view.View
import androidx.camera.camera2.Camera2Config
import androidx.camera.camera2.pipe.integration.CameraPipeConfig
+import androidx.camera.core.CameraEffect
+import androidx.camera.core.CameraEffect.PREVIEW
import androidx.camera.core.CameraSelector
import androidx.camera.core.CameraSelector.LENS_FACING_BACK
import androidx.camera.core.CameraSelector.LENS_FACING_FRONT
import androidx.camera.core.CameraXConfig
-import androidx.camera.core.EffectBundle
import androidx.camera.core.ImageCapture
-import androidx.camera.core.SurfaceProcessor.PREVIEW
import androidx.camera.core.impl.utils.executor.CameraXExecutors.mainThreadExecutor
import androidx.camera.lifecycle.ProcessCameraProvider
import androidx.camera.testing.CameraPipeConfigTestRule
@@ -127,26 +127,17 @@ class CameraControllerDeviceTest(
}
waitUtilPreviewViewIsReady(previewView!!)
- // Act: set an EffectBundle
- instrumentation.runOnMainSync {
- controller!!.setEffectBundle(
- EffectBundle.Builder(mainThreadExecutor())
- .addEffect(PREVIEW,
- FakeSurfaceProcessor(
- mainThreadExecutor()
- )
- )
- .build()
- )
- }
+ // Act: set an effect
+ val effect = CameraEffect.Builder(PREVIEW).setSurfaceProcessor(
+ mainThreadExecutor(), FakeSurfaceProcessor(mainThreadExecutor())
+ ).build()
+ instrumentation.runOnMainSync { controller!!.setEffects(listOf(effect)) }
// Assert: preview has effect
assertThat(controller!!.mPreview.processor).isNotNull()
- // Act: clear the EffectBundle
- instrumentation.runOnMainSync {
- controller!!.setEffectBundle(null)
- }
+ // Act: clear the effects
+ instrumentation.runOnMainSync { controller!!.setEffects(listOf()) }
// Assert: preview no longer has the effect.
assertThat(controller!!.mPreview.processor).isNull()
diff --git a/camera/camera-view/src/main/java/androidx/camera/view/CameraController.java b/camera/camera-view/src/main/java/androidx/camera/view/CameraController.java
index a0f314e1920..711938c37a8 100644
--- a/camera/camera-view/src/main/java/androidx/camera/view/CameraController.java
+++ b/camera/camera-view/src/main/java/androidx/camera/view/CameraController.java
@@ -20,6 +20,8 @@ import static androidx.camera.core.impl.utils.Threads.checkMainThread;
import static androidx.camera.core.impl.utils.executor.CameraXExecutors.mainThreadExecutor;
import static androidx.camera.view.CameraController.OutputSize.UNASSIGNED_ASPECT_RATIO;
+import static java.util.Collections.emptyList;
+
import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Matrix;
@@ -41,11 +43,11 @@ import androidx.annotation.VisibleForTesting;
import androidx.camera.core.AspectRatio;
import androidx.camera.core.Camera;
import androidx.camera.core.CameraControl;
+import androidx.camera.core.CameraEffect;
import androidx.camera.core.CameraInfo;
import androidx.camera.core.CameraInfoUnavailableException;
import androidx.camera.core.CameraSelector;
import androidx.camera.core.CameraUnavailableException;
-import androidx.camera.core.EffectBundle;
import androidx.camera.core.FocusMeteringAction;
import androidx.camera.core.FocusMeteringResult;
import androidx.camera.core.ImageAnalysis;
@@ -80,6 +82,7 @@ import com.google.common.util.concurrent.ListenableFuture;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import java.util.List;
import java.util.Objects;
import java.util.concurrent.Executor;
import java.util.concurrent.atomic.AtomicBoolean;
@@ -306,8 +309,8 @@ public abstract class CameraController {
final MutableLiveData<Integer> mTapToFocusState = new MutableLiveData<>(
TAP_TO_FOCUS_NOT_STARTED);
- @Nullable
- private EffectBundle mEffectBundle;
+ @NonNull
+ private List<CameraEffect> mEffects = emptyList();
private final Context mAppContext;
@@ -1664,13 +1667,13 @@ public abstract class CameraController {
/**
* Sets post-processing effects.
*
- * @param effectBundle the effects applied to camera output.
+ * @param effects the effects applied to camera output.
* @hide
- * @see UseCaseGroup.Builder#getEffectBundle()
+ * @see UseCaseGroup.Builder#addEffect
*/
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
- public void setEffectBundle(@Nullable EffectBundle effectBundle) {
- if (mEffectBundle == effectBundle) {
+ public void setEffects(@NonNull List<CameraEffect> effects) {
+ if (Objects.equals(mEffects, effects)) {
// Same effect. No change needed.
return;
}
@@ -1678,7 +1681,7 @@ public abstract class CameraController {
// Unbind to make sure the pipelines will be recreated.
mCameraProvider.unbindAll();
}
- mEffectBundle = effectBundle;
+ mEffects = effects;
startCameraAndTrackStates();
}
@@ -1763,8 +1766,8 @@ public abstract class CameraController {
}
builder.setViewPort(mViewPort);
- if (mEffectBundle != null) {
- builder.setEffectBundle(mEffectBundle);
+ for (CameraEffect effect : mEffects) {
+ builder.addEffect(effect);
}
return builder.build();
}
diff --git a/camera/integration-tests/viewtestapp/src/androidTest/java/androidx/camera/integration/view/CameraControllerFragmentTest.kt b/camera/integration-tests/viewtestapp/src/androidTest/java/androidx/camera/integration/view/CameraControllerFragmentTest.kt
index f949eb557df..0f908436c13 100644
--- a/camera/integration-tests/viewtestapp/src/androidTest/java/androidx/camera/integration/view/CameraControllerFragmentTest.kt
+++ b/camera/integration-tests/viewtestapp/src/androidTest/java/androidx/camera/integration/view/CameraControllerFragmentTest.kt
@@ -134,7 +134,9 @@ class CameraControllerFragmentTest(
fun enableEffect_effectIsEnabled() {
// Arrange: launch app and verify effect is inactive.
fragment.assertPreviewIsStreaming()
- assertThat(fragment.mSurfaceProcessor.isSurfaceRequestedAndProvided()).isFalse()
+ val processor =
+ fragment.mToneMappingPreviewEffect.surfaceProcessor as ToneMappingSurfaceProcessor
+ assertThat(processor.isSurfaceRequestedAndProvided()).isFalse()
// Act: turn on effect.
val effectToggleId = "androidx.camera.integration.view:id/effect_toggle"
@@ -142,7 +144,7 @@ class CameraControllerFragmentTest(
instrumentation.waitForIdleSync()
// Assert: verify that effect is active.
- assertThat(fragment.mSurfaceProcessor.isSurfaceRequestedAndProvided()).isTrue()
+ assertThat(processor.isSurfaceRequestedAndProvided()).isTrue()
}
@Test
diff --git a/camera/integration-tests/viewtestapp/src/main/java/androidx/camera/integration/view/CameraControllerFragment.java b/camera/integration-tests/viewtestapp/src/main/java/androidx/camera/integration/view/CameraControllerFragment.java
index 97a9bde23ff..b7c539ceb04 100644
--- a/camera/integration-tests/viewtestapp/src/main/java/androidx/camera/integration/view/CameraControllerFragment.java
+++ b/camera/integration-tests/viewtestapp/src/main/java/androidx/camera/integration/view/CameraControllerFragment.java
@@ -19,6 +19,9 @@ package androidx.camera.integration.view;
import static androidx.camera.core.impl.utils.TransformUtils.getRectToRect;
import static androidx.camera.core.impl.utils.executor.CameraXExecutors.mainThreadExecutor;
+import static java.util.Collections.emptyList;
+import static java.util.Collections.singletonList;
+
import android.annotation.SuppressLint;
import android.app.Dialog;
import android.content.ContentResolver;
@@ -54,13 +57,11 @@ import androidx.annotation.OptIn;
import androidx.annotation.RestrictTo;
import androidx.annotation.VisibleForTesting;
import androidx.camera.core.CameraSelector;
-import androidx.camera.core.EffectBundle;
import androidx.camera.core.ImageAnalysis;
import androidx.camera.core.ImageCapture;
import androidx.camera.core.ImageCaptureException;
import androidx.camera.core.ImageProxy;
import androidx.camera.core.Logger;
-import androidx.camera.core.SurfaceProcessor;
import androidx.camera.core.ZoomState;
import androidx.camera.core.impl.utils.futures.FutureCallback;
import androidx.camera.core.impl.utils.futures.Futures;
@@ -126,7 +127,7 @@ public class CameraControllerFragment extends Fragment {
private ImageAnalysis.Analyzer mWrappedAnalyzer;
@VisibleForTesting
- ToneMappingSurfaceProcessor mSurfaceProcessor;
+ ToneMappingPreviewEffect mToneMappingPreviewEffect;
private final ImageAnalysis.Analyzer mAnalyzer = image -> {
byte[] bytes = new byte[image.getPlanes()[0].getBuffer().remaining()];
@@ -182,7 +183,7 @@ public class CameraControllerFragment extends Fragment {
});
// Set up post-processing effects.
- mSurfaceProcessor = new ToneMappingSurfaceProcessor();
+ mToneMappingPreviewEffect = new ToneMappingPreviewEffect();
mEffectToggle = view.findViewById(R.id.effect_toggle);
mEffectToggle.setOnCheckedChangeListener((compoundButton, isChecked) -> onEffectsToggled());
onEffectsToggled();
@@ -352,16 +353,14 @@ public class CameraControllerFragment extends Fragment {
mExecutorService.shutdown();
}
mRotationProvider.removeListener(mRotationListener);
- mSurfaceProcessor.release();
+ mToneMappingPreviewEffect.release();
}
private void onEffectsToggled() {
if (mEffectToggle.isChecked()) {
- mCameraController.setEffectBundle(new EffectBundle.Builder(mainThreadExecutor())
- .addEffect(SurfaceProcessor.PREVIEW, mSurfaceProcessor)
- .build());
- } else if (mSurfaceProcessor != null) {
- mCameraController.setEffectBundle(null);
+ mCameraController.setEffects(singletonList(mToneMappingPreviewEffect));
+ } else {
+ mCameraController.setEffects(emptyList());
}
}
diff --git a/camera/integration-tests/viewtestapp/src/main/java/androidx/camera/integration/view/ToneMappingPreviewEffect.kt b/camera/integration-tests/viewtestapp/src/main/java/androidx/camera/integration/view/ToneMappingPreviewEffect.kt
new file mode 100644
index 00000000000..25bdc1cfd77
--- /dev/null
+++ b/camera/integration-tests/viewtestapp/src/main/java/androidx/camera/integration/view/ToneMappingPreviewEffect.kt
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2022 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.integration.view
+
+import androidx.camera.core.CameraEffect
+import androidx.camera.core.impl.utils.executor.CameraXExecutors.mainThreadExecutor
+
+/**
+ * A tone mapping effect for preview UseCase.
+ */
+internal class ToneMappingPreviewEffect :
+ CameraEffect(PREVIEW, mainThreadExecutor(), ToneMappingSurfaceProcessor()) {
+
+ fun release() {
+ (surfaceProcessor as? ToneMappingSurfaceProcessor)?.release()
+ }
+} \ No newline at end of file