1 /*
2  * Copyright 2019 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.fakes;
18 
19 import static android.graphics.ImageFormat.YUV_420_888;
20 
21 import static androidx.camera.core.impl.StreamSpec.FRAME_RATE_RANGE_UNSPECIFIED;
22 import static androidx.camera.core.impl.SurfaceConfig.ConfigSize.PREVIEW;
23 import static androidx.camera.core.impl.SurfaceConfig.ConfigType.YUV;
24 
25 import static com.google.common.truth.Truth.assertThat;
26 
27 import static java.util.Collections.emptyList;
28 import static java.util.Collections.singletonList;
29 
30 import android.os.Build;
31 import android.util.Range;
32 import android.util.Size;
33 
34 import androidx.camera.core.DynamicRange;
35 import androidx.camera.core.ImageAnalysis;
36 import androidx.camera.core.impl.AttachedSurfaceInfo;
37 import androidx.camera.core.impl.CameraMode;
38 import androidx.camera.core.impl.StreamSpec;
39 import androidx.camera.core.impl.SurfaceConfig;
40 import androidx.camera.core.impl.UseCaseConfig;
41 import androidx.camera.core.impl.UseCaseConfigFactory;
42 import androidx.camera.testing.impl.fakes.FakeCameraDeviceSurfaceManager;
43 import androidx.camera.testing.impl.fakes.FakeUseCaseConfig;
44 
45 import org.jspecify.annotations.NonNull;
46 import org.junit.Before;
47 import org.junit.Test;
48 import org.junit.runner.RunWith;
49 import org.robolectric.RobolectricTestRunner;
50 import org.robolectric.annotation.Config;
51 import org.robolectric.annotation.internal.DoNotInstrument;
52 
53 import java.util.Collections;
54 import java.util.HashMap;
55 import java.util.List;
56 import java.util.Map;
57 
58 /**
59  * Unit tests for {@link FakeCameraDeviceSurfaceManager}.
60  */
61 @RunWith(RobolectricTestRunner.class)
62 @DoNotInstrument
63 @Config(minSdk = Build.VERSION_CODES.LOLLIPOP)
64 public class FakeCameraDeviceSurfaceManagerTest {
65 
66     private static final int FAKE_WIDTH0 = 400;
67     private static final int FAKE_HEIGHT0 = 300;
68 
69     private static final int FAKE_WIDTH1 = 800;
70     private static final int FAKE_HEIGHT1 = 600;
71 
72     private static final String FAKE_CAMERA_ID0 = "0";
73     private static final String FAKE_CAMERA_ID1 = "1";
74 
75     private FakeCameraDeviceSurfaceManager mFakeCameraDeviceSurfaceManager;
76 
77     private FakeUseCaseConfig mFakeUseCaseConfig;
78 
79     @Before
setUp()80     public void setUp() {
81         mFakeCameraDeviceSurfaceManager = new FakeCameraDeviceSurfaceManager();
82         mFakeUseCaseConfig = new FakeUseCaseConfig.Builder().getUseCaseConfig();
83 
84         mFakeCameraDeviceSurfaceManager.setSuggestedStreamSpec(FAKE_CAMERA_ID0,
85                 mFakeUseCaseConfig.getClass(),
86                 StreamSpec.builder(new Size(FAKE_WIDTH0, FAKE_HEIGHT0)).build());
87         mFakeCameraDeviceSurfaceManager.setSuggestedStreamSpec(FAKE_CAMERA_ID1,
88                 mFakeUseCaseConfig.getClass(),
89                 StreamSpec.builder(new Size(FAKE_WIDTH1, FAKE_HEIGHT1)).build());
90     }
91 
92     @Test
validSurfaceCombination_noException()93     public void validSurfaceCombination_noException() {
94         UseCaseConfig<?> preview = new FakeUseCaseConfig.Builder().getUseCaseConfig();
95         UseCaseConfig<?> analysis = new ImageAnalysis.Builder().getUseCaseConfig();
96         mFakeCameraDeviceSurfaceManager.getSuggestedStreamSpecs(
97                 CameraMode.DEFAULT,
98                 FAKE_CAMERA_ID0,
99                 emptyList(),
100                 createConfigOutputSizesMap(preview, analysis),
101                 false,
102                 false);
103     }
104 
105     @Test(expected = IllegalArgumentException.class)
invalidSurfaceAndConfigCombination_throwException()106     public void invalidSurfaceAndConfigCombination_throwException() {
107         UseCaseConfig<?> preview = new FakeUseCaseConfig.Builder().getUseCaseConfig();
108         UseCaseConfig<?> video = new FakeUseCaseConfig.Builder().getUseCaseConfig();
109         AttachedSurfaceInfo analysis = AttachedSurfaceInfo.create(
110                         SurfaceConfig.create(YUV, PREVIEW),
111                         YUV_420_888,
112                         new Size(1, 1),
113                         DynamicRange.SDR,
114                         singletonList(UseCaseConfigFactory.CaptureType.IMAGE_ANALYSIS),
115                         preview,
116                         new Range<>(30, 30),
117                         FRAME_RATE_RANGE_UNSPECIFIED);
118         mFakeCameraDeviceSurfaceManager.getSuggestedStreamSpecs(
119                 CameraMode.DEFAULT,
120                 FAKE_CAMERA_ID0,
121                 singletonList(analysis), createConfigOutputSizesMap(preview, video),
122                 false,
123                 false);
124     }
125 
126     @Test(expected = IllegalArgumentException.class)
invalidConfigCombination_throwException()127     public void invalidConfigCombination_throwException() {
128         UseCaseConfig<?> preview = new FakeUseCaseConfig.Builder().getUseCaseConfig();
129         UseCaseConfig<?> video = new FakeUseCaseConfig.Builder().getUseCaseConfig();
130         UseCaseConfig<?> analysis = new ImageAnalysis.Builder().getUseCaseConfig();
131         mFakeCameraDeviceSurfaceManager.getSuggestedStreamSpecs(
132                 CameraMode.DEFAULT,
133                 FAKE_CAMERA_ID0,
134                 Collections.emptyList(), createConfigOutputSizesMap(preview, video, analysis),
135                 false,
136                 false);
137     }
138 
139     @Test
canRetrieveInsertedSuggestedStreamSpecs()140     public void canRetrieveInsertedSuggestedStreamSpecs() {
141         Map<UseCaseConfig<?>, StreamSpec> suggestedStreamSpecsCamera0 =
142                 mFakeCameraDeviceSurfaceManager.getSuggestedStreamSpecs(
143                         CameraMode.DEFAULT,
144                         FAKE_CAMERA_ID0,
145                         emptyList(), createConfigOutputSizesMap(mFakeUseCaseConfig),
146                         false,
147                         false).first;
148         Map<UseCaseConfig<?>, StreamSpec> suggestedStreamSpecCamera1 =
149                 mFakeCameraDeviceSurfaceManager.getSuggestedStreamSpecs(
150                         CameraMode.DEFAULT,
151                         FAKE_CAMERA_ID1,
152                         emptyList(), createConfigOutputSizesMap(mFakeUseCaseConfig),
153                         false,
154                         false).first;
155 
156         assertThat(suggestedStreamSpecsCamera0.get(mFakeUseCaseConfig)).isEqualTo(
157                 StreamSpec.builder(new Size(FAKE_WIDTH0, FAKE_HEIGHT0)).build());
158         assertThat(suggestedStreamSpecCamera1.get(mFakeUseCaseConfig)).isEqualTo(
159                 StreamSpec.builder(new Size(FAKE_WIDTH1, FAKE_HEIGHT1)).build());
160     }
161 
createConfigOutputSizesMap( UseCaseConfig<?> @onNull .... useCaseConfigs)162     private Map<UseCaseConfig<?>, List<Size>> createConfigOutputSizesMap(
163             UseCaseConfig<?> @NonNull ... useCaseConfigs) {
164         Map<UseCaseConfig<?>, List<Size>> configOutputSizesMap = new HashMap<>();
165         for (UseCaseConfig<?> useCaseConfig : useCaseConfigs) {
166             configOutputSizesMap.put(useCaseConfig, Collections.emptyList());
167         }
168         return configOutputSizesMap;
169     }
170 }
171