• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2014 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 android.hardware.cts.helpers;
18 
19 import static org.junit.Assert.assertNotNull;
20 
21 import android.content.Context;
22 import android.content.res.Resources;
23 import android.graphics.SurfaceTexture;
24 import android.hardware.Camera;
25 import android.hardware.Camera.Parameters;
26 import android.hardware.Camera.Size;
27 import android.hardware.camera2.CameraCharacteristics;
28 import android.hardware.camera2.CameraManager;
29 import android.hardware.camera2.CameraMetadata;
30 import android.hardware.camera2.cts.helpers.StaticMetadata;
31 import android.hardware.devicestate.DeviceStateManager;
32 import android.os.Bundle;
33 import android.os.SystemClock;
34 import android.util.Log;
35 import android.view.TextureView;
36 
37 import androidx.test.InstrumentationRegistry;
38 
39 import java.util.Arrays;
40 import java.util.Comparator;
41 import java.util.List;
42 import java.util.Set;
43 import java.util.stream.Collectors;
44 import java.util.stream.IntStream;
45 
46 /**
47  * Utility class containing helper functions for the Camera CTS tests.
48  */
49 public class CameraUtils {
50     private static final float FOCAL_LENGTH_TOLERANCE = .01f;
51 
52 
53     private static final String TAG = "CameraUtils";
54     private static final long SHORT_SLEEP_WAIT_TIME_MS = 100;
55 
56     /**
57      * Returns {@code true} if this device only supports {@code LEGACY} mode operation in the
58      * Camera2 API for the given camera ID.
59      *
60      * @param context {@link Context} to access the {@link CameraManager} in.
61      * @param cameraId the ID of the camera device to check.
62      * @return {@code true} if this device only supports {@code LEGACY} mode.
63      */
isLegacyHAL(Context context, int cameraId)64     public static boolean isLegacyHAL(Context context, int cameraId) throws Exception {
65         CameraManager manager = (CameraManager) context.getSystemService(Context.CAMERA_SERVICE);
66         String cameraIdStr = manager.getCameraIdListNoLazy()[cameraId];
67         return isLegacyHAL(manager, cameraIdStr);
68     }
69 
70     /**
71      * Returns {@code true} if this device only supports {@code LEGACY} mode operation in the
72      * Camera2 API for the given camera ID.
73      *
74      * @param manager The {@link CameraManager} used to retrieve camera characteristics.
75      * @param cameraId the ID of the camera device to check.
76      * @return {@code true} if this device only supports {@code LEGACY} mode.
77      */
isLegacyHAL(CameraManager manager, String cameraIdStr)78     public static boolean isLegacyHAL(CameraManager manager, String cameraIdStr) throws Exception {
79         CameraCharacteristics characteristics =
80                 manager.getCameraCharacteristics(cameraIdStr);
81 
82         return characteristics.get(CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL) ==
83                 CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY;
84     }
85 
86     /**
87      * Returns {@code true} if the Camera.Parameter and Camera.Info arguments describe a similar
88      * camera as the CameraCharacteristics.
89      *
90      * @param params Camera.Parameters to use for matching.
91      * @param info Camera.CameraInfo to use for matching.
92      * @param ch CameraCharacteristics to use for matching.
93      * @return {@code true} if the arguments describe similar camera devices.
94      */
matchParametersToCharacteristics(Camera.Parameters params, Camera.CameraInfo info, CameraCharacteristics ch)95     public static boolean matchParametersToCharacteristics(Camera.Parameters params,
96             Camera.CameraInfo info, CameraCharacteristics ch) {
97         Integer facing = ch.get(CameraCharacteristics.LENS_FACING);
98         switch (facing.intValue()) {
99             case CameraMetadata.LENS_FACING_EXTERNAL:
100                 if (info.facing != Camera.CameraInfo.CAMERA_FACING_FRONT &&
101                     info.facing != Camera.CameraInfo.CAMERA_FACING_BACK) {
102                     return false;
103                 }
104                 break;
105             case CameraMetadata.LENS_FACING_FRONT:
106                 if (info.facing != Camera.CameraInfo.CAMERA_FACING_FRONT) {
107                     return false;
108                 }
109                 break;
110             case CameraMetadata.LENS_FACING_BACK:
111                 if (info.facing != Camera.CameraInfo.CAMERA_FACING_BACK) {
112                     return false;
113                 }
114                 break;
115             default:
116                 return false;
117         }
118 
119         Integer orientation = ch.get(CameraCharacteristics.SENSOR_ORIENTATION);
120         if (orientation.intValue() != info.orientation) {
121             return false;
122         }
123 
124         StaticMetadata staticMeta = new StaticMetadata(ch);
125         boolean legacyHasFlash = params.getSupportedFlashModes() != null;
126         if (staticMeta.hasFlash() != legacyHasFlash) {
127             return false;
128         }
129 
130         boolean isExternal = (ch.get(CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL) ==
131                 CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_EXTERNAL);
132         boolean hasValidMinFocusDistance = staticMeta.areKeysAvailable(
133                 CameraCharacteristics.LENS_INFO_MINIMUM_FOCUS_DISTANCE);
134         boolean fixedFocusExternal = isExternal && !hasValidMinFocusDistance;
135         boolean hasFocuser = staticMeta.hasFocuser() && !fixedFocusExternal;
136         List<String> legacyFocusModes = params.getSupportedFocusModes();
137         boolean legacyHasFocuser = !((legacyFocusModes.size() == 1) &&
138                 (legacyFocusModes.contains(Camera.Parameters.FOCUS_MODE_FIXED)));
139         if (hasFocuser != legacyHasFocuser) {
140             return false;
141         }
142 
143         if (staticMeta.isVideoStabilizationSupported() !=
144                 params.isVideoStabilizationSupported()) {
145             return false;
146         }
147 
148         float legacyFocalLength = params.getFocalLength();
149         if (ch.get(CameraCharacteristics.LENS_INFO_AVAILABLE_FOCAL_LENGTHS) != null) {
150             float [] focalLengths = staticMeta.getAvailableFocalLengthsChecked();
151             boolean found = false;
152             for (float focalLength : focalLengths) {
153                 if (Math.abs(focalLength - legacyFocalLength) <= FOCAL_LENGTH_TOLERANCE) {
154                     found = true;
155                     break;
156                 }
157             }
158             return found;
159         } else if (legacyFocalLength != -1.0f) {
160             return false;
161         }
162 
163         return true;
164     }
165 
166     /**
167      * Returns {@code true} if this device only supports {@code EXTERNAL} mode operation in the
168      * Camera2 API for the given camera ID.
169      *
170      * @param context {@link Context} to access the {@link CameraManager} in.
171      * @param cameraId the ID of the camera device to check.
172      * @return {@code true} if this device only supports {@code LEGACY} mode.
173      */
isExternal(Context context, int cameraId)174     public static boolean isExternal(Context context, int cameraId) throws Exception {
175         CameraManager manager = (CameraManager) context.getSystemService(Context.CAMERA_SERVICE);
176 
177         Camera camera = null;
178         Camera.Parameters params = null;
179         Camera.CameraInfo info = new Camera.CameraInfo();
180         try {
181             Camera.getCameraInfo(cameraId, info);
182             camera = Camera.open(cameraId);
183             params = camera.getParameters();
184         } finally {
185             if (camera != null) {
186                 camera.release();
187             }
188         }
189 
190         String [] cameraIdList = manager.getCameraIdList();
191         CameraCharacteristics characteristics =
192                 manager.getCameraCharacteristics(cameraIdList[cameraId]);
193 
194         if (!matchParametersToCharacteristics(params, info, characteristics)) {
195             boolean found = false;
196             for (String id : cameraIdList) {
197                 characteristics = manager.getCameraCharacteristics(id);
198                 if (matchParametersToCharacteristics(params, info, characteristics)) {
199                     found = true;
200                     break;
201                 }
202             }
203             if (!found) {
204                 return false;
205             }
206         }
207 
208         return characteristics.get(CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL) ==
209                 CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_EXTERNAL;
210     }
211 
212     /**
213      * Shared size comparison method used by size comparators.
214      *
215      * <p>Compares the number of pixels it covers.If two the areas of two sizes are same, compare
216      * the widths.</p>
217      */
compareSizes(int widthA, int heightA, int widthB, int heightB)218      public static int compareSizes(int widthA, int heightA, int widthB, int heightB) {
219         long left = widthA * (long) heightA;
220         long right = widthB * (long) heightB;
221         if (left == right) {
222             left = widthA;
223             right = widthB;
224         }
225         return (left < right) ? -1 : (left > right ? 1 : 0);
226     }
227 
228     /**
229      * Size comparator that compares the number of pixels it covers.
230      *
231      * <p>If two the areas of two sizes are same, compare the widths.</p>
232      */
233     public static class LegacySizeComparator implements Comparator<Camera.Size> {
234         @Override
compare(Camera.Size lhs, Camera.Size rhs)235         public int compare(Camera.Size lhs, Camera.Size rhs) {
236             return compareSizes(lhs.width, lhs.height, rhs.width, rhs.height);
237         }
238     }
239 
getOverrideCameraId()240     public static String getOverrideCameraId() {
241         Bundle bundle = InstrumentationRegistry.getArguments();
242         return bundle.getString("camera-id");
243     }
244 
deriveCameraIdsUnderTest()245     public static int[] deriveCameraIdsUnderTest() throws Exception {
246         String overrideId = getOverrideCameraId();
247         int numberOfCameras = Camera.getNumberOfCameras();
248         int[] cameraIds;
249         if (overrideId == null) {
250             cameraIds = IntStream.range(0, numberOfCameras).toArray();
251         } else {
252             int overrideCameraId = Integer.parseInt(overrideId);
253             if (overrideCameraId >= 0 && overrideCameraId < numberOfCameras) {
254                 cameraIds = new int[]{overrideCameraId};
255             } else {
256                 cameraIds = new int[]{};
257             }
258         }
259         return cameraIds;
260     }
261 
262     /**
263      * Wait until the SurfaceTexture available from the TextureView, then return it.
264      * Return null if the wait times out.
265      *
266      * @param timeOutMs The timeout value for the wait
267      * @return The available SurfaceTexture, return null if the wait times out.
268     */
getAvailableSurfaceTexture(long timeOutMs, TextureView view)269     public static SurfaceTexture getAvailableSurfaceTexture(long timeOutMs, TextureView view) {
270         long waitTime = timeOutMs;
271 
272         while (!view.isAvailable() && waitTime > 0) {
273             long startTimeMs = SystemClock.elapsedRealtime();
274             SystemClock.sleep(SHORT_SLEEP_WAIT_TIME_MS);
275             waitTime -= (SystemClock.elapsedRealtime() - startTimeMs);
276         }
277 
278         if (view.isAvailable()) {
279             return view.getSurfaceTexture();
280         } else {
281             Log.w(TAG, "Wait for SurfaceTexture available timed out after " + timeOutMs + "ms");
282             return null;
283         }
284     }
285 
286     /**
287      * Uses {@link DeviceStateManager} to determine if the device is foldable or not. It relies on
288      * the OEM exposing supported states, and setting
289      * com.android.internal.R.array.config_foldedDeviceStates correctly with the folded states.
290      *
291      * @return true is the device is a foldable; false otherwise
292      */
isDeviceFoldable(Context mContext)293     public static boolean isDeviceFoldable(Context mContext) {
294         DeviceStateManager deviceStateManager =
295                 mContext.getSystemService(DeviceStateManager.class);
296         if (deviceStateManager == null) {
297             Log.w(TAG, "Couldn't locate DeviceStateManager to detect if the device is foldable"
298                     + " or not. Defaulting to not-foldable.");
299             return false;
300         }
301         Set<Integer> supportedStates = Arrays.stream(
302                 deviceStateManager.getSupportedStates()).boxed().collect(Collectors.toSet());
303 
304         Resources systemRes = Resources.getSystem();
305         int foldedStatesArrayIdentifier = systemRes.getIdentifier("config_foldedDeviceStates",
306                 "array", "android");
307         int[] foldedDeviceStates = systemRes.getIntArray(foldedStatesArrayIdentifier);
308 
309         // Device is a foldable if supportedStates contains any state in foldedDeviceStates
310         return Arrays.stream(foldedDeviceStates).anyMatch(supportedStates::contains);
311     }
312 
313     /**
314      * Returns Gets the supported video frame sizes that can be used by MediaRecorder.
315      *
316      * @param camera Camera for which to get the supported video sizes.
317      * @return a list of Size object if camera has separate preview and video output;
318      * in case there isn't a separate video/preview size option,
319      * it returns the preview sizes.
320      */
getSupportedVideoSizes(Camera camera)321     public static List<Size> getSupportedVideoSizes(Camera camera) {
322         Parameters parameters = camera.getParameters();
323         assertNotNull("Camera did not provide parameters", parameters);
324         List<Size> videoSizes = parameters.getSupportedVideoSizes();
325 
326         if (videoSizes == null) {
327             videoSizes = parameters.getSupportedPreviewSizes();
328             assertNotNull(videoSizes);
329         }
330 
331         return videoSizes;
332     }
333 }
334