1 /*
2  * Copyright (C) 2015 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 com.android.camera.one.config;
18 
19 import android.content.ContentResolver;
20 import android.hardware.camera2.CameraCharacteristics;
21 
22 import com.android.camera.app.MemoryManager;
23 import com.android.camera.debug.Log;
24 import com.android.camera.one.config.OneCameraFeatureConfig.CaptureSupportLevel;
25 import com.android.camera.one.config.OneCameraFeatureConfig.HdrPlusSupportLevel;
26 import com.android.camera.util.ApiHelper;
27 import com.android.camera.util.GcamHelper;
28 import com.android.camera.util.GservicesHelper;
29 import com.google.common.base.Function;
30 import com.google.common.base.Optional;
31 
32 /**
33  * Creates the OneCamera feature configurations for the GoogleCamera app.
34  */
35 public class OneCameraFeatureConfigCreator {
36     private static final Log.Tag TAG = new Log.Tag("OneCamFtrCnfgCrtr");
37 
38     /**
39      * Create the default camera feature config.
40      */
createDefault(ContentResolver contentResolver, MemoryManager memoryManager)41     public static OneCameraFeatureConfig createDefault(ContentResolver contentResolver,
42             MemoryManager memoryManager) {
43         // Enable CaptureModule on all M devices.
44         boolean useCaptureModule = true;
45         Log.i(TAG, "CaptureModule? " + useCaptureModule);
46 
47         // HDR+ has multiple levels of support.
48         HdrPlusSupportLevel hdrPlusSupportLevel =
49                 GcamHelper.determineHdrPlusSupportLevel(contentResolver, useCaptureModule);
50         return new OneCameraFeatureConfig(useCaptureModule,
51                 buildCaptureModuleDetector(contentResolver),
52                 hdrPlusSupportLevel,
53                 memoryManager.getMaxAllowedNativeMemoryAllocation(),
54                 GservicesHelper.getMaxAllowedImageReaderCount(contentResolver));
55     }
56 
buildCaptureModuleDetector( final ContentResolver contentResolver)57     private static Function<CameraCharacteristics, CaptureSupportLevel> buildCaptureModuleDetector(
58             final ContentResolver contentResolver) {
59         return new Function<CameraCharacteristics, CaptureSupportLevel>() {
60             @Override
61             public CaptureSupportLevel apply(CameraCharacteristics characteristics) {
62                 // If a capture support level override exists, use it. Otherwise
63                 // dynamically check the capabilities of the current device.
64                 Optional<CaptureSupportLevel> override =
65                         getCaptureSupportLevelOverride(characteristics, contentResolver);
66                 if (override.isPresent()) {
67                     Log.i(TAG, "Camera support level override: " + override.get().name());
68                     return override.get();
69                 }
70 
71                 Integer supportedLevel = characteristics
72                         .get(CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL);
73 
74                 // A hardware level should always be supported, so we should
75                 // never have to return here. If no hardware level is supported
76                 // on a LEGACY device, the LIMITED_JPEG fallback will not work.
77                 if (supportedLevel == null) {
78                     Log.e(TAG, "Device does not report supported hardware level.");
79                     return CaptureSupportLevel.LIMITED_JPEG;
80                 }
81 
82                 // LEGACY_JPEG is the ONLY mode that is supported on LEGACY
83                 // devices.
84                 if (supportedLevel == CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY) {
85                     return CaptureSupportLevel.LEGACY_JPEG;
86                 }
87 
88                 // No matter if L or L MR1, the N5 does not currently support
89                 // ZSL due to HAL bugs. The latest one causes random preview
90                 // freezes even on MR1, see b/19565931.
91                 if (ApiHelper.IS_NEXUS_5) {
92                     return CaptureSupportLevel.LIMITED_JPEG;
93                 }
94 
95                 if (ApiHelper.IS_NEXUS_6) {
96                     if (ApiHelper.isLMr1OrHigher()) {
97                         // Although front-facing cameras on the N6 (and N5) are not advertised as
98                         // FULL, they can do ZSL. We might want to change the check for ZSL
99                         // according to b/19625916.
100                         return CaptureSupportLevel.ZSL;
101                     } else {
102                         // On a non-LEGACY N6 (or N5) prior to Lollipop MR1 we fall back to
103                         // LIMITED_JPEG due to HAL bugs.
104                         return CaptureSupportLevel.LIMITED_JPEG;
105                     }
106                 }
107 
108                 // On FULL devices starting with L-MR1 we can run ZSL if private reprocessing
109                 // or YUV reprocessing is supported.
110                 if (supportedLevel == CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_FULL ||
111                         supportedLevel == CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_3) {
112                     if (supportsReprocessing(characteristics)) {
113                         return CaptureSupportLevel.ZSL;
114                     } else {
115                         return CaptureSupportLevel.LIMITED_YUV;
116                     }
117                 }
118 
119                 // On LIMITED devices starting with L-MR1 we run a simple YUV
120                 // capture mode.
121                 if (supportedLevel == CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED) {
122                     return CaptureSupportLevel.LIMITED_YUV;
123                 }
124 
125                 // We should never get here. If we do, let's fall back to a mode
126                 // that should work on all non-LEGACY devices.
127                 Log.e(TAG, "Unknown support level: " + supportedLevel);
128                 return CaptureSupportLevel.LIMITED_JPEG;
129             }
130         };
131     }
132 
133     private static boolean supportsReprocessing(CameraCharacteristics characteristics) {
134         Integer maxNumInputStreams = characteristics.get(
135                 CameraCharacteristics.REQUEST_MAX_NUM_INPUT_STREAMS);
136         if (maxNumInputStreams == null) {
137             Log.e(TAG, "Camera does not have maximum number of input streams.");
138             return false;
139         }
140         if (maxNumInputStreams == 0) {
141             return false;
142         }
143 
144         int[] capabilities = characteristics.get(
145                 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES);
146         for (int cap : capabilities) {
147             if (cap == CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_PRIVATE_REPROCESSING ||
148                     cap == CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_YUV_REPROCESSING) {
149                 return true;
150             }
151         }
152         return false;
153     }
154 
155     /**
156      * @return If an override exits, this returns the capture support hardware
157      *         level that should be used on this device.
158      */
159     private static Optional<CaptureSupportLevel> getCaptureSupportLevelOverride(
160             CameraCharacteristics cameraCharacteristics, ContentResolver contentResolver) {
161         Integer facing = cameraCharacteristics.get(CameraCharacteristics.LENS_FACING);
162         if (facing == null) {
163             Log.e(TAG, "Camera not facing anywhere.");
164             return Optional.absent();
165         }
166 
167         switch (facing) {
168             case CameraCharacteristics.LENS_FACING_BACK: {
169                 int override = GservicesHelper.getCaptureSupportLevelOverrideBack(contentResolver);
170                 return CaptureSupportLevel.fromFlag(override);
171             }
172             case CameraCharacteristics.LENS_FACING_FRONT: {
173                 int override = GservicesHelper.getCaptureSupportLevelOverrideFront(contentResolver);
174                 return CaptureSupportLevel.fromFlag(override);
175             }
176             default:
177                 Log.e(TAG, "Not sure where camera is facing to.");
178                 return Optional.absent();
179         }
180     }
181 }
182