| /* |
| * Copyright 2020 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 android.hardware.camera2.cts; |
| |
| import android.content.Context; |
| import android.graphics.ImageFormat; |
| import android.graphics.SurfaceTexture; |
| import android.hardware.camera2.CameraExtensionCharacteristics; |
| import android.hardware.camera2.CaptureRequest; |
| import android.hardware.camera2.CaptureResult; |
| import android.hardware.camera2.cts.helpers.StaticMetadata; |
| import android.hardware.camera2.cts.testcases.Camera2AndroidTestRule; |
| import android.platform.test.annotations.AppModeFull; |
| import android.renderscript.Allocation; |
| import android.util.ArraySet; |
| import android.util.Log; |
| import android.util.Range; |
| import android.util.Size; |
| |
| import androidx.test.InstrumentationRegistry; |
| |
| import com.android.compatibility.common.util.PropertyUtil; |
| |
| import java.util.ArrayList; |
| import java.util.Arrays; |
| import java.util.List; |
| import java.util.Set; |
| |
| import static org.junit.Assert.*; |
| |
| import org.junit.Rule; |
| import org.junit.Test; |
| import org.junit.runner.RunWith; |
| import org.junit.runners.JUnit4; |
| |
| @RunWith(JUnit4.class) |
| public class CameraExtensionCharacteristicsTest { |
| private static final String TAG = "CameraExtensionManagerTest"; |
| private static final boolean VERBOSE = Log.isLoggable(TAG, Log.VERBOSE); |
| private static final List<Integer> EXTENSIONS = Arrays.asList( |
| CameraExtensionCharacteristics.EXTENSION_AUTOMATIC, |
| CameraExtensionCharacteristics.EXTENSION_BEAUTY, |
| CameraExtensionCharacteristics.EXTENSION_BOKEH, |
| CameraExtensionCharacteristics.EXTENSION_HDR, |
| CameraExtensionCharacteristics.EXTENSION_NIGHT); |
| |
| private final Context mContext = InstrumentationRegistry.getTargetContext(); |
| |
| @Rule |
| public final Camera2AndroidTestRule mTestRule = new Camera2AndroidTestRule(mContext); |
| |
| private void openDevice(String cameraId) throws Exception { |
| mTestRule.setCamera(CameraTestUtils.openCamera( |
| mTestRule.getCameraManager(), cameraId, |
| mTestRule.getCameraListener(), mTestRule.getHandler())); |
| mTestRule.getCollector().setCameraId(cameraId); |
| mTestRule.setStaticInfo(new StaticMetadata( |
| mTestRule.getCameraManager().getCameraCharacteristics(cameraId), |
| StaticMetadata.CheckLevel.ASSERT, /*collector*/null)); |
| } |
| |
| private <T> void verifySupportedExtension(CameraExtensionCharacteristics chars, String cameraId, |
| Integer extension, Class<T> klass) { |
| List<Size> availableSizes = chars.getExtensionSupportedSizes(extension, klass); |
| assertTrue(String.format("Supported extension %d on camera id: %s doesn't " + |
| "include any valid resolutions!", extension, cameraId), |
| (availableSizes != null) && (!availableSizes.isEmpty())); |
| } |
| |
| private <T> void verifySupportedSizes(CameraExtensionCharacteristics chars, String cameraId, |
| Integer extension, Class<T> klass) throws Exception { |
| verifySupportedExtension(chars, cameraId, extension, klass); |
| try { |
| openDevice(cameraId); |
| List<Size> extensionSizes = chars.getExtensionSupportedSizes(extension, klass); |
| List<Size> cameraSizes = Arrays.asList( |
| mTestRule.getStaticInfo().getAvailableSizesForFormatChecked(ImageFormat.PRIVATE, |
| StaticMetadata.StreamDirection.Output)); |
| for (Size extensionSize : extensionSizes) { |
| assertTrue(String.format("Supported extension %d on camera id: %s advertises " + |
| " resolution %s unsupported by camera", extension, cameraId, |
| extensionSize), cameraSizes.contains(extensionSize)); |
| } |
| } finally { |
| mTestRule.closeDevice(cameraId); |
| } |
| } |
| |
| private void verifySupportedSizes(CameraExtensionCharacteristics chars, String cameraId, |
| Integer extension, int format) throws Exception { |
| List<Size> extensionSizes = chars.getExtensionSupportedSizes(extension, format); |
| assertFalse(String.format("No available sizes for extension %d on camera id: %s " + |
| "using format: %x", extension, cameraId, format), extensionSizes.isEmpty()); |
| try { |
| openDevice(cameraId); |
| List<Size> cameraSizes = Arrays.asList( |
| mTestRule.getStaticInfo().getAvailableSizesForFormatChecked(format, |
| StaticMetadata.StreamDirection.Output)); |
| for (Size extensionSize : extensionSizes) { |
| assertTrue(String.format("Supported extension %d on camera id: %s advertises " + |
| " resolution %s unsupported by camera", extension, cameraId, |
| extensionSize), cameraSizes.contains(extensionSize)); |
| } |
| } finally { |
| mTestRule.closeDevice(cameraId); |
| } |
| } |
| |
| private <T> void verifyUnsupportedExtension(CameraExtensionCharacteristics chars, |
| Integer extension, Class<T> klass) { |
| try { |
| chars.getExtensionSupportedSizes(extension, klass); |
| fail("should get IllegalArgumentException due to unsupported extension"); |
| } catch (IllegalArgumentException e) { |
| // Expected |
| } |
| } |
| |
| @Test |
| @AppModeFull(reason = "Instant apps can't access Test API") |
| public void testExtensionAvailability() throws Exception { |
| boolean extensionsAdvertised = false; |
| for (String id : mTestRule.getCameraIdsUnderTest()) { |
| StaticMetadata staticMeta = |
| new StaticMetadata(mTestRule.getCameraManager().getCameraCharacteristics(id)); |
| if (!staticMeta.isColorOutputSupported()) { |
| continue; |
| } |
| CameraExtensionCharacteristics extensionChars = |
| mTestRule.getCameraManager().getCameraExtensionCharacteristics(id); |
| ArrayList<Integer> unsupportedExtensions = new ArrayList<>(EXTENSIONS); |
| List<Integer> supportedExtensions = extensionChars.getSupportedExtensions(); |
| if (!extensionsAdvertised && !supportedExtensions.isEmpty()) { |
| extensionsAdvertised = true; |
| } |
| for (Integer extension : supportedExtensions) { |
| verifySupportedExtension(extensionChars, id, extension, SurfaceTexture.class); |
| unsupportedExtensions.remove(extension); |
| } |
| |
| // Unsupported extension size queries must throw corresponding exception. |
| for (Integer extension : unsupportedExtensions) { |
| verifyUnsupportedExtension(extensionChars, extension, SurfaceTexture.class); |
| } |
| } |
| boolean extensionsEnabledProp = PropertyUtil.areCameraXExtensionsEnabled(); |
| assertEquals("Extensions system property : " + extensionsEnabledProp + " does not match " + |
| "with the advertised extensions: " + extensionsAdvertised, extensionsEnabledProp, |
| extensionsAdvertised); |
| } |
| |
| @Test |
| public void testExtensionSizes() throws Exception { |
| for (String id : mTestRule.getCameraIdsUnderTest()) { |
| StaticMetadata staticMeta = |
| new StaticMetadata(mTestRule.getCameraManager().getCameraCharacteristics(id)); |
| if (!staticMeta.isColorOutputSupported()) { |
| continue; |
| } |
| CameraExtensionCharacteristics extensionChars = |
| mTestRule.getCameraManager().getCameraExtensionCharacteristics(id); |
| List<Integer> supportedExtensions = extensionChars.getSupportedExtensions(); |
| for (Integer extension : supportedExtensions) { |
| verifySupportedSizes(extensionChars, id, extension, SurfaceTexture.class); |
| verifySupportedSizes(extensionChars, id, extension, ImageFormat.JPEG); |
| } |
| } |
| } |
| |
| @Test |
| public void testIllegalArguments() throws Exception { |
| try { |
| mTestRule.getCameraManager().getCameraExtensionCharacteristics("InvalidCameraId!"); |
| fail("should get IllegalArgumentException due to invalid camera id"); |
| } catch (IllegalArgumentException e) { |
| // Expected |
| } |
| |
| for (String id : mTestRule.getCameraIdsUnderTest()) { |
| CameraExtensionCharacteristics extensionChars = |
| mTestRule.getCameraManager().getCameraExtensionCharacteristics(id); |
| List<Integer> supportedExtensions = extensionChars.getSupportedExtensions(); |
| for (Integer extension : supportedExtensions) { |
| try { |
| extensionChars.getExtensionSupportedSizes(extension, ImageFormat.UNKNOWN); |
| fail("should get IllegalArgumentException due to invalid pixel format"); |
| } catch (IllegalArgumentException e) { |
| // Expected |
| } |
| |
| try { |
| List<Size> ret = extensionChars.getExtensionSupportedSizes(extension, |
| Allocation.class); |
| assertTrue("should get empty resolution list for unsupported " + |
| "surface type", ret.isEmpty()); |
| } catch (IllegalArgumentException e) { |
| fail("should not get IllegalArgumentException due to unsupported surface " + |
| "type"); |
| } |
| } |
| } |
| } |
| |
| @Test |
| public void testExtensionLatencyRanges() throws Exception { |
| final int testFormat = ImageFormat.JPEG; |
| for (String id : mTestRule.getCameraIdsUnderTest()) { |
| StaticMetadata staticMeta = |
| new StaticMetadata(mTestRule.getCameraManager().getCameraCharacteristics(id)); |
| if (!staticMeta.isColorOutputSupported()) { |
| continue; |
| } |
| |
| CameraExtensionCharacteristics chars = |
| mTestRule.getCameraManager().getCameraExtensionCharacteristics(id); |
| List<Integer> supportedExtensions = chars.getSupportedExtensions(); |
| for (Integer extension : supportedExtensions) { |
| List<Size> extensionSizes = chars.getExtensionSupportedSizes(extension, testFormat); |
| for (Size sz : extensionSizes) { |
| Range<Long> latencyRange = chars.getEstimatedCaptureLatencyRangeMillis( |
| extension, sz, testFormat); |
| if (latencyRange != null) { |
| assertTrue("Negative range surface type", (latencyRange.getLower() > 0) && |
| (latencyRange.getUpper() > 0)); |
| assertTrue("Lower range value must be smaller compared to the upper", |
| (latencyRange.getLower() < latencyRange.getUpper())); |
| } |
| } |
| } |
| } |
| } |
| |
| @Test |
| public void testExtensionRequestKeys() throws Exception { |
| for (String id : mTestRule.getCameraIdsUnderTest()) { |
| StaticMetadata staticMeta = |
| new StaticMetadata(mTestRule.getCameraManager().getCameraCharacteristics(id)); |
| if (!staticMeta.isColorOutputSupported()) { |
| continue; |
| } |
| |
| CameraExtensionCharacteristics chars = |
| mTestRule.getCameraManager().getCameraExtensionCharacteristics(id); |
| List<Integer> supportedExtensions = chars.getSupportedExtensions(); |
| for (Integer extension : supportedExtensions) { |
| Set<CaptureRequest.Key> captureKeySet = |
| chars.getAvailableCaptureRequestKeys(extension); |
| ArraySet<CaptureRequest.Key> captureKeys = new ArraySet<>(captureKeySet); |
| // No repeating keys allowed |
| assertEquals(captureKeys.size(), captureKeySet.size()); |
| // Jpeg quality and jpeg orientation must always be available |
| assertTrue(captureKeys.contains(CaptureRequest.JPEG_QUALITY)); |
| assertTrue(captureKeys.contains(CaptureRequest.JPEG_ORIENTATION)); |
| // The extension request keys must always match or be a subset of the regular keys |
| for (CaptureRequest.Key captureKey : captureKeys) { |
| String msg = String.format("Supported extension request key %s doesn't appear " |
| + " int the regular camera characteristics list of supported keys!", |
| captureKey.getName()); |
| assertTrue(msg, staticMeta.areKeysAvailable(captureKey)); |
| } |
| } |
| } |
| } |
| |
| @Test |
| public void testExtensionResultKeys() throws Exception { |
| for (String id : mTestRule.getCameraIdsUnderTest()) { |
| StaticMetadata staticMeta = |
| new StaticMetadata(mTestRule.getCameraManager().getCameraCharacteristics(id)); |
| if (!staticMeta.isColorOutputSupported()) { |
| continue; |
| } |
| |
| CameraExtensionCharacteristics chars = |
| mTestRule.getCameraManager().getCameraExtensionCharacteristics(id); |
| List<Integer> supportedExtensions = chars.getSupportedExtensions(); |
| for (Integer extension : supportedExtensions) { |
| Set<CaptureResult.Key> resultKeySet = |
| chars.getAvailableCaptureResultKeys(extension); |
| if (resultKeySet.isEmpty()) { |
| // Extension capture result support is optional |
| continue; |
| } |
| |
| ArraySet<CaptureResult.Key> resultKeys = new ArraySet<>(resultKeySet); |
| ArraySet<String> resultKeyNames = new ArraySet<>(resultKeys.size()); |
| // No repeating keys allowed |
| assertEquals(resultKeys.size(), resultKeySet.size()); |
| // Sensor timestamp, jpeg quality and jpeg orientation must always be available |
| assertTrue(resultKeys.contains(CaptureResult.SENSOR_TIMESTAMP)); |
| assertTrue(resultKeys.contains(CaptureResult.JPEG_QUALITY)); |
| assertTrue(resultKeys.contains(CaptureResult.JPEG_ORIENTATION)); |
| // The extension result keys must always match or be a subset of the regular result |
| // keys |
| for (CaptureResult.Key resultKey : resultKeys) { |
| String msg = String.format("Supported extension result key %s doesn't appear " |
| + " in the regular camera characteristics list of supported keys!", |
| resultKey.getName()); |
| assertTrue(msg, staticMeta.areKeysAvailable(resultKey)); |
| resultKeyNames.add(resultKey.getName()); |
| } |
| |
| ArraySet<CaptureRequest.Key> captureKeys = new ArraySet<>( |
| chars.getAvailableCaptureRequestKeys(extension)); |
| for (CaptureRequest.Key requestKey : captureKeys) { |
| String msg = String.format("Supported extension request key %s doesn't appear " |
| + " in the corresponding supported extension result key list!", |
| requestKey.getName()); |
| assertTrue(msg, resultKeyNames.contains(requestKey.getName())); |
| } |
| } |
| } |
| } |
| } |