1 /*
2  * Copyright (C) 2014 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.v2;
18 
19 import static com.google.common.base.Preconditions.checkNotNull;
20 
21 import android.annotation.TargetApi;
22 import android.graphics.Rect;
23 import android.graphics.SurfaceTexture;
24 import android.hardware.camera2.CameraCharacteristics;
25 import android.hardware.camera2.CameraMetadata;
26 import android.hardware.camera2.params.StreamConfigurationMap;
27 import android.os.Build;
28 import android.util.Range;
29 import android.util.Rational;
30 
31 import com.android.camera.debug.Log;
32 import com.android.camera.one.OneCamera;
33 import com.android.camera.one.OneCameraCharacteristics;
34 import com.android.camera.ui.focus.LensRangeCalculator;
35 import com.android.camera.ui.motion.LinearScale;
36 import com.android.camera.util.ApiHelper;
37 import com.android.camera.util.Size;
38 import com.google.common.primitives.Floats;
39 
40 import java.util.ArrayList;
41 import java.util.List;
42 
43 /**
44  * Describes a OneCamera device which is on top of camera2 API. This is
45  * essential a wrapper for #{link
46  * android.hardware.camera2.CameraCharacteristics}.
47  */
48 @TargetApi(Build.VERSION_CODES.LOLLIPOP)
49 public class OneCameraCharacteristicsImpl implements OneCameraCharacteristics {
50     private static final int CONTROL_SCENE_MODE_HDR = 0x12;
51     private static final Log.Tag TAG = new Log.Tag("OneCamCharImpl");
52 
53     private final CameraCharacteristics mCameraCharacteristics;
54 
OneCameraCharacteristicsImpl(CameraCharacteristics cameraCharacteristics)55     public OneCameraCharacteristicsImpl(CameraCharacteristics cameraCharacteristics) {
56         mCameraCharacteristics = cameraCharacteristics;
57     }
58 
59     @Override
getSupportedPictureSizes(int imageFormat)60     public List<Size> getSupportedPictureSizes(int imageFormat) {
61         StreamConfigurationMap configMap;
62         try {
63             configMap = mCameraCharacteristics.get(
64                     CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
65         } catch (Exception ex) {
66             Log.e(TAG, "Unable to obtain picture sizes.", ex);
67             // See b/19623115   where java.lang.AssertionError can be thrown due to HAL error
68             return new ArrayList<>(0);
69         }
70 
71         ArrayList<Size> supportedPictureSizes = new ArrayList<>();
72         for (android.util.Size androidSize : configMap.getOutputSizes(imageFormat)) {
73             supportedPictureSizes.add(new Size(androidSize));
74         }
75         return supportedPictureSizes;
76     }
77 
78     @Override
getSupportedPreviewSizes()79     public List<Size> getSupportedPreviewSizes() {
80         StreamConfigurationMap configMap;
81         try {
82             configMap = mCameraCharacteristics.get(
83                     CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
84         } catch (Exception ex) {
85             Log.e(TAG, "Unable to obtain preview sizes.", ex);
86             // See b/19623115   where java.lang.AssertionError can be thrown due to HAL error
87             return new ArrayList<>(0);
88         }
89         ArrayList<Size> supportedPictureSizes = new ArrayList<>();
90         for (android.util.Size androidSize : configMap.getOutputSizes(SurfaceTexture.class)) {
91             supportedPictureSizes.add(new Size(androidSize));
92         }
93         return supportedPictureSizes;
94     }
95 
96     @Override
getSensorOrientation()97     public int getSensorOrientation() {
98         return mCameraCharacteristics.get(CameraCharacteristics.SENSOR_ORIENTATION);
99     }
100 
101     @Override
getCameraDirection()102     public OneCamera.Facing getCameraDirection() {
103         int direction = mCameraCharacteristics.get(CameraCharacteristics.LENS_FACING);
104         if (direction == CameraCharacteristics.LENS_FACING_BACK) {
105             return OneCamera.Facing.BACK;
106         } else {
107             return OneCamera.Facing.FRONT;
108         }
109     }
110 
111     @Override
getSensorInfoActiveArraySize()112     public Rect getSensorInfoActiveArraySize() {
113         return mCameraCharacteristics.get(CameraCharacteristics.SENSOR_INFO_ACTIVE_ARRAY_SIZE);
114     }
115 
116     @Override
getAvailableMaxDigitalZoom()117     public float getAvailableMaxDigitalZoom() {
118         return mCameraCharacteristics.get(CameraCharacteristics.SCALER_AVAILABLE_MAX_DIGITAL_ZOOM);
119     }
120 
121     @Override
isFlashSupported()122     public boolean isFlashSupported() {
123         return mCameraCharacteristics.get(CameraCharacteristics.FLASH_INFO_AVAILABLE);
124     }
125 
126     @Override
isHdrSceneSupported()127     public boolean isHdrSceneSupported() {
128         // API 21 omitted this constant officially, but kept it around as a hidden constant
129         // MR1 brings it back officially as the same int value.
130         int[] availableSceneModes = mCameraCharacteristics.get(
131               CameraCharacteristics.CONTROL_AVAILABLE_SCENE_MODES);
132         for (int availableSceneMode : availableSceneModes) {
133             if (availableSceneMode == CONTROL_SCENE_MODE_HDR) {
134                 return true;
135             }
136         }
137         return false;
138     }
139 
140     @Override
getSupportedHardwareLevel()141     public SupportedHardwareLevel getSupportedHardwareLevel() {
142         Integer supportedHardwareLevel = mCameraCharacteristics
143                 .get(CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL);
144         // If this fails, it is a framework bug, per API documentation.
145         checkNotNull(supportedHardwareLevel, "INFO_SUPPORTED_HARDWARE_LEVEL not found");
146         switch (supportedHardwareLevel) {
147             case CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_FULL:
148                 return SupportedHardwareLevel.FULL;
149             case CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED:
150                 return SupportedHardwareLevel.LIMITED;
151             case CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY:
152                 return SupportedHardwareLevel.LEGACY;
153             default:
154                 if (supportedHardwareLevel >
155                         CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_FULL) {
156                     Log.i(TAG, "Unknown higher hardware level mapped to FULL: "
157                             + supportedHardwareLevel);
158                     return SupportedHardwareLevel.FULL;
159                 }
160                 throw new IllegalStateException("Invalid value for INFO_SUPPORTED_HARDWARE_LEVEL");
161         }
162     }
163 
164     @Override
getSupportedFaceDetectModes()165     public List<FaceDetectMode> getSupportedFaceDetectModes() {
166         int[] modes = mCameraCharacteristics.get(
167               CameraCharacteristics.STATISTICS_INFO_AVAILABLE_FACE_DETECT_MODES);
168 
169         List<FaceDetectMode> oneModes = new ArrayList<>(modes.length);
170 
171         for(int i=0; i < modes.length; i++) {
172             if (modes[i] == CameraMetadata.STATISTICS_FACE_DETECT_MODE_FULL) {
173                 oneModes.add(FaceDetectMode.FULL);
174             }
175             if (modes[i] == CameraMetadata.STATISTICS_FACE_DETECT_MODE_SIMPLE) {
176                 oneModes.add(FaceDetectMode.SIMPLE);
177             }
178             if (modes[i] == CameraMetadata.STATISTICS_FACE_DETECT_MODE_OFF) {
179                 oneModes.add(FaceDetectMode.NONE);
180             }
181         }
182 
183         return oneModes;
184     }
185 
186     @Override
getLensFocusRange()187     public LinearScale getLensFocusRange() {
188         return LensRangeCalculator.getDiopterToRatioCalculator(mCameraCharacteristics);
189     }
190 
191     @Override
getAvailableFocalLengths()192     public List<Float> getAvailableFocalLengths() {
193         return Floats.asList(mCameraCharacteristics.get(CameraCharacteristics.LENS_INFO_AVAILABLE_FOCAL_LENGTHS));
194     }
195 
196     @Override
isExposureCompensationSupported()197     public boolean isExposureCompensationSupported() {
198         // Turn off exposure compensation for Nexus 6 on L (API level 21)
199         // because the bug in framework b/19219128.
200         if (ApiHelper.IS_NEXUS_6 && ApiHelper.isLollipop()) {
201             return false;
202         }
203         Range<Integer> compensationRange =
204                 mCameraCharacteristics.get(CameraCharacteristics.CONTROL_AE_COMPENSATION_RANGE);
205         return compensationRange.getLower() != 0 || compensationRange.getUpper() != 0;
206     }
207 
208     @Override
getMinExposureCompensation()209     public int getMinExposureCompensation() {
210         if (!isExposureCompensationSupported()) {
211             return -1;
212         }
213         Range<Integer> compensationRange =
214                 mCameraCharacteristics.get(CameraCharacteristics.CONTROL_AE_COMPENSATION_RANGE);
215         return compensationRange.getLower();
216     }
217 
218     @Override
getMaxExposureCompensation()219     public int getMaxExposureCompensation() {
220         if (!isExposureCompensationSupported()) {
221             return -1;
222         }
223         Range<Integer> compensationRange =
224                 mCameraCharacteristics.get(CameraCharacteristics.CONTROL_AE_COMPENSATION_RANGE);
225         return compensationRange.getUpper();
226     }
227 
228     @Override
getExposureCompensationStep()229     public float getExposureCompensationStep() {
230         if (!isExposureCompensationSupported()) {
231             return -1.0f;
232         }
233         Rational compensationStep = mCameraCharacteristics.get(
234                 CameraCharacteristics.CONTROL_AE_COMPENSATION_STEP);
235         return (float) compensationStep.getNumerator() / compensationStep.getDenominator();
236     }
237 
238     @Override
isAutoFocusSupported()239     public boolean isAutoFocusSupported() {
240         Integer maxAfRegions = mCameraCharacteristics.get(
241               CameraCharacteristics.CONTROL_MAX_REGIONS_AF);
242         // Auto-Focus is supported if the device supports one or more AF regions
243         return maxAfRegions != null && maxAfRegions > 0;
244     }
245 
246     @Override
isAutoExposureSupported()247     public boolean isAutoExposureSupported() {
248         Integer maxAeRegions = mCameraCharacteristics.get(
249               CameraCharacteristics.CONTROL_MAX_REGIONS_AE);
250         // Auto-Exposure is supported if the device supports one or more AE regions
251         return maxAeRegions != null && maxAeRegions > 0;
252     }
253 }
254