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