/* * 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 buildCaptureModuleDetector( final ContentResolver contentResolver) { return new Function() { @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 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_YUV; } // 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 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); } default: Log.e(TAG, "Not sure where camera is facing to."); return Optional.absent(); } } }