blob: 5b4b485dc42c4666573aed78193db29199e64b50 [file] [log] [blame]
/*
* Copyright 2014 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.cts.helpers;
import android.content.Context;
import android.graphics.SurfaceTexture;
import android.hardware.Camera;
import android.hardware.camera2.CameraCharacteristics;
import android.hardware.camera2.CameraManager;
import android.hardware.camera2.CameraMetadata;
import android.hardware.camera2.cts.helpers.StaticMetadata;
import android.os.Bundle;
import android.os.SystemClock;
import android.util.Log;
import android.view.TextureView;
import androidx.test.InstrumentationRegistry;
import java.util.Comparator;
import java.util.List;
import java.util.stream.IntStream;
/**
* Utility class containing helper functions for the Camera CTS tests.
*/
public class CameraUtils {
private static final float FOCAL_LENGTH_TOLERANCE = .01f;
private static final String TAG = "CameraUtils";
private static final long SHORT_SLEEP_WAIT_TIME_MS = 100;
/**
* Returns {@code true} if this device only supports {@code LEGACY} mode operation in the
* Camera2 API for the given camera ID.
*
* @param context {@link Context} to access the {@link CameraManager} in.
* @param cameraId the ID of the camera device to check.
* @return {@code true} if this device only supports {@code LEGACY} mode.
*/
public static boolean isLegacyHAL(Context context, int cameraId) throws Exception {
CameraManager manager = (CameraManager) context.getSystemService(Context.CAMERA_SERVICE);
String cameraIdStr = manager.getCameraIdListNoLazy()[cameraId];
return isLegacyHAL(manager, cameraIdStr);
}
/**
* Returns {@code true} if this device only supports {@code LEGACY} mode operation in the
* Camera2 API for the given camera ID.
*
* @param manager The {@link CameraManager} used to retrieve camera characteristics.
* @param cameraId the ID of the camera device to check.
* @return {@code true} if this device only supports {@code LEGACY} mode.
*/
public static boolean isLegacyHAL(CameraManager manager, String cameraIdStr) throws Exception {
CameraCharacteristics characteristics =
manager.getCameraCharacteristics(cameraIdStr);
return characteristics.get(CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL) ==
CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY;
}
/**
* Returns {@code true} if the Camera.Parameter and Camera.Info arguments describe a similar
* camera as the CameraCharacteristics.
*
* @param params Camera.Parameters to use for matching.
* @param info Camera.CameraInfo to use for matching.
* @param ch CameraCharacteristics to use for matching.
* @return {@code true} if the arguments describe similar camera devices.
*/
public static boolean matchParametersToCharacteristics(Camera.Parameters params,
Camera.CameraInfo info, CameraCharacteristics ch) {
Integer facing = ch.get(CameraCharacteristics.LENS_FACING);
switch (facing.intValue()) {
case CameraMetadata.LENS_FACING_EXTERNAL:
if (info.facing != Camera.CameraInfo.CAMERA_FACING_FRONT &&
info.facing != Camera.CameraInfo.CAMERA_FACING_BACK) {
return false;
}
break;
case CameraMetadata.LENS_FACING_FRONT:
if (info.facing != Camera.CameraInfo.CAMERA_FACING_FRONT) {
return false;
}
break;
case CameraMetadata.LENS_FACING_BACK:
if (info.facing != Camera.CameraInfo.CAMERA_FACING_BACK) {
return false;
}
break;
default:
return false;
}
Integer orientation = ch.get(CameraCharacteristics.SENSOR_ORIENTATION);
if (orientation.intValue() != info.orientation) {
return false;
}
StaticMetadata staticMeta = new StaticMetadata(ch);
boolean legacyHasFlash = params.getSupportedFlashModes() != null;
if (staticMeta.hasFlash() != legacyHasFlash) {
return false;
}
boolean isExternal = (ch.get(CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL) ==
CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_EXTERNAL);
boolean hasValidMinFocusDistance = staticMeta.areKeysAvailable(
CameraCharacteristics.LENS_INFO_MINIMUM_FOCUS_DISTANCE);
boolean fixedFocusExternal = isExternal && !hasValidMinFocusDistance;
boolean hasFocuser = staticMeta.hasFocuser() && !fixedFocusExternal;
List<String> legacyFocusModes = params.getSupportedFocusModes();
boolean legacyHasFocuser = !((legacyFocusModes.size() == 1) &&
(legacyFocusModes.contains(Camera.Parameters.FOCUS_MODE_FIXED)));
if (hasFocuser != legacyHasFocuser) {
return false;
}
if (staticMeta.isVideoStabilizationSupported() != params.isVideoStabilizationSupported()) {
return false;
}
float legacyFocalLength = params.getFocalLength();
if (ch.get(CameraCharacteristics.LENS_INFO_AVAILABLE_FOCAL_LENGTHS) != null) {
float [] focalLengths = staticMeta.getAvailableFocalLengthsChecked();
boolean found = false;
for (float focalLength : focalLengths) {
if (Math.abs(focalLength - legacyFocalLength) <= FOCAL_LENGTH_TOLERANCE) {
found = true;
break;
}
}
return found;
} else if (legacyFocalLength != -1.0f) {
return false;
}
return true;
}
/**
* Returns {@code true} if this device only supports {@code EXTERNAL} mode operation in the
* Camera2 API for the given camera ID.
*
* @param context {@link Context} to access the {@link CameraManager} in.
* @param cameraId the ID of the camera device to check.
* @return {@code true} if this device only supports {@code LEGACY} mode.
*/
public static boolean isExternal(Context context, int cameraId) throws Exception {
CameraManager manager = (CameraManager) context.getSystemService(Context.CAMERA_SERVICE);
Camera camera = null;
Camera.Parameters params = null;
Camera.CameraInfo info = new Camera.CameraInfo();
try {
Camera.getCameraInfo(cameraId, info);
camera = Camera.open(cameraId);
params = camera.getParameters();
} finally {
if (camera != null) {
camera.release();
}
}
String [] cameraIdList = manager.getCameraIdList();
CameraCharacteristics characteristics =
manager.getCameraCharacteristics(cameraIdList[cameraId]);
if (!matchParametersToCharacteristics(params, info, characteristics)) {
boolean found = false;
for (String id : cameraIdList) {
characteristics = manager.getCameraCharacteristics(id);
if (matchParametersToCharacteristics(params, info, characteristics)) {
found = true;
break;
}
}
if (!found) {
return false;
}
}
return characteristics.get(CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL) ==
CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_EXTERNAL;
}
/**
* Shared size comparison method used by size comparators.
*
* <p>Compares the number of pixels it covers.If two the areas of two sizes are same, compare
* the widths.</p>
*/
public static int compareSizes(int widthA, int heightA, int widthB, int heightB) {
long left = widthA * (long) heightA;
long right = widthB * (long) heightB;
if (left == right) {
left = widthA;
right = widthB;
}
return (left < right) ? -1 : (left > right ? 1 : 0);
}
/**
* Size comparator that compares the number of pixels it covers.
*
* <p>If two the areas of two sizes are same, compare the widths.</p>
*/
public static class LegacySizeComparator implements Comparator<Camera.Size> {
@Override
public int compare(Camera.Size lhs, Camera.Size rhs) {
return compareSizes(lhs.width, lhs.height, rhs.width, rhs.height);
}
}
public static String getOverrideCameraId() {
Bundle bundle = InstrumentationRegistry.getArguments();
return bundle.getString("camera-id");
}
public static int[] deriveCameraIdsUnderTest() throws Exception {
String overrideId = getOverrideCameraId();
int numberOfCameras = Camera.getNumberOfCameras();
int[] cameraIds;
if (overrideId == null) {
cameraIds = IntStream.range(0, numberOfCameras).toArray();
} else {
int overrideCameraId = Integer.parseInt(overrideId);
if (overrideCameraId >= 0 && overrideCameraId < numberOfCameras) {
cameraIds = new int[]{overrideCameraId};
} else {
cameraIds = new int[]{};
}
}
return cameraIds;
}
/**
* Wait until the SurfaceTexture available from the TextureView, then return it.
* Return null if the wait times out.
*
* @param timeOutMs The timeout value for the wait
* @return The available SurfaceTexture, return null if the wait times out.
*/
public static SurfaceTexture getAvailableSurfaceTexture(long timeOutMs, TextureView view) {
long waitTime = timeOutMs;
while (!view.isAvailable() && waitTime > 0) {
long startTimeMs = SystemClock.elapsedRealtime();
SystemClock.sleep(SHORT_SLEEP_WAIT_TIME_MS);
waitTime -= (SystemClock.elapsedRealtime() - startTimeMs);
}
if (view.isAvailable()) {
return view.getSurfaceTexture();
} else {
Log.w(TAG, "Wait for SurfaceTexture available timed out after " + timeOutMs + "ms");
return null;
}
}
}