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.testingcamera2;
18 
19 import java.util.HashSet;
20 import java.util.Set;
21 
22 import android.Manifest;
23 import android.app.Activity;
24 import android.content.pm.PackageManager;
25 import android.hardware.camera2.CameraCharacteristics;
26 import android.hardware.camera2.CameraDevice;
27 import android.hardware.camera2.CameraManager;
28 import android.hardware.camera2.CameraAccessException;
29 
30 /**
31  * A central manager of camera devices and current clients for them.
32  *
33  */
34 public class CameraOps2 extends CameraManager.AvailabilityCallback {
35 
36     private final CameraManager mCameraManager;
37     private final Activity mActivity;
38     private final Set<CameraDevice> mOpenCameras = new HashSet<CameraDevice>();
39 
40     // For persisting values for permission requests
41     private static final int PERMISSIONS_REQUEST_CAMERA = 1;
42     private String mDelayedOpenId = null;
43     private CameraDevice.StateCallback mDelayedOpenListener = null;
44 
CameraOps2(Activity activity)45     public CameraOps2(Activity activity) {
46         mActivity = activity;
47         mCameraManager = (CameraManager) activity.getSystemService(Activity.CAMERA_SERVICE);
48         if (mCameraManager == null) {
49             throw new AssertionError("Can't connect to camera manager!");
50         }
51         try {
52             String[] cameraIds = mCameraManager.getCameraIdList();
53             TLog.i("Camera count: %d", cameraIds.length);
54             for (String cameraId : cameraIds) {
55                 TLog.i("  Camera %s", cameraId);
56             }
57         } catch (CameraAccessException e) {
58             TLog.e("Unable to get camera list: %s", e);
59         }
60 
61         mCameraManager.registerAvailabilityCallback(this, /*handler*/null);
62     }
63 
64     /**
65      * Add a listener for new camera addition events, and retrieve the list of
66      * current cameras
67      *
68      * @param listener
69      *            A listener to notify on changes to camera availability
70      * @return the current list of available cameras
71      * @throws CameraAccessException
72      *             if the camera manager cannot be queried
73      */
getCamerasAndListen(CameraManager.AvailabilityCallback listener)74     public String[] getCamerasAndListen(CameraManager.AvailabilityCallback listener)
75             throws CameraAccessException {
76 
77         mCameraManager.registerAvailabilityCallback(listener, /*handler*/null);
78 
79         return mCameraManager.getCameraIdList();
80     }
81 
removeAvailabilityCallback(CameraManager.AvailabilityCallback listener)82     public void removeAvailabilityCallback(CameraManager.AvailabilityCallback listener) {
83         mCameraManager.unregisterAvailabilityCallback(listener);
84     }
85 
86     @Override
onCameraAvailable(String cameraId)87     public void onCameraAvailable(String cameraId) {
88         TLog.i("Camera %s is now available", cameraId);
89     }
90 
91     @Override
onCameraUnavailable(String cameraId)92     public void onCameraUnavailable(String cameraId) {
93         TLog.i("Camera %s is now unavailable", cameraId);
94     }
95 
96     /**
97      * Attempt to open a camera device. Returns false if the open call cannot be
98      * made or the device is already open
99      *
100      * @param cameraId id of the camera to open
101      * @param listener listener to notify of camera device state changes
102      * @return true if open call was sent successfully. The client needs to wait
103      *         for its listener to be called to determine if open will succeed.
104      */
openCamera(String cameraId, CameraDevice.StateCallback listener)105     public boolean openCamera(String cameraId, CameraDevice.StateCallback listener) {
106         for (CameraDevice camera : mOpenCameras) {
107             if (camera.getId() == cameraId) {
108                 TLog.e("Camera %s is already open", cameraId);
109                 return false;
110             }
111         }
112         if (mActivity.checkSelfPermission(Manifest.permission.CAMERA)
113                 != PackageManager.PERMISSION_GRANTED) {
114             TLog.i("Requesting camera permissions");
115 
116             mDelayedOpenId = cameraId;
117             mDelayedOpenListener = listener;
118 
119             mActivity.requestPermissions(new String[] {Manifest.permission.CAMERA},
120                     PERMISSIONS_REQUEST_CAMERA);
121             return false;
122         }
123 
124         return doOpenCamera(cameraId, listener);
125     }
126 
doOpenCamera(String cameraId, CameraDevice.StateCallback listener)127     private boolean doOpenCamera(String cameraId, CameraDevice.StateCallback listener) {
128         try {
129             DeviceStateCallback proxyListener = new DeviceStateCallback(listener);
130             mCameraManager.openCamera(cameraId, proxyListener, null);
131         } catch (CameraAccessException e) {
132             TLog.e("Unable to open camera %s.", e, cameraId);
133             return false;
134         }
135 
136         return true;
137     }
138 
onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults)139     public void onRequestPermissionsResult (int requestCode, String[] permissions,
140             int[] grantResults) {
141         if (requestCode == PERMISSIONS_REQUEST_CAMERA) {
142             if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
143                 TLog.i("Camera permission granted");
144                 if (mDelayedOpenId != null && mDelayedOpenListener != null) {
145                     doOpenCamera(mDelayedOpenId, mDelayedOpenListener);
146                 }
147                 mDelayedOpenId = null;
148                 mDelayedOpenListener = null;
149             } else {
150                 TLog.i("Camera permission denied, not opening camera");
151                 if (mDelayedOpenId != null && mDelayedOpenListener != null) {
152                     mDelayedOpenListener.onError(null,
153                             CameraDevice.StateCallback.ERROR_CAMERA_DISABLED);
154                     mDelayedOpenId = null;
155                     mDelayedOpenListener = null;
156                 }
157             }
158             if (grantResults[1] == PackageManager.PERMISSION_GRANTED) {
159                 TLog.i("Storage permission granted");
160             } else {
161                 TLog.i("Storage permission not granted; saving will not work");
162             }
163         }
164     }
165 
getCameraInfo(String cameraId)166     public CameraCharacteristics getCameraInfo(String cameraId) {
167         try {
168             return mCameraManager.getCameraCharacteristics(cameraId);
169         } catch (CameraAccessException e) {
170             TLog.e("Unable to get camera characteristics for camera %s.", e, cameraId);
171         }
172         return null;
173     }
174 
175     private class DeviceStateCallback extends CameraDevice.StateCallback {
176 
177         private final CameraDevice.StateCallback mClientListener;
178 
DeviceStateCallback(CameraDevice.StateCallback clientListener)179         public DeviceStateCallback(CameraDevice.StateCallback clientListener) {
180             mClientListener = clientListener;
181         }
182 
183         @Override
onClosed(CameraDevice camera)184         public void onClosed(CameraDevice camera) {
185             mOpenCameras.remove(camera);
186             TLog.i("Camera %s now closed", camera.getId());
187             mClientListener.onClosed(camera);
188         }
189 
190         @Override
onDisconnected(CameraDevice camera)191         public void onDisconnected(CameraDevice camera) {
192             TLog.i("Camera %s now disconnected", camera.getId());
193             mClientListener.onDisconnected(camera);
194         }
195 
196         @Override
onError(CameraDevice camera, int error)197         public void onError(CameraDevice camera, int error) {
198             TLog.i("Camera %s encountered error: %d", camera.getId(), error);
199             mClientListener.onError(camera, error);
200         }
201 
202         @Override
onOpened(CameraDevice camera)203         public void onOpened(CameraDevice camera) {
204             mOpenCameras.add(camera);
205             TLog.i("Camera %s now open", camera.getId());
206             mClientListener.onOpened(camera);
207         }
208 
209     }
210 }
211