1 /* 2 * Copyright 2023 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package androidx.camera.testing.impl.fakes; 18 19 import androidx.annotation.RestrictTo; 20 import androidx.camera.core.ImageCapture; 21 import androidx.camera.core.UseCase; 22 import androidx.camera.core.impl.CameraCaptureResult; 23 import androidx.camera.core.impl.CameraInfoInternal; 24 import androidx.camera.core.impl.Config; 25 import androidx.camera.core.impl.SessionConfig; 26 import androidx.camera.core.impl.StreamSpec; 27 import androidx.camera.core.impl.UseCaseConfig; 28 import androidx.camera.core.impl.UseCaseConfigFactory; 29 import androidx.camera.core.impl.UseCaseConfigFactory.CaptureType; 30 import androidx.core.util.Supplier; 31 32 import org.jspecify.annotations.NonNull; 33 import org.jspecify.annotations.Nullable; 34 35 import java.util.Collections; 36 import java.util.List; 37 import java.util.Set; 38 import java.util.concurrent.atomic.AtomicInteger; 39 40 /** 41 * A fake {@link UseCase}. 42 */ 43 public class FakeUseCase extends UseCase { 44 45 private static final int DEFAULT_SURFACE_OCCUPANCY_PRIORITY = 0; 46 47 private volatile boolean mIsDetached = false; 48 private final AtomicInteger mStateAttachedCount = new AtomicInteger(0); 49 private final CaptureType mCaptureType; 50 private boolean mMergedConfigRetrieved = false; 51 private int mPipelineCreationCount = 0; 52 private Supplier<SessionConfig> mSessionConfigSupplier; 53 private Set<Integer> mEffectTargets = Collections.emptySet(); 54 55 /** 56 * Creates a new instance of a {@link FakeUseCase} with a given configuration and capture type. 57 */ FakeUseCase(@onNull FakeUseCaseConfig config, @NonNull CaptureType captureType)58 public FakeUseCase(@NonNull FakeUseCaseConfig config, @NonNull CaptureType captureType) { 59 super(config); 60 mCaptureType = captureType; 61 } 62 63 /** 64 * Creates a new instance of a {@link FakeUseCase} with a given configuration. 65 */ FakeUseCase(@onNull FakeUseCaseConfig config)66 public FakeUseCase(@NonNull FakeUseCaseConfig config) { 67 this(config, CaptureType.PREVIEW); 68 } 69 70 /** 71 * Creates a new instance of a {@link FakeUseCase} with a default configuration. 72 */ FakeUseCase()73 public FakeUseCase() { 74 this(new FakeUseCaseConfig.Builder() 75 .setSurfaceOccupancyPriority(DEFAULT_SURFACE_OCCUPANCY_PRIORITY) 76 .setCaptureType(CaptureType.PREVIEW) 77 .getUseCaseConfig()); 78 } 79 80 /** 81 * {@inheritDoc} 82 * 83 */ 84 @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) 85 @Override getUseCaseConfigBuilder(@onNull Config config)86 public UseCaseConfig.@NonNull Builder<?, ?, ?> getUseCaseConfigBuilder(@NonNull Config config) { 87 return new FakeUseCaseConfig.Builder(config) 88 .setCaptureType(mCaptureType) 89 .setSessionOptionUnpacker((resolution, useCaseConfig, sessionConfigBuilder) -> { 90 }); 91 } 92 93 /** 94 * {@inheritDoc} 95 * 96 */ 97 @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) 98 @Override getDefaultConfig(boolean applyDefaultConfig, @NonNull UseCaseConfigFactory factory)99 public @Nullable UseCaseConfig<?> getDefaultConfig(boolean applyDefaultConfig, 100 @NonNull UseCaseConfigFactory factory) { 101 Config config = factory.getConfig( 102 mCaptureType, 103 ImageCapture.CAPTURE_MODE_MINIMIZE_LATENCY); 104 return config == null ? null : getUseCaseConfigBuilder(config).getUseCaseConfig(); 105 } 106 107 @Override onMergeConfig(@onNull CameraInfoInternal cameraInfo, UseCaseConfig.@NonNull Builder<?, ?, ?> builder)108 protected @NonNull UseCaseConfig<?> onMergeConfig(@NonNull CameraInfoInternal cameraInfo, 109 UseCaseConfig.@NonNull Builder<?, ?, ?> builder) { 110 mMergedConfigRetrieved = true; 111 return builder.getUseCaseConfig(); 112 } 113 114 @Override onUnbind()115 public void onUnbind() { 116 super.onUnbind(); 117 mIsDetached = true; 118 } 119 120 @Override onStateAttached()121 public void onStateAttached() { 122 super.onStateAttached(); 123 mStateAttachedCount.incrementAndGet(); 124 } 125 126 @Override onStateDetached()127 public void onStateDetached() { 128 super.onStateDetached(); 129 mStateAttachedCount.decrementAndGet(); 130 } 131 132 @Override onSuggestedStreamSpecUpdated( @onNull StreamSpec primaryStreamSpec, @Nullable StreamSpec secondaryStreamSpec)133 protected @NonNull StreamSpec onSuggestedStreamSpecUpdated( 134 @NonNull StreamSpec primaryStreamSpec, 135 @Nullable StreamSpec secondaryStreamSpec) { 136 SessionConfig sessionConfig = createPipeline(); 137 if (sessionConfig != null) { 138 updateSessionConfig(List.of(sessionConfig)); 139 } 140 return primaryStreamSpec; 141 } 142 createPipeline()143 @Nullable SessionConfig createPipeline() { 144 mPipelineCreationCount++; 145 if (mSessionConfigSupplier != null) { 146 return mSessionConfigSupplier.get(); 147 } else { 148 return null; 149 } 150 } 151 152 /** 153 * Sets effect targets. 154 */ setSupportedEffectTargets(@onNull Set<Integer> effectTargets)155 public void setSupportedEffectTargets(@NonNull Set<Integer> effectTargets) { 156 mEffectTargets = effectTargets; 157 } 158 159 /** 160 * @inheritDoc 161 */ 162 @Override getSupportedEffectTargets()163 public @NonNull Set<Integer> getSupportedEffectTargets() { 164 return mEffectTargets; 165 } 166 167 168 /** 169 * Returns true if {@link #onUnbind()} has been called previously. 170 */ isDetached()171 public boolean isDetached() { 172 return mIsDetached; 173 } 174 175 /** 176 * Returns true if {@link #onStateAttached()} has been called previously. 177 */ getStateAttachedCount()178 public int getStateAttachedCount() { 179 return mStateAttachedCount.get(); 180 } 181 182 /** 183 * Returns true if {@link #mergeConfigs} have been invoked. 184 */ getMergedConfigRetrieved()185 public boolean getMergedConfigRetrieved() { 186 return mMergedConfigRetrieved; 187 } 188 189 /** 190 * Returns how many times the pipeline has been created. 191 */ getPipelineCreationCount()192 public int getPipelineCreationCount() { 193 return mPipelineCreationCount; 194 } 195 196 /** 197 * Returns {@link CameraCaptureResult} received by this use case. 198 */ setSessionConfigSupplier(@onNull Supplier<SessionConfig> sessionConfigSupplier)199 public void setSessionConfigSupplier(@NonNull Supplier<SessionConfig> sessionConfigSupplier) { 200 mSessionConfigSupplier = sessionConfigSupplier; 201 } 202 203 /** 204 * Calls the protected method {@link UseCase#updateSessionConfig}. 205 */ updateSessionConfigForTesting(@onNull SessionConfig sessionConfig)206 public void updateSessionConfigForTesting(@NonNull SessionConfig sessionConfig) { 207 updateSessionConfig(List.of(sessionConfig)); 208 } 209 210 /** 211 * Calls the protected method {@link UseCase#notifyActive()}. 212 */ notifyActiveForTesting()213 public void notifyActiveForTesting() { 214 notifyActive(); 215 } 216 217 /** 218 * Calls the protected method {@link UseCase#notifyInactive()}. 219 */ notifyInactiveForTesting()220 public void notifyInactiveForTesting() { 221 notifyInactive(); 222 } 223 224 /** 225 * Calls the protected method {@link UseCase#notifyUpdated()}. 226 */ notifyUpdatedForTesting()227 public void notifyUpdatedForTesting() { 228 notifyUpdated(); 229 } 230 231 /** 232 * Calls the protected method {@link UseCase#notifyReset()}. 233 */ notifyResetForTesting()234 public void notifyResetForTesting() { 235 notifyReset(); 236 } 237 } 238