/*
|
* Copyright (C) 2015 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 com.android.camera.one.config;
|
|
import android.content.ContentResolver;
|
import android.hardware.camera2.CameraCharacteristics;
|
|
import com.android.camera.app.MemoryManager;
|
import com.android.camera.debug.Log;
|
import com.android.camera.one.config.OneCameraFeatureConfig.CaptureSupportLevel;
|
import com.android.camera.one.config.OneCameraFeatureConfig.HdrPlusSupportLevel;
|
import com.android.camera.util.ApiHelper;
|
import com.android.camera.util.GcamHelper;
|
import com.android.camera.util.GservicesHelper;
|
import com.google.common.base.Function;
|
import com.google.common.base.Optional;
|
|
/**
|
* Creates the OneCamera feature configurations for the GoogleCamera app.
|
*/
|
public class OneCameraFeatureConfigCreator {
|
private static final Log.Tag TAG = new Log.Tag("OneCamFtrCnfgCrtr");
|
|
/**
|
* Create the default camera feature config.
|
*/
|
public static OneCameraFeatureConfig createDefault(ContentResolver contentResolver,
|
MemoryManager memoryManager) {
|
// Enable CaptureModule on all M devices.
|
boolean useCaptureModule = true;
|
Log.i(TAG, "CaptureModule? " + useCaptureModule);
|
|
// HDR+ has multiple levels of support.
|
HdrPlusSupportLevel hdrPlusSupportLevel =
|
GcamHelper.determineHdrPlusSupportLevel(contentResolver, useCaptureModule);
|
return new OneCameraFeatureConfig(useCaptureModule,
|
buildCaptureModuleDetector(contentResolver),
|
hdrPlusSupportLevel,
|
memoryManager.getMaxAllowedNativeMemoryAllocation(),
|
GservicesHelper.getMaxAllowedImageReaderCount(contentResolver));
|
}
|
|
private static Function<CameraCharacteristics, CaptureSupportLevel> buildCaptureModuleDetector(
|
final ContentResolver contentResolver) {
|
return new Function<CameraCharacteristics, CaptureSupportLevel>() {
|
@Override
|
public CaptureSupportLevel apply(CameraCharacteristics characteristics) {
|
// If a capture support level override exists, use it. Otherwise
|
// dynamically check the capabilities of the current device.
|
Optional<CaptureSupportLevel> override =
|
getCaptureSupportLevelOverride(characteristics, contentResolver);
|
if (override.isPresent()) {
|
Log.i(TAG, "Camera support level override: " + override.get().name());
|
return override.get();
|
}
|
|
Integer supportedLevel = characteristics
|
.get(CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL);
|
|
// A hardware level should always be supported, so we should
|
// never have to return here. If no hardware level is supported
|
// on a LEGACY device, the LIMITED_JPEG fallback will not work.
|
if (supportedLevel == null) {
|
Log.e(TAG, "Device does not report supported hardware level.");
|
return CaptureSupportLevel.LIMITED_JPEG;
|
}
|
|
// LEGACY_JPEG is the ONLY mode that is supported on LEGACY
|
// devices.
|
if (supportedLevel == CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY) {
|
return CaptureSupportLevel.LEGACY_JPEG;
|
}
|
|
// No matter if L or L MR1, the N5 does not currently support
|
// ZSL due to HAL bugs. The latest one causes random preview
|
// freezes even on MR1, see b/19565931.
|
if (ApiHelper.IS_NEXUS_5) {
|
return CaptureSupportLevel.LIMITED_JPEG;
|
}
|
|
if (ApiHelper.IS_NEXUS_6) {
|
if (ApiHelper.isLMr1OrHigher()) {
|
// Although front-facing cameras on the N6 (and N5) are not advertised as
|
// FULL, they can do ZSL. We might want to change the check for ZSL
|
// according to b/19625916.
|
return CaptureSupportLevel.ZSL;
|
} else {
|
// On a non-LEGACY N6 (or N5) prior to Lollipop MR1 we fall back to
|
// LIMITED_JPEG due to HAL bugs.
|
return CaptureSupportLevel.LIMITED_JPEG;
|
}
|
}
|
|
// On FULL devices starting with L-MR1 we can run ZSL if private reprocessing
|
// or YUV reprocessing is supported.
|
if (supportedLevel == CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_FULL ||
|
supportedLevel == CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_3) {
|
if (supportsReprocessing(characteristics)) {
|
return CaptureSupportLevel.ZSL;
|
} else {
|
return CaptureSupportLevel.LIMITED_YUV;
|
}
|
}
|
|
// On LIMITED devices starting with L-MR1 we run a simple YUV
|
// capture mode.
|
if (supportedLevel == CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED) {
|
return CaptureSupportLevel.LIMITED_JPEG;
|
}
|
|
// We should never get here. If we do, let's fall back to a mode
|
// that should work on all non-LEGACY devices.
|
Log.e(TAG, "Unknown support level: " + supportedLevel);
|
return CaptureSupportLevel.LIMITED_JPEG;
|
}
|
};
|
}
|
|
private static boolean supportsReprocessing(CameraCharacteristics characteristics) {
|
Integer maxNumInputStreams = characteristics.get(
|
CameraCharacteristics.REQUEST_MAX_NUM_INPUT_STREAMS);
|
if (maxNumInputStreams == null) {
|
Log.e(TAG, "Camera does not have maximum number of input streams.");
|
return false;
|
}
|
if (maxNumInputStreams == 0) {
|
return false;
|
}
|
|
int[] capabilities = characteristics.get(
|
CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES);
|
for (int cap : capabilities) {
|
if (cap == CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_PRIVATE_REPROCESSING ||
|
cap == CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_YUV_REPROCESSING) {
|
return true;
|
}
|
}
|
return false;
|
}
|
|
/**
|
* @return If an override exits, this returns the capture support hardware
|
* level that should be used on this device.
|
*/
|
private static Optional<CaptureSupportLevel> getCaptureSupportLevelOverride(
|
CameraCharacteristics cameraCharacteristics, ContentResolver contentResolver) {
|
Integer facing = cameraCharacteristics.get(CameraCharacteristics.LENS_FACING);
|
if (facing == null) {
|
Log.e(TAG, "Camera not facing anywhere.");
|
return Optional.absent();
|
}
|
|
switch (facing) {
|
case CameraCharacteristics.LENS_FACING_BACK: {
|
int override = GservicesHelper.getCaptureSupportLevelOverrideBack(contentResolver);
|
return CaptureSupportLevel.fromFlag(override);
|
}
|
case CameraCharacteristics.LENS_FACING_FRONT: {
|
int override = GservicesHelper.getCaptureSupportLevelOverrideFront(contentResolver);
|
return CaptureSupportLevel.fromFlag(override);
|
}
|
case CameraCharacteristics.LENS_FACING_EXTERNAL: {
|
int override = GservicesHelper.getCaptureSupportLevelOverrideFront(contentResolver);
|
return CaptureSupportLevel.fromFlag(override);
|
}
|
default:
|
Log.e(TAG, "Not sure where camera is facing to.");
|
return Optional.absent();
|
}
|
}
|
}
|