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 
18 package com.android.camera.one.v2;
19 
20 import android.annotation.TargetApi;
21 import android.hardware.camera2.CameraAccessException;
22 import android.hardware.camera2.CameraCharacteristics;
23 import android.hardware.camera2.CameraManager;
24 import android.os.Build.VERSION_CODES;
25 
26 import com.android.camera.debug.Log;
27 import com.android.camera.debug.Log.Tag;
28 import com.android.camera.device.CameraId;
29 import com.android.camera.one.OneCamera.Facing;
30 import com.android.camera.one.OneCameraAccessException;
31 import com.android.camera.one.OneCameraCharacteristics;
32 import com.android.camera.one.OneCameraManager;
33 import com.android.camera.util.AndroidServices;
34 import com.android.camera.util.ApiHelper;
35 import com.google.common.base.Optional;
36 
37 import java.util.Hashtable;
38 
39 import javax.annotation.Nonnull;
40 
41 /**
42  * Pick camera ids from a list of devices based on defined characteristics.
43  */
44 @TargetApi(VERSION_CODES.LOLLIPOP)
45 public class Camera2OneCameraManagerImpl implements OneCameraManager {
46     private static final Tag TAG = new Tag("Camera2OneCamMgr");
47     /**
48      * Create a new camera2 api hardware manager.
49      */
create()50     public static Optional<Camera2OneCameraManagerImpl> create() {
51         if (!ApiHelper.HAS_CAMERA_2_API) {
52             return Optional.absent();
53         }
54         CameraManager cameraManager;
55         try {
56             cameraManager = AndroidServices.instance().provideCameraManager();
57         } catch (IllegalStateException ex) {
58             Log.e(TAG, "camera2.CameraManager is not available.");
59             return Optional.absent();
60         }
61         Camera2OneCameraManagerImpl hardwareManager =
62               new Camera2OneCameraManagerImpl(cameraManager);
63         return Optional.of(hardwareManager);
64     }
65 
66     private final CameraManager mCameraManager;
67     private Hashtable<Facing, String> mCameraFacingCache = new Hashtable<Facing, String>();
68 
Camera2OneCameraManagerImpl(CameraManager cameraManger)69     public Camera2OneCameraManagerImpl(CameraManager cameraManger) {
70         mCameraManager = cameraManger;
71 
72         //Camera facing queries depending on camera implementation can be
73         //expensive and involve additional IPC with side effects. Cache front&
74         //back camera ids as early as possible.
75         if (mCameraManager != null) {
76             mCameraFacingCache.clear();
77             findFirstCameraFacing(Facing.BACK);
78             findFirstCameraFacing(Facing.FRONT);
79         }
80     }
81 
82     @Override
hasCamera()83     public boolean hasCamera() {
84         try {
85             String[] ids = mCameraManager.getCameraIdList();
86             return ids != null && ids.length > 0;
87         } catch (CameraAccessException ex) {
88             Log.e(TAG, "Unable to read camera list.", ex);
89             return false;
90         }
91     }
92 
93     @Override
hasCameraFacing(@onnull Facing direction)94     public boolean hasCameraFacing(@Nonnull Facing direction) {
95         return findCameraId(direction) != null;
96     }
97 
98     @Override
findFirstCamera()99     public CameraId findFirstCamera() {
100         try {
101             String[] ids = mCameraManager.getCameraIdList();
102             if(ids != null && ids.length > 0) {
103                 return CameraId.from(ids[0]);
104             }
105         } catch (CameraAccessException ex) {
106             Log.e(TAG, "Unable to read camera list.", ex);
107         }
108 
109         return null;
110     }
111 
112     @Override
findFirstCameraFacing(@onnull Facing facing)113     public CameraId findFirstCameraFacing(@Nonnull Facing facing) {
114         String cameraId = findCameraId(facing);
115         return (cameraId != null) ? CameraId.from(cameraId) : null;
116     }
117 
118     @Override
getOneCameraCharacteristics( @onnull CameraId key)119     public OneCameraCharacteristics getOneCameraCharacteristics(
120           @Nonnull CameraId key)
121           throws OneCameraAccessException {
122         return new OneCameraCharacteristicsImpl(getCameraCharacteristics(key));
123     }
124 
getCameraCharacteristics( @onnull CameraId key)125     public CameraCharacteristics getCameraCharacteristics(
126           @Nonnull CameraId key)
127           throws OneCameraAccessException {
128         try {
129             return mCameraManager.getCameraCharacteristics(key.getValue());
130         } catch (CameraAccessException ex) {
131             throw new OneCameraAccessException("Unable to get camera characteristics", ex);
132         }
133     }
134 
135     /** Returns the ID of the first camera facing the given direction. */
findCameraId(Facing facing)136     private String findCameraId(Facing facing) {
137         String id = mCameraFacingCache.get(facing);
138         if (id != null) {
139             return id;
140         }
141 
142         if (facing == Facing.FRONT) {
143             id = findFirstFrontCameraId();
144         } else {
145             id = findFirstBackCameraId();
146         }
147 
148         if (id != null) {
149             mCameraFacingCache.put(facing, id);
150         }
151         return id;
152     }
153 
154     /** Returns the ID of the first back-facing camera. */
findFirstBackCameraId()155     private String findFirstBackCameraId() {
156         Log.d(TAG, "Getting First BACK Camera");
157         String cameraId = findFirstCameraIdFacing(CameraCharacteristics.LENS_FACING_BACK);
158         if (cameraId == null) {
159             Log.w(TAG, "No back-facing camera found.");
160             cameraId = findFirstCameraIdFacing(CameraCharacteristics.LENS_FACING_EXTERNAL);
161             if (cameraId == null) {
162                 Log.w(TAG, "No external camera found.");
163             }
164         }
165         return cameraId;
166     }
167 
168     /** Returns the ID of the first front-facing camera. */
findFirstFrontCameraId()169     private String findFirstFrontCameraId() {
170         Log.d(TAG, "Getting First FRONT Camera");
171         String cameraId = findFirstCameraIdFacing(CameraCharacteristics.LENS_FACING_FRONT);
172         if (cameraId == null) {
173             Log.w(TAG, "No front-facing camera found.");
174             cameraId = findFirstCameraIdFacing(CameraCharacteristics.LENS_FACING_EXTERNAL);
175             if (cameraId == null) {
176                 Log.w(TAG, "No external camera found.");
177             }
178         }
179         return cameraId;
180     }
181 
182 
183     /** Returns the ID of the first camera facing the given direction. */
findFirstCameraIdFacing(int facing)184     private String findFirstCameraIdFacing(int facing) {
185         try {
186             String[] cameraIds = mCameraManager.getCameraIdList();
187             for (String cameraId : cameraIds) {
188                 CameraCharacteristics characteristics = mCameraManager
189                       .getCameraCharacteristics(cameraId);
190                 if (characteristics.get(CameraCharacteristics.LENS_FACING) == facing) {
191                     return cameraId;
192                 }
193             }
194         } catch (CameraAccessException ex) {
195             Log.w(TAG, "Unable to get camera ID", ex);
196         }
197         return null;
198     }
199 
200 }
201