CameraManager.java revision 7fcb357811d4dc1f44624e30ad924e9e580d4cbf
127735a4ba50d42df64eb82acc3f64fa2d68fd505John Spurlock/* 227735a4ba50d42df64eb82acc3f64fa2d68fd505John Spurlock * Copyright (C) 2013 The Android Open Source Project 327735a4ba50d42df64eb82acc3f64fa2d68fd505John Spurlock * 427735a4ba50d42df64eb82acc3f64fa2d68fd505John Spurlock * Licensed under the Apache License, Version 2.0 (the "License"); 527735a4ba50d42df64eb82acc3f64fa2d68fd505John Spurlock * you may not use this file except in compliance with the License. 627735a4ba50d42df64eb82acc3f64fa2d68fd505John Spurlock * You may obtain a copy of the License at 727735a4ba50d42df64eb82acc3f64fa2d68fd505John Spurlock * 827735a4ba50d42df64eb82acc3f64fa2d68fd505John Spurlock * http://www.apache.org/licenses/LICENSE-2.0 927735a4ba50d42df64eb82acc3f64fa2d68fd505John Spurlock * 1027735a4ba50d42df64eb82acc3f64fa2d68fd505John Spurlock * Unless required by applicable law or agreed to in writing, software 1127735a4ba50d42df64eb82acc3f64fa2d68fd505John Spurlock * distributed under the License is distributed on an "AS IS" BASIS, 1227735a4ba50d42df64eb82acc3f64fa2d68fd505John Spurlock * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1327735a4ba50d42df64eb82acc3f64fa2d68fd505John Spurlock * See the License for the specific language governing permissions and 1427735a4ba50d42df64eb82acc3f64fa2d68fd505John Spurlock * limitations under the License. 1527735a4ba50d42df64eb82acc3f64fa2d68fd505John Spurlock */ 1627735a4ba50d42df64eb82acc3f64fa2d68fd505John Spurlock 1727735a4ba50d42df64eb82acc3f64fa2d68fd505John Spurlockpackage android.hardware.camera2; 1827735a4ba50d42df64eb82acc3f64fa2d68fd505John Spurlock 1927735a4ba50d42df64eb82acc3f64fa2d68fd505John Spurlockimport android.content.Context; 2027735a4ba50d42df64eb82acc3f64fa2d68fd505John Spurlockimport android.hardware.ICameraService; 2127735a4ba50d42df64eb82acc3f64fa2d68fd505John Spurlockimport android.hardware.ICameraServiceListener; 2227735a4ba50d42df64eb82acc3f64fa2d68fd505John Spurlockimport android.hardware.camera2.impl.CameraMetadataNative; 23b77edbfdab54531023c8bbea7d89b6cefc42096cJohn Spurlockimport android.hardware.camera2.legacy.CameraDeviceUserShim; 2427735a4ba50d42df64eb82acc3f64fa2d68fd505John Spurlockimport android.hardware.camera2.utils.CameraBinderDecorator; 2527735a4ba50d42df64eb82acc3f64fa2d68fd505John Spurlockimport android.hardware.camera2.utils.CameraRuntimeException; 26bd95740648372449a4d5c164d7050eee352d4c24John Spurlockimport android.hardware.camera2.utils.BinderHolder; 2727735a4ba50d42df64eb82acc3f64fa2d68fd505John Spurlockimport android.os.IBinder; 2827735a4ba50d42df64eb82acc3f64fa2d68fd505John Spurlockimport android.os.Handler; 2927735a4ba50d42df64eb82acc3f64fa2d68fd505John Spurlockimport android.os.Looper; 3027735a4ba50d42df64eb82acc3f64fa2d68fd505John Spurlockimport android.os.RemoteException; 3127735a4ba50d42df64eb82acc3f64fa2d68fd505John Spurlockimport android.os.ServiceManager; 3227735a4ba50d42df64eb82acc3f64fa2d68fd505John Spurlockimport android.util.Log; 3327735a4ba50d42df64eb82acc3f64fa2d68fd505John Spurlockimport android.util.ArrayMap; 3427735a4ba50d42df64eb82acc3f64fa2d68fd505John Spurlock 3527735a4ba50d42df64eb82acc3f64fa2d68fd505John Spurlockimport java.util.ArrayList; 3627735a4ba50d42df64eb82acc3f64fa2d68fd505John Spurlock 377edfbca5d00cbc376fda790b50a3fedb9c6070abJohn Spurlock/** 3827735a4ba50d42df64eb82acc3f64fa2d68fd505John Spurlock * <p>An interface for iterating, listing, and connecting to 3927735a4ba50d42df64eb82acc3f64fa2d68fd505John Spurlock * {@link CameraDevice CameraDevices}.</p> 40f25706fc3e169f07a81017ad38dc4501698a5cb3John Spurlock * 41f25706fc3e169f07a81017ad38dc4501698a5cb3John Spurlock * <p>You can get an instance of this class by calling 42f25706fc3e169f07a81017ad38dc4501698a5cb3John Spurlock * {@link android.content.Context#getSystemService(String) Context.getSystemService()}.</p> 4327735a4ba50d42df64eb82acc3f64fa2d68fd505John Spurlock * 44bd95740648372449a4d5c164d7050eee352d4c24John Spurlock * <pre>CameraManager manager = (CameraManager) getSystemService(Context.CAMERA_SERVICE);</pre> 45b77edbfdab54531023c8bbea7d89b6cefc42096cJohn Spurlock * 4627735a4ba50d42df64eb82acc3f64fa2d68fd505John Spurlock * <p>For more details about communicating with camera devices, read the Camera 4727735a4ba50d42df64eb82acc3f64fa2d68fd505John Spurlock * developer guide or the {@link android.hardware.camera2 camera2} 485b9145bf990a9bbf4fdef1739e61ff8c70ec868fJohn Spurlock * package documentation.</p> 49bd95740648372449a4d5c164d7050eee352d4c24John Spurlock */ 5027735a4ba50d42df64eb82acc3f64fa2d68fd505John Spurlockpublic final class CameraManager { 51bd95740648372449a4d5c164d7050eee352d4c24John Spurlock 5227735a4ba50d42df64eb82acc3f64fa2d68fd505John Spurlock private static final String TAG = "CameraManager"; 5327735a4ba50d42df64eb82acc3f64fa2d68fd505John Spurlock 5427735a4ba50d42df64eb82acc3f64fa2d68fd505John Spurlock /** 5527735a4ba50d42df64eb82acc3f64fa2d68fd505John Spurlock * This should match the ICameraService definition 5627735a4ba50d42df64eb82acc3f64fa2d68fd505John Spurlock */ 57d4e6575c4f664e0d42d9306c9762d96533df429eJohn Spurlock private static final String CAMERA_SERVICE_BINDER_NAME = "media.camera"; 5827735a4ba50d42df64eb82acc3f64fa2d68fd505John Spurlock private static final int USE_CALLING_UID = -1; 5927735a4ba50d42df64eb82acc3f64fa2d68fd505John Spurlock 60bd95740648372449a4d5c164d7050eee352d4c24John Spurlock private final ICameraService mCameraService; 6127735a4ba50d42df64eb82acc3f64fa2d68fd505John Spurlock private ArrayList<String> mDeviceIdList; 62bd95740648372449a4d5c164d7050eee352d4c24John Spurlock 63bd95740648372449a4d5c164d7050eee352d4c24John Spurlock private final ArrayMap<AvailabilityListener, Handler> mListenerMap = 6427735a4ba50d42df64eb82acc3f64fa2d68fd505John Spurlock new ArrayMap<AvailabilityListener, Handler>(); 6527735a4ba50d42df64eb82acc3f64fa2d68fd505John Spurlock 665b9145bf990a9bbf4fdef1739e61ff8c70ec868fJohn Spurlock private final Context mContext; 67bd95740648372449a4d5c164d7050eee352d4c24John Spurlock private final Object mLock = new Object(); 6827735a4ba50d42df64eb82acc3f64fa2d68fd505John Spurlock 69bd95740648372449a4d5c164d7050eee352d4c24John Spurlock /** 7027735a4ba50d42df64eb82acc3f64fa2d68fd505John Spurlock * @hide 7127735a4ba50d42df64eb82acc3f64fa2d68fd505John Spurlock */ 7227735a4ba50d42df64eb82acc3f64fa2d68fd505John Spurlock public CameraManager(Context context) { 7327735a4ba50d42df64eb82acc3f64fa2d68fd505John Spurlock mContext = context; 7427735a4ba50d42df64eb82acc3f64fa2d68fd505John Spurlock 7527735a4ba50d42df64eb82acc3f64fa2d68fd505John Spurlock IBinder cameraServiceBinder = ServiceManager.getService(CAMERA_SERVICE_BINDER_NAME); 7627735a4ba50d42df64eb82acc3f64fa2d68fd505John Spurlock ICameraService cameraServiceRaw = ICameraService.Stub.asInterface(cameraServiceBinder); 7727735a4ba50d42df64eb82acc3f64fa2d68fd505John Spurlock 7827735a4ba50d42df64eb82acc3f64fa2d68fd505John Spurlock /** 79f25706fc3e169f07a81017ad38dc4501698a5cb3John Spurlock * Wrap the camera service in a decorator which automatically translates return codes 8027735a4ba50d42df64eb82acc3f64fa2d68fd505John Spurlock * into exceptions, and RemoteExceptions into other exceptions. 8127735a4ba50d42df64eb82acc3f64fa2d68fd505John Spurlock */ 8227735a4ba50d42df64eb82acc3f64fa2d68fd505John Spurlock mCameraService = CameraBinderDecorator.newInstance(cameraServiceRaw); 8327735a4ba50d42df64eb82acc3f64fa2d68fd505John Spurlock 8427735a4ba50d42df64eb82acc3f64fa2d68fd505John Spurlock try { 8527735a4ba50d42df64eb82acc3f64fa2d68fd505John Spurlock CameraBinderDecorator.throwOnError( 8627735a4ba50d42df64eb82acc3f64fa2d68fd505John Spurlock CameraMetadataNative.nativeSetupGlobalVendorTagDescriptor()); 87f25706fc3e169f07a81017ad38dc4501698a5cb3John Spurlock } catch(CameraRuntimeException e) { 88f25706fc3e169f07a81017ad38dc4501698a5cb3John Spurlock throw new IllegalStateException("Failed to setup camera vendor tags", 89f25706fc3e169f07a81017ad38dc4501698a5cb3John Spurlock e.asChecked()); 90f25706fc3e169f07a81017ad38dc4501698a5cb3John Spurlock } 91bd95740648372449a4d5c164d7050eee352d4c24John Spurlock 92bd95740648372449a4d5c164d7050eee352d4c24John Spurlock try { 93b77edbfdab54531023c8bbea7d89b6cefc42096cJohn Spurlock mCameraService.addListener(new CameraServiceListener()); 94b77edbfdab54531023c8bbea7d89b6cefc42096cJohn Spurlock } catch(CameraRuntimeException e) { 955b9145bf990a9bbf4fdef1739e61ff8c70ec868fJohn Spurlock throw new IllegalStateException("Failed to register a camera service listener", 9627735a4ba50d42df64eb82acc3f64fa2d68fd505John Spurlock e.asChecked()); 975b9145bf990a9bbf4fdef1739e61ff8c70ec868fJohn Spurlock } catch (RemoteException e) { 985b9145bf990a9bbf4fdef1739e61ff8c70ec868fJohn Spurlock // impossible 9927735a4ba50d42df64eb82acc3f64fa2d68fd505John Spurlock } 10027735a4ba50d42df64eb82acc3f64fa2d68fd505John Spurlock } 1015b9145bf990a9bbf4fdef1739e61ff8c70ec868fJohn Spurlock 1025b9145bf990a9bbf4fdef1739e61ff8c70ec868fJohn Spurlock /** 1035b9145bf990a9bbf4fdef1739e61ff8c70ec868fJohn Spurlock * Return the list of currently connected camera devices by 10427735a4ba50d42df64eb82acc3f64fa2d68fd505John Spurlock * identifier. 10527735a4ba50d42df64eb82acc3f64fa2d68fd505John Spurlock * 10627735a4ba50d42df64eb82acc3f64fa2d68fd505John Spurlock * <p>Non-removable cameras use integers starting at 0 for their 107bd95740648372449a4d5c164d7050eee352d4c24John Spurlock * identifiers, while removable cameras have a unique identifier for each 108bd95740648372449a4d5c164d7050eee352d4c24John Spurlock * individual device, even if they are the same model.</p> 109bd95740648372449a4d5c164d7050eee352d4c24John Spurlock * 110bd95740648372449a4d5c164d7050eee352d4c24John Spurlock * @return The list of currently connected camera devices. 111ea56251d92050e9a672d1f66d0d4621e4dd4136eAdrian Roos */ 112ea56251d92050e9a672d1f66d0d4621e4dd4136eAdrian Roos public String[] getCameraIdList() throws CameraAccessException { 113bd95740648372449a4d5c164d7050eee352d4c24John Spurlock synchronized (mLock) { 114bd95740648372449a4d5c164d7050eee352d4c24John Spurlock try { 115bd95740648372449a4d5c164d7050eee352d4c24John Spurlock return getOrCreateDeviceIdListLocked().toArray(new String[0]); 116bd95740648372449a4d5c164d7050eee352d4c24John Spurlock } catch(CameraAccessException e) { 117ea56251d92050e9a672d1f66d0d4621e4dd4136eAdrian Roos // this should almost never happen, except if mediaserver crashes 118ea56251d92050e9a672d1f66d0d4621e4dd4136eAdrian Roos throw new IllegalStateException( 119ea56251d92050e9a672d1f66d0d4621e4dd4136eAdrian Roos "Failed to query camera service for device ID list", e); 120ea56251d92050e9a672d1f66d0d4621e4dd4136eAdrian Roos } 121ea56251d92050e9a672d1f66d0d4621e4dd4136eAdrian Roos } 122bd95740648372449a4d5c164d7050eee352d4c24John Spurlock } 123bd95740648372449a4d5c164d7050eee352d4c24John Spurlock 124cffd1e42d329c99f0fd85243b703fd29573d4fe6Adrian Roos /** 125bd95740648372449a4d5c164d7050eee352d4c24John Spurlock * Register a listener to be notified about camera device availability. 126bd95740648372449a4d5c164d7050eee352d4c24John Spurlock * 127bd95740648372449a4d5c164d7050eee352d4c24John Spurlock * <p>Registering the same listener again will replace the handler with the 128bd95740648372449a4d5c164d7050eee352d4c24John Spurlock * new one provided.</p> 129bd95740648372449a4d5c164d7050eee352d4c24John Spurlock * 13027735a4ba50d42df64eb82acc3f64fa2d68fd505John Spurlock * @param listener The new listener to send camera availability notices to 13127735a4ba50d42df64eb82acc3f64fa2d68fd505John Spurlock * @param handler The handler on which the listener should be invoked, or 13227735a4ba50d42df64eb82acc3f64fa2d68fd505John Spurlock * {@code null} to use the current thread's {@link android.os.Looper looper}. 13327735a4ba50d42df64eb82acc3f64fa2d68fd505John Spurlock */ 13427735a4ba50d42df64eb82acc3f64fa2d68fd505John Spurlock public void addAvailabilityListener(AvailabilityListener listener, Handler handler) { 13527735a4ba50d42df64eb82acc3f64fa2d68fd505John Spurlock if (handler == null) { 1367edfbca5d00cbc376fda790b50a3fedb9c6070abJohn Spurlock Looper looper = Looper.myLooper(); 1377edfbca5d00cbc376fda790b50a3fedb9c6070abJohn Spurlock if (looper == null) { 1387edfbca5d00cbc376fda790b50a3fedb9c6070abJohn Spurlock throw new IllegalArgumentException( 1397edfbca5d00cbc376fda790b50a3fedb9c6070abJohn Spurlock "No handler given, and current thread has no looper!"); 140c23bd80b38bf9c03c1eb51fbde621eb5a6381c14John Spurlock } 141c23bd80b38bf9c03c1eb51fbde621eb5a6381c14John Spurlock handler = new Handler(looper); 1425b9145bf990a9bbf4fdef1739e61ff8c70ec868fJohn Spurlock } 1435b9145bf990a9bbf4fdef1739e61ff8c70ec868fJohn Spurlock 1447edfbca5d00cbc376fda790b50a3fedb9c6070abJohn Spurlock synchronized (mLock) { 1457edfbca5d00cbc376fda790b50a3fedb9c6070abJohn Spurlock mListenerMap.put(listener, handler); 1467edfbca5d00cbc376fda790b50a3fedb9c6070abJohn Spurlock } 1477edfbca5d00cbc376fda790b50a3fedb9c6070abJohn Spurlock } 1487edfbca5d00cbc376fda790b50a3fedb9c6070abJohn Spurlock 1497edfbca5d00cbc376fda790b50a3fedb9c6070abJohn Spurlock /** 150c23bd80b38bf9c03c1eb51fbde621eb5a6381c14John Spurlock * Remove a previously-added listener; the listener will no longer receive 151c23bd80b38bf9c03c1eb51fbde621eb5a6381c14John Spurlock * connection and disconnection callbacks. 1527edfbca5d00cbc376fda790b50a3fedb9c6070abJohn Spurlock * 1537edfbca5d00cbc376fda790b50a3fedb9c6070abJohn Spurlock * <p>Removing a listener that isn't registered has no effect.</p> 1547edfbca5d00cbc376fda790b50a3fedb9c6070abJohn Spurlock * 1557edfbca5d00cbc376fda790b50a3fedb9c6070abJohn Spurlock * @param listener The listener to remove from the notification list 1567edfbca5d00cbc376fda790b50a3fedb9c6070abJohn Spurlock */ 1577edfbca5d00cbc376fda790b50a3fedb9c6070abJohn Spurlock public void removeAvailabilityListener(AvailabilityListener listener) { 1587edfbca5d00cbc376fda790b50a3fedb9c6070abJohn Spurlock synchronized (mLock) { 1597edfbca5d00cbc376fda790b50a3fedb9c6070abJohn Spurlock mListenerMap.remove(listener); 1607edfbca5d00cbc376fda790b50a3fedb9c6070abJohn Spurlock } 1615b9145bf990a9bbf4fdef1739e61ff8c70ec868fJohn Spurlock } 1625b9145bf990a9bbf4fdef1739e61ff8c70ec868fJohn Spurlock 163c23bd80b38bf9c03c1eb51fbde621eb5a6381c14John Spurlock /** 1645b9145bf990a9bbf4fdef1739e61ff8c70ec868fJohn Spurlock * <p>Query the capabilities of a camera device. These capabilities are 1655b9145bf990a9bbf4fdef1739e61ff8c70ec868fJohn Spurlock * immutable for a given camera.</p> 1660ec64c65fb7fbfd89556bc33f5caab4ef0937fd4John Spurlock * 1675b9145bf990a9bbf4fdef1739e61ff8c70ec868fJohn Spurlock * @param cameraId The id of the camera device to query 1685b9145bf990a9bbf4fdef1739e61ff8c70ec868fJohn Spurlock * @return The properties of the given camera 1695b9145bf990a9bbf4fdef1739e61ff8c70ec868fJohn Spurlock * 1705b9145bf990a9bbf4fdef1739e61ff8c70ec868fJohn Spurlock * @throws IllegalArgumentException if the cameraId does not match any 1715b9145bf990a9bbf4fdef1739e61ff8c70ec868fJohn Spurlock * currently connected camera device. 1725b9145bf990a9bbf4fdef1739e61ff8c70ec868fJohn Spurlock * @throws CameraAccessException if the camera is disabled by device policy. 1735b9145bf990a9bbf4fdef1739e61ff8c70ec868fJohn Spurlock * @throws SecurityException if the application does not have permission to 1745b9145bf990a9bbf4fdef1739e61ff8c70ec868fJohn Spurlock * access the camera 1755b9145bf990a9bbf4fdef1739e61ff8c70ec868fJohn Spurlock * 1760ec64c65fb7fbfd89556bc33f5caab4ef0937fd4John Spurlock * @see #getCameraIdList 1775b9145bf990a9bbf4fdef1739e61ff8c70ec868fJohn Spurlock * @see android.app.admin.DevicePolicyManager#setCameraDisabled 1785b9145bf990a9bbf4fdef1739e61ff8c70ec868fJohn Spurlock */ 1795b9145bf990a9bbf4fdef1739e61ff8c70ec868fJohn Spurlock public CameraCharacteristics getCameraCharacteristics(String cameraId) 1805b9145bf990a9bbf4fdef1739e61ff8c70ec868fJohn Spurlock throws CameraAccessException { 1815b9145bf990a9bbf4fdef1739e61ff8c70ec868fJohn Spurlock 182c23bd80b38bf9c03c1eb51fbde621eb5a6381c14John Spurlock synchronized (mLock) { 1835b9145bf990a9bbf4fdef1739e61ff8c70ec868fJohn Spurlock if (!getOrCreateDeviceIdListLocked().contains(cameraId)) { 184c23bd80b38bf9c03c1eb51fbde621eb5a6381c14John Spurlock throw new IllegalArgumentException(String.format("Camera id %s does not match any" + 18527735a4ba50d42df64eb82acc3f64fa2d68fd505John Spurlock " currently connected camera device", cameraId)); 18627735a4ba50d42df64eb82acc3f64fa2d68fd505John Spurlock } 18727735a4ba50d42df64eb82acc3f64fa2d68fd505John Spurlock } 188d4e6575c4f664e0d42d9306c9762d96533df429eJohn Spurlock 1895b9145bf990a9bbf4fdef1739e61ff8c70ec868fJohn Spurlock CameraMetadataNative info = new CameraMetadataNative(); 1907edfbca5d00cbc376fda790b50a3fedb9c6070abJohn Spurlock try { 1915b9145bf990a9bbf4fdef1739e61ff8c70ec868fJohn Spurlock mCameraService.getCameraCharacteristics(Integer.valueOf(cameraId), info); 1925b9145bf990a9bbf4fdef1739e61ff8c70ec868fJohn Spurlock } catch(CameraRuntimeException e) { 1935b9145bf990a9bbf4fdef1739e61ff8c70ec868fJohn Spurlock throw e.asChecked(); 1945b9145bf990a9bbf4fdef1739e61ff8c70ec868fJohn Spurlock } catch(RemoteException e) { 1955b9145bf990a9bbf4fdef1739e61ff8c70ec868fJohn Spurlock // impossible 1965b9145bf990a9bbf4fdef1739e61ff8c70ec868fJohn Spurlock return null; 1975b9145bf990a9bbf4fdef1739e61ff8c70ec868fJohn Spurlock } 1985b9145bf990a9bbf4fdef1739e61ff8c70ec868fJohn Spurlock return new CameraCharacteristics(info); 1995b9145bf990a9bbf4fdef1739e61ff8c70ec868fJohn Spurlock } 20027735a4ba50d42df64eb82acc3f64fa2d68fd505John Spurlock 20127735a4ba50d42df64eb82acc3f64fa2d68fd505John Spurlock /** 20227735a4ba50d42df64eb82acc3f64fa2d68fd505John Spurlock * Helper for openning a connection to a camera with the given ID. 20327735a4ba50d42df64eb82acc3f64fa2d68fd505John Spurlock * 20427735a4ba50d42df64eb82acc3f64fa2d68fd505John Spurlock * @param cameraId The unique identifier of the camera device to open 20527735a4ba50d42df64eb82acc3f64fa2d68fd505John Spurlock * @param listener The listener for the camera. Must not be null. 20627735a4ba50d42df64eb82acc3f64fa2d68fd505John Spurlock * @param handler The handler to call the listener on. Must not be null. 20727735a4ba50d42df64eb82acc3f64fa2d68fd505John Spurlock * 20827735a4ba50d42df64eb82acc3f64fa2d68fd505John Spurlock * @throws CameraAccessException if the camera is disabled by device policy, 209f25706fc3e169f07a81017ad38dc4501698a5cb3John Spurlock * or too many camera devices are already open, or the cameraId does not match 210f25706fc3e169f07a81017ad38dc4501698a5cb3John Spurlock * any currently available camera device. 211f25706fc3e169f07a81017ad38dc4501698a5cb3John Spurlock * 21227735a4ba50d42df64eb82acc3f64fa2d68fd505John Spurlock * @throws SecurityException if the application does not have permission to 21327735a4ba50d42df64eb82acc3f64fa2d68fd505John Spurlock * access the camera 21427735a4ba50d42df64eb82acc3f64fa2d68fd505John Spurlock * @throws IllegalArgumentException if listener or handler is null. 21527735a4ba50d42df64eb82acc3f64fa2d68fd505John Spurlock * @return A handle to the newly-created camera device. 21627735a4ba50d42df64eb82acc3f64fa2d68fd505John Spurlock * 21727735a4ba50d42df64eb82acc3f64fa2d68fd505John Spurlock * @see #getCameraIdList 21827735a4ba50d42df64eb82acc3f64fa2d68fd505John Spurlock * @see android.app.admin.DevicePolicyManager#setCameraDisabled 21927735a4ba50d42df64eb82acc3f64fa2d68fd505John Spurlock */ 22027735a4ba50d42df64eb82acc3f64fa2d68fd505John Spurlock private CameraDevice openCameraDeviceUserAsync(String cameraId, 22127735a4ba50d42df64eb82acc3f64fa2d68fd505John Spurlock CameraDevice.StateListener listener, Handler handler) 22227735a4ba50d42df64eb82acc3f64fa2d68fd505John Spurlock throws CameraAccessException { 223bd95740648372449a4d5c164d7050eee352d4c24John Spurlock CameraCharacteristics characteristics = getCameraCharacteristics(cameraId); 22427735a4ba50d42df64eb82acc3f64fa2d68fd505John Spurlock CameraDevice device = null; 225f25706fc3e169f07a81017ad38dc4501698a5cb3John Spurlock try { 226bd95740648372449a4d5c164d7050eee352d4c24John Spurlock 22727735a4ba50d42df64eb82acc3f64fa2d68fd505John Spurlock synchronized (mLock) { 22827735a4ba50d42df64eb82acc3f64fa2d68fd505John Spurlock 2295b9145bf990a9bbf4fdef1739e61ff8c70ec868fJohn Spurlock ICameraDeviceUser cameraUser = null; 23027735a4ba50d42df64eb82acc3f64fa2d68fd505John Spurlock 231f25706fc3e169f07a81017ad38dc4501698a5cb3John Spurlock android.hardware.camera2.impl.CameraDeviceImpl deviceImpl = 23227735a4ba50d42df64eb82acc3f64fa2d68fd505John Spurlock new android.hardware.camera2.impl.CameraDeviceImpl( 23327735a4ba50d42df64eb82acc3f64fa2d68fd505John Spurlock cameraId, 23427735a4ba50d42df64eb82acc3f64fa2d68fd505John Spurlock listener, 23527735a4ba50d42df64eb82acc3f64fa2d68fd505John Spurlock handler, 23627735a4ba50d42df64eb82acc3f64fa2d68fd505John Spurlock characteristics); 23727735a4ba50d42df64eb82acc3f64fa2d68fd505John Spurlock 23827735a4ba50d42df64eb82acc3f64fa2d68fd505John Spurlock BinderHolder holder = new BinderHolder(); 23927735a4ba50d42df64eb82acc3f64fa2d68fd505John Spurlock 240ea56251d92050e9a672d1f66d0d4621e4dd4136eAdrian Roos ICameraDeviceCallbacks callbacks = deviceImpl.getCallbacks(); 241ea56251d92050e9a672d1f66d0d4621e4dd4136eAdrian Roos int id = Integer.parseInt(cameraId); 242bd95740648372449a4d5c164d7050eee352d4c24John Spurlock try { 243b77edbfdab54531023c8bbea7d89b6cefc42096cJohn Spurlock mCameraService.connectDevice(callbacks, id, mContext.getPackageName(), 24427735a4ba50d42df64eb82acc3f64fa2d68fd505John Spurlock USE_CALLING_UID, holder); 24527735a4ba50d42df64eb82acc3f64fa2d68fd505John Spurlock cameraUser = ICameraDeviceUser.Stub.asInterface(holder.getBinder()); 24627735a4ba50d42df64eb82acc3f64fa2d68fd505John Spurlock } catch (CameraRuntimeException e) { 24727735a4ba50d42df64eb82acc3f64fa2d68fd505John Spurlock if (e.getReason() == CameraAccessException.CAMERA_DEPRECATED_HAL) { 24827735a4ba50d42df64eb82acc3f64fa2d68fd505John Spurlock // Use legacy camera implementation for HAL1 devices 249b77edbfdab54531023c8bbea7d89b6cefc42096cJohn Spurlock Log.i(TAG, "Using legacy camera HAL."); 250bd95740648372449a4d5c164d7050eee352d4c24John Spurlock cameraUser = CameraDeviceUserShim.connectBinderShim(callbacks, id); 251b77edbfdab54531023c8bbea7d89b6cefc42096cJohn Spurlock } else if (e.getReason() == CameraAccessException.CAMERA_IN_USE || 25227735a4ba50d42df64eb82acc3f64fa2d68fd505John Spurlock e.getReason() == CameraAccessException.MAX_CAMERAS_IN_USE || 2530ec64c65fb7fbfd89556bc33f5caab4ef0937fd4John Spurlock e.getReason() == CameraAccessException.CAMERA_DISABLED || 25427735a4ba50d42df64eb82acc3f64fa2d68fd505John Spurlock e.getReason() == CameraAccessException.CAMERA_DISCONNECTED || 25527735a4ba50d42df64eb82acc3f64fa2d68fd505John Spurlock e.getReason() == CameraAccessException.CAMERA_ERROR) { 25627735a4ba50d42df64eb82acc3f64fa2d68fd505John Spurlock // Received one of the known connection errors 25727735a4ba50d42df64eb82acc3f64fa2d68fd505John Spurlock // The remote camera device cannot be connected to, so 25827735a4ba50d42df64eb82acc3f64fa2d68fd505John Spurlock // set the local camera to the startup error state 25927735a4ba50d42df64eb82acc3f64fa2d68fd505John Spurlock deviceImpl.setRemoteFailure(e); 26027735a4ba50d42df64eb82acc3f64fa2d68fd505John Spurlock 26127735a4ba50d42df64eb82acc3f64fa2d68fd505John Spurlock if (e.getReason() == CameraAccessException.CAMERA_DISABLED || 26227735a4ba50d42df64eb82acc3f64fa2d68fd505John Spurlock e.getReason() == CameraAccessException.CAMERA_DISCONNECTED) { 26327735a4ba50d42df64eb82acc3f64fa2d68fd505John Spurlock // Per API docs, these failures call onError and throw 26427735a4ba50d42df64eb82acc3f64fa2d68fd505John Spurlock throw e; 26527735a4ba50d42df64eb82acc3f64fa2d68fd505John Spurlock } 26627735a4ba50d42df64eb82acc3f64fa2d68fd505John Spurlock } else { 26727735a4ba50d42df64eb82acc3f64fa2d68fd505John Spurlock // Unexpected failure - rethrow 26827735a4ba50d42df64eb82acc3f64fa2d68fd505John Spurlock throw e; 26927735a4ba50d42df64eb82acc3f64fa2d68fd505John Spurlock } 270f25706fc3e169f07a81017ad38dc4501698a5cb3John Spurlock } 27127735a4ba50d42df64eb82acc3f64fa2d68fd505John Spurlock 27227735a4ba50d42df64eb82acc3f64fa2d68fd505John Spurlock // TODO: factor out listener to be non-nested, then move setter to constructor 27327735a4ba50d42df64eb82acc3f64fa2d68fd505John Spurlock // For now, calling setRemoteDevice will fire initial 27427735a4ba50d42df64eb82acc3f64fa2d68fd505John Spurlock // onOpened/onUnconfigured callbacks. 27527735a4ba50d42df64eb82acc3f64fa2d68fd505John Spurlock deviceImpl.setRemoteDevice(cameraUser); 27627735a4ba50d42df64eb82acc3f64fa2d68fd505John Spurlock device = deviceImpl; 2770ec64c65fb7fbfd89556bc33f5caab4ef0937fd4John Spurlock } 278d4e6575c4f664e0d42d9306c9762d96533df429eJohn Spurlock 2790ec64c65fb7fbfd89556bc33f5caab4ef0937fd4John Spurlock } catch (NumberFormatException e) { 280d4e6575c4f664e0d42d9306c9762d96533df429eJohn Spurlock throw new IllegalArgumentException("Expected cameraId to be numeric, but it was: " 28127735a4ba50d42df64eb82acc3f64fa2d68fd505John Spurlock + cameraId); 28227735a4ba50d42df64eb82acc3f64fa2d68fd505John Spurlock } catch (CameraRuntimeException e) { 28327735a4ba50d42df64eb82acc3f64fa2d68fd505John Spurlock throw e.asChecked(); 28427735a4ba50d42df64eb82acc3f64fa2d68fd505John Spurlock } catch (RemoteException e) { 285 // impossible 286 } 287 return device; 288 } 289 290 /** 291 * Open a connection to a camera with the given ID. 292 * 293 * <p>Use {@link #getCameraIdList} to get the list of available camera 294 * devices. Note that even if an id is listed, open may fail if the device 295 * is disconnected between the calls to {@link #getCameraIdList} and 296 * {@link #openCamera}.</p> 297 * 298 * <p>Once the camera is successfully opened, {@link CameraDevice.StateListener#onOpened} will 299 * be invoked with the newly opened {@link CameraDevice}. The camera device can then be set up 300 * for operation by calling {@link CameraDevice#createCaptureSession} and 301 * {@link CameraDevice#createCaptureRequest}</p> 302 * 303 * <!-- 304 * <p>Since the camera device will be opened asynchronously, any asynchronous operations done 305 * on the returned CameraDevice instance will be queued up until the device startup has 306 * completed and the listener's {@link CameraDevice.StateListener#onOpened onOpened} method is 307 * called. The pending operations are then processed in order.</p> 308 * --> 309 * <p>If the camera becomes disconnected during initialization 310 * after this function call returns, 311 * {@link CameraDevice.StateListener#onDisconnected} with a 312 * {@link CameraDevice} in the disconnected state (and 313 * {@link CameraDevice.StateListener#onOpened} will be skipped).</p> 314 * 315 * <p>If opening the camera device fails, then the device listener's 316 * {@link CameraDevice.StateListener#onError onError} method will be called, and subsequent 317 * calls on the camera device will throw a {@link CameraAccessException}.</p> 318 * 319 * @param cameraId 320 * The unique identifier of the camera device to open 321 * @param listener 322 * The listener which is invoked once the camera is opened 323 * @param handler 324 * The handler on which the listener should be invoked, or 325 * {@code null} to use the current thread's {@link android.os.Looper looper}. 326 * 327 * @throws CameraAccessException if the camera is disabled by device policy, 328 * or the camera has become or was disconnected. 329 * 330 * @throws IllegalArgumentException if cameraId or the listener was null, 331 * or the cameraId does not match any currently or previously available 332 * camera device. 333 * 334 * @throws SecurityException if the application does not have permission to 335 * access the camera 336 * 337 * @see #getCameraIdList 338 * @see android.app.admin.DevicePolicyManager#setCameraDisabled 339 */ 340 public void openCamera(String cameraId, final CameraDevice.StateListener listener, 341 Handler handler) 342 throws CameraAccessException { 343 344 if (cameraId == null) { 345 throw new IllegalArgumentException("cameraId was null"); 346 } else if (listener == null) { 347 throw new IllegalArgumentException("listener was null"); 348 } else if (handler == null) { 349 if (Looper.myLooper() != null) { 350 handler = new Handler(); 351 } else { 352 throw new IllegalArgumentException( 353 "Looper doesn't exist in the calling thread"); 354 } 355 } 356 357 openCameraDeviceUserAsync(cameraId, listener, handler); 358 } 359 360 /** 361 * Interface for listening to camera devices becoming available or 362 * unavailable. 363 * 364 * <p>Cameras become available when they are no longer in use, or when a new 365 * removable camera is connected. They become unavailable when some 366 * application or service starts using a camera, or when a removable camera 367 * is disconnected.</p> 368 * 369 * @see addAvailabilityListener 370 */ 371 public static abstract class AvailabilityListener { 372 373 /** 374 * A new camera has become available to use. 375 * 376 * <p>The default implementation of this method does nothing.</p> 377 * 378 * @param cameraId The unique identifier of the new camera. 379 */ 380 public void onCameraAvailable(String cameraId) { 381 // default empty implementation 382 } 383 384 /** 385 * A previously-available camera has become unavailable for use. 386 * 387 * <p>If an application had an active CameraDevice instance for the 388 * now-disconnected camera, that application will receive a 389 * {@link CameraDevice.StateListener#onDisconnected disconnection error}.</p> 390 * 391 * <p>The default implementation of this method does nothing.</p> 392 * 393 * @param cameraId The unique identifier of the disconnected camera. 394 */ 395 public void onCameraUnavailable(String cameraId) { 396 // default empty implementation 397 } 398 } 399 400 private ArrayList<String> getOrCreateDeviceIdListLocked() throws CameraAccessException { 401 if (mDeviceIdList == null) { 402 int numCameras = 0; 403 404 try { 405 numCameras = mCameraService.getNumberOfCameras(); 406 } catch(CameraRuntimeException e) { 407 throw e.asChecked(); 408 } catch (RemoteException e) { 409 // impossible 410 return null; 411 } 412 413 mDeviceIdList = new ArrayList<String>(); 414 CameraMetadataNative info = new CameraMetadataNative(); 415 for (int i = 0; i < numCameras; ++i) { 416 // Non-removable cameras use integers starting at 0 for their 417 // identifiers 418 boolean isDeviceSupported = false; 419 try { 420 mCameraService.getCameraCharacteristics(i, info); 421 if (!info.isEmpty()) { 422 isDeviceSupported = true; 423 } else { 424 throw new AssertionError("Expected to get non-empty characteristics"); 425 } 426 } catch(IllegalArgumentException e) { 427 // Got a BAD_VALUE from service, meaning that this 428 // device is not supported. 429 } catch(CameraRuntimeException e) { 430 throw e.asChecked(); 431 } catch(RemoteException e) { 432 // impossible 433 } 434 435 if (isDeviceSupported) { 436 mDeviceIdList.add(String.valueOf(i)); 437 } 438 } 439 440 } 441 return mDeviceIdList; 442 } 443 444 // TODO: this class needs unit tests 445 // TODO: extract class into top level 446 private class CameraServiceListener extends ICameraServiceListener.Stub { 447 448 // Keep up-to-date with ICameraServiceListener.h 449 450 // Device physically unplugged 451 public static final int STATUS_NOT_PRESENT = 0; 452 // Device physically has been plugged in 453 // and the camera can be used exclusively 454 public static final int STATUS_PRESENT = 1; 455 // Device physically has been plugged in 456 // but it will not be connect-able until enumeration is complete 457 public static final int STATUS_ENUMERATING = 2; 458 // Camera is in use by another app and cannot be used exclusively 459 public static final int STATUS_NOT_AVAILABLE = 0x80000000; 460 461 // Camera ID -> Status map 462 private final ArrayMap<String, Integer> mDeviceStatus = new ArrayMap<String, Integer>(); 463 464 private static final String TAG = "CameraServiceListener"; 465 466 @Override 467 public IBinder asBinder() { 468 return this; 469 } 470 471 private boolean isAvailable(int status) { 472 switch (status) { 473 case STATUS_PRESENT: 474 return true; 475 default: 476 return false; 477 } 478 } 479 480 private boolean validStatus(int status) { 481 switch (status) { 482 case STATUS_NOT_PRESENT: 483 case STATUS_PRESENT: 484 case STATUS_ENUMERATING: 485 case STATUS_NOT_AVAILABLE: 486 return true; 487 default: 488 return false; 489 } 490 } 491 492 @Override 493 public void onStatusChanged(int status, int cameraId) throws RemoteException { 494 synchronized(CameraManager.this.mLock) { 495 496 Log.v(TAG, 497 String.format("Camera id %d has status changed to 0x%x", cameraId, status)); 498 499 final String id = String.valueOf(cameraId); 500 501 if (!validStatus(status)) { 502 Log.e(TAG, String.format("Ignoring invalid device %d status 0x%x", cameraId, 503 status)); 504 return; 505 } 506 507 Integer oldStatus = mDeviceStatus.put(id, status); 508 509 if (oldStatus != null && oldStatus == status) { 510 Log.v(TAG, String.format( 511 "Device status changed to 0x%x, which is what it already was", 512 status)); 513 return; 514 } 515 516 // TODO: consider abstracting out this state minimization + transition 517 // into a separate 518 // more easily testable class 519 // i.e. (new State()).addState(STATE_AVAILABLE) 520 // .addState(STATE_NOT_AVAILABLE) 521 // .addTransition(STATUS_PRESENT, STATE_AVAILABLE), 522 // .addTransition(STATUS_NOT_PRESENT, STATE_NOT_AVAILABLE) 523 // .addTransition(STATUS_ENUMERATING, STATE_NOT_AVAILABLE); 524 // .addTransition(STATUS_NOT_AVAILABLE, STATE_NOT_AVAILABLE); 525 526 // Translate all the statuses to either 'available' or 'not available' 527 // available -> available => no new update 528 // not available -> not available => no new update 529 if (oldStatus != null && isAvailable(status) == isAvailable(oldStatus)) { 530 531 Log.v(TAG, 532 String.format( 533 "Device status was previously available (%d), " + 534 " and is now again available (%d)" + 535 "so no new client visible update will be sent", 536 isAvailable(status), isAvailable(status))); 537 return; 538 } 539 540 final int listenerCount = mListenerMap.size(); 541 for (int i = 0; i < listenerCount; i++) { 542 Handler handler = mListenerMap.valueAt(i); 543 final AvailabilityListener listener = mListenerMap.keyAt(i); 544 if (isAvailable(status)) { 545 handler.post( 546 new Runnable() { 547 @Override 548 public void run() { 549 listener.onCameraAvailable(id); 550 } 551 }); 552 } else { 553 handler.post( 554 new Runnable() { 555 @Override 556 public void run() { 557 listener.onCameraUnavailable(id); 558 } 559 }); 560 } 561 } // for 562 } // synchronized 563 } // onStatusChanged 564 } // CameraServiceListener 565} // CameraManager 566