CameraManager.java revision feb50af361e4305a25758966b6b5df2738c00259
1b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala/* 2b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala * Copyright (C) 2013 The Android Open Source Project 3b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala * 4b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala * Licensed under the Apache License, Version 2.0 (the "License"); 5b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala * you may not use this file except in compliance with the License. 6b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala * You may obtain a copy of the License at 7b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala * 8b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala * http://www.apache.org/licenses/LICENSE-2.0 9b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala * 10b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala * Unless required by applicable law or agreed to in writing, software 11b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala * distributed under the License is distributed on an "AS IS" BASIS, 12b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala * See the License for the specific language governing permissions and 14b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala * limitations under the License. 15b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala */ 16b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala 172f1a2e423e0fbb64467d6fcfa4e82c6384f31210Eino-Ville Talvalapackage android.hardware.camera2; 18b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala 19e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkinimport android.content.Context; 20e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkinimport android.hardware.ICameraService; 21e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkinimport android.hardware.ICameraServiceListener; 2270c2207c34cf0e6b3b383b1b1500ff5385aa51a6Eino-Ville Talvalaimport android.hardware.camera2.impl.CameraMetadataNative; 23feb50af361e4305a25758966b6b5df2738c00259Ruben Brunkimport android.hardware.camera2.legacy.CameraDeviceUserShim; 242f1a2e423e0fbb64467d6fcfa4e82c6384f31210Eino-Ville Talvalaimport android.hardware.camera2.utils.CameraBinderDecorator; 252f1a2e423e0fbb64467d6fcfa4e82c6384f31210Eino-Ville Talvalaimport android.hardware.camera2.utils.CameraRuntimeException; 2666ef64514464a1bb9c7931993cc8db3d7539f39aRuben Brunkimport android.hardware.camera2.utils.BinderHolder; 27e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkinimport android.os.IBinder; 284af73c2153747d0624ccc75dfa001cb91982957fEino-Ville Talvalaimport android.os.Handler; 294af73c2153747d0624ccc75dfa001cb91982957fEino-Ville Talvalaimport android.os.Looper; 30e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkinimport android.os.RemoteException; 31e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkinimport android.os.ServiceManager; 32e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkinimport android.util.Log; 334af73c2153747d0624ccc75dfa001cb91982957fEino-Ville Talvalaimport android.util.ArrayMap; 34e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin 35e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkinimport java.util.ArrayList; 36e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin 37b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala/** 38b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala * <p>An interface for iterating, listing, and connecting to 39b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala * {@link CameraDevice CameraDevices}.</p> 40b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala * 41b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala * <p>You can get an instance of this class by calling 42b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala * {@link android.content.Context#getSystemService(String) Context.getSystemService()}.</p> 43b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala * 44b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala * <pre>CameraManager manager = (CameraManager) getSystemService(Context.CAMERA_SERVICE);</pre> 45b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala * 46b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala * <p>For more details about communicating with camera devices, read the Camera 472f1a2e423e0fbb64467d6fcfa4e82c6384f31210Eino-Ville Talvala * developer guide or the {@link android.hardware.camera2 camera2} 48b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala * package documentation.</p> 49b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala */ 50b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvalapublic final class CameraManager { 51b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala 5285c4388de1fea3d45783f07895c2b113c4cc1ba5Ruben Brunk private static final String TAG = "CameraManager"; 5385c4388de1fea3d45783f07895c2b113c4cc1ba5Ruben Brunk 54b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala /** 55e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin * This should match the ICameraService definition 56e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin */ 57e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin private static final String CAMERA_SERVICE_BINDER_NAME = "media.camera"; 58e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin private static final int USE_CALLING_UID = -1; 59e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin 60e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin private final ICameraService mCameraService; 61e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin private ArrayList<String> mDeviceIdList; 624af73c2153747d0624ccc75dfa001cb91982957fEino-Ville Talvala 635c9eaf6796a4c972710dd5cd23cdfa334fa8ad2eIgor Murashkin private final ArrayMap<AvailabilityListener, Handler> mListenerMap = 644af73c2153747d0624ccc75dfa001cb91982957fEino-Ville Talvala new ArrayMap<AvailabilityListener, Handler>(); 654af73c2153747d0624ccc75dfa001cb91982957fEino-Ville Talvala 66e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin private final Context mContext; 67e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin private final Object mLock = new Object(); 68e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin 69e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin /** 70b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala * @hide 71b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala */ 72e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin public CameraManager(Context context) { 73e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin mContext = context; 74e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin 75e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin IBinder cameraServiceBinder = ServiceManager.getService(CAMERA_SERVICE_BINDER_NAME); 76e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin ICameraService cameraServiceRaw = ICameraService.Stub.asInterface(cameraServiceBinder); 77e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin 78e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin /** 79e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin * Wrap the camera service in a decorator which automatically translates return codes 80e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin * into exceptions, and RemoteExceptions into other exceptions. 81e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin */ 82e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin mCameraService = CameraBinderDecorator.newInstance(cameraServiceRaw); 83e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin 84e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin try { 855614cbe64493308dc5330eac5d5ba17202013dc4Igor Murashkin CameraBinderDecorator.throwOnError( 865614cbe64493308dc5330eac5d5ba17202013dc4Igor Murashkin CameraMetadataNative.nativeSetupGlobalVendorTagDescriptor()); 8785c4388de1fea3d45783f07895c2b113c4cc1ba5Ruben Brunk } catch(CameraRuntimeException e) { 8885c4388de1fea3d45783f07895c2b113c4cc1ba5Ruben Brunk throw new IllegalStateException("Failed to setup camera vendor tags", 8985c4388de1fea3d45783f07895c2b113c4cc1ba5Ruben Brunk e.asChecked()); 9085c4388de1fea3d45783f07895c2b113c4cc1ba5Ruben Brunk } 9185c4388de1fea3d45783f07895c2b113c4cc1ba5Ruben Brunk 9285c4388de1fea3d45783f07895c2b113c4cc1ba5Ruben Brunk try { 93e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin mCameraService.addListener(new CameraServiceListener()); 94e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin } catch(CameraRuntimeException e) { 95e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin throw new IllegalStateException("Failed to register a camera service listener", 96e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin e.asChecked()); 97e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin } catch (RemoteException e) { 98e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin // impossible 99e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin } 100b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala } 101b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala 102b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala /** 1034af73c2153747d0624ccc75dfa001cb91982957fEino-Ville Talvala * Return the list of currently connected camera devices by 1044af73c2153747d0624ccc75dfa001cb91982957fEino-Ville Talvala * identifier. 1054af73c2153747d0624ccc75dfa001cb91982957fEino-Ville Talvala * 1064af73c2153747d0624ccc75dfa001cb91982957fEino-Ville Talvala * <p>Non-removable cameras use integers starting at 0 for their 107b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala * identifiers, while removable cameras have a unique identifier for each 108b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala * individual device, even if they are the same model.</p> 109b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala * 110b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala * @return The list of currently connected camera devices. 111b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala */ 1124af73c2153747d0624ccc75dfa001cb91982957fEino-Ville Talvala public String[] getCameraIdList() throws CameraAccessException { 113e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin synchronized (mLock) { 11470725500dcf3b666b43d50563d64705aab58d2d3Igor Murashkin try { 11570725500dcf3b666b43d50563d64705aab58d2d3Igor Murashkin return getOrCreateDeviceIdListLocked().toArray(new String[0]); 11670725500dcf3b666b43d50563d64705aab58d2d3Igor Murashkin } catch(CameraAccessException e) { 11770725500dcf3b666b43d50563d64705aab58d2d3Igor Murashkin // this should almost never happen, except if mediaserver crashes 11870725500dcf3b666b43d50563d64705aab58d2d3Igor Murashkin throw new IllegalStateException( 11970725500dcf3b666b43d50563d64705aab58d2d3Igor Murashkin "Failed to query camera service for device ID list", e); 12070725500dcf3b666b43d50563d64705aab58d2d3Igor Murashkin } 121e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin } 122b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala } 123b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala 124b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala /** 125b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala * Register a listener to be notified about camera device availability. 126b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala * 1274af73c2153747d0624ccc75dfa001cb91982957fEino-Ville Talvala * <p>Registering the same listener again will replace the handler with the 1284af73c2153747d0624ccc75dfa001cb91982957fEino-Ville Talvala * new one provided.</p> 129e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin * 13024eb8a313f1a80a35566b8dc456ec2684a05a22eBenjamin Hendricks * @param listener The new listener to send camera availability notices to 1314af73c2153747d0624ccc75dfa001cb91982957fEino-Ville Talvala * @param handler The handler on which the listener should be invoked, or 1324af73c2153747d0624ccc75dfa001cb91982957fEino-Ville Talvala * {@code null} to use the current thread's {@link android.os.Looper looper}. 133b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala */ 1344af73c2153747d0624ccc75dfa001cb91982957fEino-Ville Talvala public void addAvailabilityListener(AvailabilityListener listener, Handler handler) { 1354af73c2153747d0624ccc75dfa001cb91982957fEino-Ville Talvala if (handler == null) { 1364af73c2153747d0624ccc75dfa001cb91982957fEino-Ville Talvala Looper looper = Looper.myLooper(); 1374af73c2153747d0624ccc75dfa001cb91982957fEino-Ville Talvala if (looper == null) { 1384af73c2153747d0624ccc75dfa001cb91982957fEino-Ville Talvala throw new IllegalArgumentException( 1394af73c2153747d0624ccc75dfa001cb91982957fEino-Ville Talvala "No handler given, and current thread has no looper!"); 1404af73c2153747d0624ccc75dfa001cb91982957fEino-Ville Talvala } 1414af73c2153747d0624ccc75dfa001cb91982957fEino-Ville Talvala handler = new Handler(looper); 1424af73c2153747d0624ccc75dfa001cb91982957fEino-Ville Talvala } 1434af73c2153747d0624ccc75dfa001cb91982957fEino-Ville Talvala 144e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin synchronized (mLock) { 1454af73c2153747d0624ccc75dfa001cb91982957fEino-Ville Talvala mListenerMap.put(listener, handler); 146e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin } 147b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala } 148b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala 149b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala /** 150b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala * Remove a previously-added listener; the listener will no longer receive 151b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala * connection and disconnection callbacks. 152b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala * 1534af73c2153747d0624ccc75dfa001cb91982957fEino-Ville Talvala * <p>Removing a listener that isn't registered has no effect.</p> 154e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin * 15524eb8a313f1a80a35566b8dc456ec2684a05a22eBenjamin Hendricks * @param listener The listener to remove from the notification list 156b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala */ 1574af73c2153747d0624ccc75dfa001cb91982957fEino-Ville Talvala public void removeAvailabilityListener(AvailabilityListener listener) { 158e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin synchronized (mLock) { 1594af73c2153747d0624ccc75dfa001cb91982957fEino-Ville Talvala mListenerMap.remove(listener); 160e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin } 161b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala } 162b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala 163b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala /** 164b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala * <p>Query the capabilities of a camera device. These capabilities are 165b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala * immutable for a given camera.</p> 166b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala * 167b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala * @param cameraId The id of the camera device to query 168b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala * @return The properties of the given camera 169b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala * 170b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala * @throws IllegalArgumentException if the cameraId does not match any 171b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala * currently connected camera device. 172b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala * @throws CameraAccessException if the camera is disabled by device policy. 173b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala * @throws SecurityException if the application does not have permission to 174b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala * access the camera 175b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala * 1764af73c2153747d0624ccc75dfa001cb91982957fEino-Ville Talvala * @see #getCameraIdList 177b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala * @see android.app.admin.DevicePolicyManager#setCameraDisabled 178b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala */ 17968f40066c914aefc1f88819dd46dd1135fb9f5bcIgor Murashkin public CameraCharacteristics getCameraCharacteristics(String cameraId) 180b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala throws CameraAccessException { 181e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin 182e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin synchronized (mLock) { 183e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin if (!getOrCreateDeviceIdListLocked().contains(cameraId)) { 184e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin throw new IllegalArgumentException(String.format("Camera id %s does not match any" + 185e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin " currently connected camera device", cameraId)); 186e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin } 187e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin } 188e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin 1892001188be30649198972a3199a4322d6f7f5f93dZhijun He CameraMetadataNative info = new CameraMetadataNative(); 1902001188be30649198972a3199a4322d6f7f5f93dZhijun He try { 1912001188be30649198972a3199a4322d6f7f5f93dZhijun He mCameraService.getCameraCharacteristics(Integer.valueOf(cameraId), info); 1922001188be30649198972a3199a4322d6f7f5f93dZhijun He } catch(CameraRuntimeException e) { 1932001188be30649198972a3199a4322d6f7f5f93dZhijun He throw e.asChecked(); 1942001188be30649198972a3199a4322d6f7f5f93dZhijun He } catch(RemoteException e) { 1952001188be30649198972a3199a4322d6f7f5f93dZhijun He // impossible 1962001188be30649198972a3199a4322d6f7f5f93dZhijun He return null; 1972001188be30649198972a3199a4322d6f7f5f93dZhijun He } 1982001188be30649198972a3199a4322d6f7f5f93dZhijun He return new CameraCharacteristics(info); 199b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala } 200b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala 201b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala /** 202b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala * Open a connection to a camera with the given ID. Use 2034af73c2153747d0624ccc75dfa001cb91982957fEino-Ville Talvala * {@link #getCameraIdList} to get the list of available camera 204b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala * devices. Note that even if an id is listed, open may fail if the device 2054af73c2153747d0624ccc75dfa001cb91982957fEino-Ville Talvala * is disconnected between the calls to {@link #getCameraIdList} and 206b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala * {@link #openCamera}. 207b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala * 208b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala * @param cameraId The unique identifier of the camera device to open 209868d904306c6a96d94fa0da03515c51c86eefc63Eino-Ville Talvala * @param listener The listener for the camera. Must not be null. 210868d904306c6a96d94fa0da03515c51c86eefc63Eino-Ville Talvala * @param handler The handler to call the listener on. Must not be null. 211b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala * 212b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala * @throws CameraAccessException if the camera is disabled by device policy, 21366ef64514464a1bb9c7931993cc8db3d7539f39aRuben Brunk * or too many camera devices are already open, or the cameraId does not match 21466ef64514464a1bb9c7931993cc8db3d7539f39aRuben Brunk * any currently available camera device. 21566ef64514464a1bb9c7931993cc8db3d7539f39aRuben Brunk * 216b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala * @throws SecurityException if the application does not have permission to 217b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala * access the camera 218868d904306c6a96d94fa0da03515c51c86eefc63Eino-Ville Talvala * @throws IllegalArgumentException if listener or handler is null. 219b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala * 2204af73c2153747d0624ccc75dfa001cb91982957fEino-Ville Talvala * @see #getCameraIdList 221b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala * @see android.app.admin.DevicePolicyManager#setCameraDisabled 222b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala */ 223868d904306c6a96d94fa0da03515c51c86eefc63Eino-Ville Talvala private void openCameraDeviceUserAsync(String cameraId, 224868d904306c6a96d94fa0da03515c51c86eefc63Eino-Ville Talvala CameraDevice.StateListener listener, Handler handler) 225868d904306c6a96d94fa0da03515c51c86eefc63Eino-Ville Talvala throws CameraAccessException { 226e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin try { 227e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin 228e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin synchronized (mLock) { 22970725500dcf3b666b43d50563d64705aab58d2d3Igor Murashkin 23070725500dcf3b666b43d50563d64705aab58d2d3Igor Murashkin ICameraDeviceUser cameraUser; 23170725500dcf3b666b43d50563d64705aab58d2d3Igor Murashkin 2322f1a2e423e0fbb64467d6fcfa4e82c6384f31210Eino-Ville Talvala android.hardware.camera2.impl.CameraDevice device = 233868d904306c6a96d94fa0da03515c51c86eefc63Eino-Ville Talvala new android.hardware.camera2.impl.CameraDevice( 234868d904306c6a96d94fa0da03515c51c86eefc63Eino-Ville Talvala cameraId, 235868d904306c6a96d94fa0da03515c51c86eefc63Eino-Ville Talvala listener, 236868d904306c6a96d94fa0da03515c51c86eefc63Eino-Ville Talvala handler); 23770725500dcf3b666b43d50563d64705aab58d2d3Igor Murashkin 23866ef64514464a1bb9c7931993cc8db3d7539f39aRuben Brunk BinderHolder holder = new BinderHolder(); 239feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk 240feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk ICameraDeviceCallbacks callbacks = device.getCallbacks(); 241feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk int id = Integer.parseInt(cameraId); 242feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk try { 243feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk mCameraService.connectDevice(callbacks, id, mContext.getPackageName(), 244feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk USE_CALLING_UID, holder); 245feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk cameraUser = ICameraDeviceUser.Stub.asInterface(holder.getBinder()); 246feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk } catch (CameraRuntimeException e) { 247feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk if (e.getReason() == CameraAccessException.CAMERA_DEPRECATED_HAL) { 248feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk // Use legacy camera implementation for HAL1 devices 249feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk Log.i(TAG, "Using legacy camera HAL."); 250feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk cameraUser = CameraDeviceUserShim.connectBinderShim(callbacks, id); 251feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk } else { 252feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk // Rethrow otherwise 253feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk throw e; 254feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk } 255feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk } 25670725500dcf3b666b43d50563d64705aab58d2d3Igor Murashkin 25770725500dcf3b666b43d50563d64705aab58d2d3Igor Murashkin // TODO: factor out listener to be non-nested, then move setter to constructor 258868d904306c6a96d94fa0da03515c51c86eefc63Eino-Ville Talvala // For now, calling setRemoteDevice will fire initial 259868d904306c6a96d94fa0da03515c51c86eefc63Eino-Ville Talvala // onOpened/onUnconfigured callbacks. 26070725500dcf3b666b43d50563d64705aab58d2d3Igor Murashkin device.setRemoteDevice(cameraUser); 261e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin } 262e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin 263e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin } catch (NumberFormatException e) { 264e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin throw new IllegalArgumentException("Expected cameraId to be numeric, but it was: " 265e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin + cameraId); 266e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin } catch (CameraRuntimeException e) { 26766ef64514464a1bb9c7931993cc8db3d7539f39aRuben Brunk throw e.asChecked(); 268e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin } catch (RemoteException e) { 269e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin // impossible 270e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin } 271b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala } 272b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala 273b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala /** 2745c9eaf6796a4c972710dd5cd23cdfa334fa8ad2eIgor Murashkin * Open a connection to a camera with the given ID. 2755c9eaf6796a4c972710dd5cd23cdfa334fa8ad2eIgor Murashkin * 2765c9eaf6796a4c972710dd5cd23cdfa334fa8ad2eIgor Murashkin * <p>Use {@link #getCameraIdList} to get the list of available camera 2775c9eaf6796a4c972710dd5cd23cdfa334fa8ad2eIgor Murashkin * devices. Note that even if an id is listed, open may fail if the device 2785c9eaf6796a4c972710dd5cd23cdfa334fa8ad2eIgor Murashkin * is disconnected between the calls to {@link #getCameraIdList} and 2795c9eaf6796a4c972710dd5cd23cdfa334fa8ad2eIgor Murashkin * {@link #openCamera}.</p> 2805c9eaf6796a4c972710dd5cd23cdfa334fa8ad2eIgor Murashkin * 2815c9eaf6796a4c972710dd5cd23cdfa334fa8ad2eIgor Murashkin * <p>If the camera successfully opens after this function call returns, 2825c9eaf6796a4c972710dd5cd23cdfa334fa8ad2eIgor Murashkin * {@link CameraDevice.StateListener#onOpened} will be invoked with the 2835c9eaf6796a4c972710dd5cd23cdfa334fa8ad2eIgor Murashkin * newly opened {@link CameraDevice} in the unconfigured state.</p> 2845c9eaf6796a4c972710dd5cd23cdfa334fa8ad2eIgor Murashkin * 2855c9eaf6796a4c972710dd5cd23cdfa334fa8ad2eIgor Murashkin * <p>If the camera becomes disconnected during initialization 2865c9eaf6796a4c972710dd5cd23cdfa334fa8ad2eIgor Murashkin * after this function call returns, 2875c9eaf6796a4c972710dd5cd23cdfa334fa8ad2eIgor Murashkin * {@link CameraDevice.StateListener#onDisconnected} with a 2885c9eaf6796a4c972710dd5cd23cdfa334fa8ad2eIgor Murashkin * {@link CameraDevice} in the disconnected state (and 2895c9eaf6796a4c972710dd5cd23cdfa334fa8ad2eIgor Murashkin * {@link CameraDevice.StateListener#onOpened} will be skipped).</p> 2905c9eaf6796a4c972710dd5cd23cdfa334fa8ad2eIgor Murashkin * 2915c9eaf6796a4c972710dd5cd23cdfa334fa8ad2eIgor Murashkin * <p>If the camera fails to initialize after this function call returns, 2925c9eaf6796a4c972710dd5cd23cdfa334fa8ad2eIgor Murashkin * {@link CameraDevice.StateListener#onError} will be invoked with a 2935c9eaf6796a4c972710dd5cd23cdfa334fa8ad2eIgor Murashkin * {@link CameraDevice} in the error state (and 2945c9eaf6796a4c972710dd5cd23cdfa334fa8ad2eIgor Murashkin * {@link CameraDevice.StateListener#onOpened} will be skipped).</p> 2955c9eaf6796a4c972710dd5cd23cdfa334fa8ad2eIgor Murashkin * 2965c9eaf6796a4c972710dd5cd23cdfa334fa8ad2eIgor Murashkin * @param cameraId 2975c9eaf6796a4c972710dd5cd23cdfa334fa8ad2eIgor Murashkin * The unique identifier of the camera device to open 2985c9eaf6796a4c972710dd5cd23cdfa334fa8ad2eIgor Murashkin * @param listener 2995c9eaf6796a4c972710dd5cd23cdfa334fa8ad2eIgor Murashkin * The listener which is invoked once the camera is opened 3005c9eaf6796a4c972710dd5cd23cdfa334fa8ad2eIgor Murashkin * @param handler 3015c9eaf6796a4c972710dd5cd23cdfa334fa8ad2eIgor Murashkin * The handler on which the listener should be invoked, or 3025c9eaf6796a4c972710dd5cd23cdfa334fa8ad2eIgor Murashkin * {@code null} to use the current thread's {@link android.os.Looper looper}. 3035c9eaf6796a4c972710dd5cd23cdfa334fa8ad2eIgor Murashkin * 3045c9eaf6796a4c972710dd5cd23cdfa334fa8ad2eIgor Murashkin * @throws CameraAccessException if the camera is disabled by device policy, 3055c9eaf6796a4c972710dd5cd23cdfa334fa8ad2eIgor Murashkin * or the camera has become or was disconnected. 3065c9eaf6796a4c972710dd5cd23cdfa334fa8ad2eIgor Murashkin * 3075c9eaf6796a4c972710dd5cd23cdfa334fa8ad2eIgor Murashkin * @throws IllegalArgumentException if cameraId or the listener was null, 3085c9eaf6796a4c972710dd5cd23cdfa334fa8ad2eIgor Murashkin * or the cameraId does not match any currently or previously available 3095c9eaf6796a4c972710dd5cd23cdfa334fa8ad2eIgor Murashkin * camera device. 3105c9eaf6796a4c972710dd5cd23cdfa334fa8ad2eIgor Murashkin * 3115c9eaf6796a4c972710dd5cd23cdfa334fa8ad2eIgor Murashkin * @throws SecurityException if the application does not have permission to 3125c9eaf6796a4c972710dd5cd23cdfa334fa8ad2eIgor Murashkin * access the camera 3135c9eaf6796a4c972710dd5cd23cdfa334fa8ad2eIgor Murashkin * 3145c9eaf6796a4c972710dd5cd23cdfa334fa8ad2eIgor Murashkin * @see #getCameraIdList 3155c9eaf6796a4c972710dd5cd23cdfa334fa8ad2eIgor Murashkin * @see android.app.admin.DevicePolicyManager#setCameraDisabled 3165c9eaf6796a4c972710dd5cd23cdfa334fa8ad2eIgor Murashkin */ 3175c9eaf6796a4c972710dd5cd23cdfa334fa8ad2eIgor Murashkin public void openCamera(String cameraId, final CameraDevice.StateListener listener, 3185c9eaf6796a4c972710dd5cd23cdfa334fa8ad2eIgor Murashkin Handler handler) 3195c9eaf6796a4c972710dd5cd23cdfa334fa8ad2eIgor Murashkin throws CameraAccessException { 3205c9eaf6796a4c972710dd5cd23cdfa334fa8ad2eIgor Murashkin 3215c9eaf6796a4c972710dd5cd23cdfa334fa8ad2eIgor Murashkin if (cameraId == null) { 3225c9eaf6796a4c972710dd5cd23cdfa334fa8ad2eIgor Murashkin throw new IllegalArgumentException("cameraId was null"); 3235c9eaf6796a4c972710dd5cd23cdfa334fa8ad2eIgor Murashkin } else if (listener == null) { 3245c9eaf6796a4c972710dd5cd23cdfa334fa8ad2eIgor Murashkin throw new IllegalArgumentException("listener was null"); 3255c9eaf6796a4c972710dd5cd23cdfa334fa8ad2eIgor Murashkin } else if (handler == null) { 3265c9eaf6796a4c972710dd5cd23cdfa334fa8ad2eIgor Murashkin if (Looper.myLooper() != null) { 3275c9eaf6796a4c972710dd5cd23cdfa334fa8ad2eIgor Murashkin handler = new Handler(); 3285c9eaf6796a4c972710dd5cd23cdfa334fa8ad2eIgor Murashkin } else { 3295c9eaf6796a4c972710dd5cd23cdfa334fa8ad2eIgor Murashkin throw new IllegalArgumentException( 3305c9eaf6796a4c972710dd5cd23cdfa334fa8ad2eIgor Murashkin "Looper doesn't exist in the calling thread"); 3315c9eaf6796a4c972710dd5cd23cdfa334fa8ad2eIgor Murashkin } 3325c9eaf6796a4c972710dd5cd23cdfa334fa8ad2eIgor Murashkin } 3335c9eaf6796a4c972710dd5cd23cdfa334fa8ad2eIgor Murashkin 334868d904306c6a96d94fa0da03515c51c86eefc63Eino-Ville Talvala openCameraDeviceUserAsync(cameraId, listener, handler); 3355c9eaf6796a4c972710dd5cd23cdfa334fa8ad2eIgor Murashkin } 3365c9eaf6796a4c972710dd5cd23cdfa334fa8ad2eIgor Murashkin 3375c9eaf6796a4c972710dd5cd23cdfa334fa8ad2eIgor Murashkin /** 3384af73c2153747d0624ccc75dfa001cb91982957fEino-Ville Talvala * Interface for listening to camera devices becoming available or 3394af73c2153747d0624ccc75dfa001cb91982957fEino-Ville Talvala * unavailable. 3404af73c2153747d0624ccc75dfa001cb91982957fEino-Ville Talvala * 3414af73c2153747d0624ccc75dfa001cb91982957fEino-Ville Talvala * <p>Cameras become available when they are no longer in use, or when a new 342b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala * removable camera is connected. They become unavailable when some 343b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala * application or service starts using a camera, or when a removable camera 3444af73c2153747d0624ccc75dfa001cb91982957fEino-Ville Talvala * is disconnected.</p> 3454af73c2153747d0624ccc75dfa001cb91982957fEino-Ville Talvala * 3464af73c2153747d0624ccc75dfa001cb91982957fEino-Ville Talvala * @see addAvailabilityListener 347b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala */ 3484af73c2153747d0624ccc75dfa001cb91982957fEino-Ville Talvala public static abstract class AvailabilityListener { 3494af73c2153747d0624ccc75dfa001cb91982957fEino-Ville Talvala 350b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala /** 351b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala * A new camera has become available to use. 352b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala * 3534af73c2153747d0624ccc75dfa001cb91982957fEino-Ville Talvala * <p>The default implementation of this method does nothing.</p> 3544af73c2153747d0624ccc75dfa001cb91982957fEino-Ville Talvala * 355b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala * @param cameraId The unique identifier of the new camera. 356b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala */ 3574af73c2153747d0624ccc75dfa001cb91982957fEino-Ville Talvala public void onCameraAvailable(String cameraId) { 3584af73c2153747d0624ccc75dfa001cb91982957fEino-Ville Talvala // default empty implementation 3594af73c2153747d0624ccc75dfa001cb91982957fEino-Ville Talvala } 360b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala 361b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala /** 3624af73c2153747d0624ccc75dfa001cb91982957fEino-Ville Talvala * A previously-available camera has become unavailable for use. 3634af73c2153747d0624ccc75dfa001cb91982957fEino-Ville Talvala * 3644af73c2153747d0624ccc75dfa001cb91982957fEino-Ville Talvala * <p>If an application had an active CameraDevice instance for the 3654af73c2153747d0624ccc75dfa001cb91982957fEino-Ville Talvala * now-disconnected camera, that application will receive a 3665c9eaf6796a4c972710dd5cd23cdfa334fa8ad2eIgor Murashkin * {@link CameraDevice.StateListener#onDisconnected disconnection error}.</p> 3674af73c2153747d0624ccc75dfa001cb91982957fEino-Ville Talvala * 3684af73c2153747d0624ccc75dfa001cb91982957fEino-Ville Talvala * <p>The default implementation of this method does nothing.</p> 369b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala * 370b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala * @param cameraId The unique identifier of the disconnected camera. 371b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala */ 3724af73c2153747d0624ccc75dfa001cb91982957fEino-Ville Talvala public void onCameraUnavailable(String cameraId) { 3734af73c2153747d0624ccc75dfa001cb91982957fEino-Ville Talvala // default empty implementation 3744af73c2153747d0624ccc75dfa001cb91982957fEino-Ville Talvala } 375b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala } 376e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin 377e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin private ArrayList<String> getOrCreateDeviceIdListLocked() throws CameraAccessException { 378e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin if (mDeviceIdList == null) { 379e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin int numCameras = 0; 380e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin 381e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin try { 382e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin numCameras = mCameraService.getNumberOfCameras(); 383e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin } catch(CameraRuntimeException e) { 384e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin throw e.asChecked(); 385e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin } catch (RemoteException e) { 386e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin // impossible 387e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin return null; 388e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin } 389e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin 390e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin mDeviceIdList = new ArrayList<String>(); 39118fe0ae08d49b0fe4b6414a3841bd0fcab5419e8Zhijun He CameraMetadataNative info = new CameraMetadataNative(); 392e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin for (int i = 0; i < numCameras; ++i) { 393e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin // Non-removable cameras use integers starting at 0 for their 394e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin // identifiers 39518fe0ae08d49b0fe4b6414a3841bd0fcab5419e8Zhijun He boolean isDeviceSupported = false; 39618fe0ae08d49b0fe4b6414a3841bd0fcab5419e8Zhijun He try { 39718fe0ae08d49b0fe4b6414a3841bd0fcab5419e8Zhijun He mCameraService.getCameraCharacteristics(i, info); 39818fe0ae08d49b0fe4b6414a3841bd0fcab5419e8Zhijun He if (!info.isEmpty()) { 39918fe0ae08d49b0fe4b6414a3841bd0fcab5419e8Zhijun He isDeviceSupported = true; 40018fe0ae08d49b0fe4b6414a3841bd0fcab5419e8Zhijun He } else { 40118fe0ae08d49b0fe4b6414a3841bd0fcab5419e8Zhijun He throw new AssertionError("Expected to get non-empty characteristics"); 40218fe0ae08d49b0fe4b6414a3841bd0fcab5419e8Zhijun He } 40318fe0ae08d49b0fe4b6414a3841bd0fcab5419e8Zhijun He } catch(IllegalArgumentException e) { 40418fe0ae08d49b0fe4b6414a3841bd0fcab5419e8Zhijun He // Got a BAD_VALUE from service, meaning that this 40518fe0ae08d49b0fe4b6414a3841bd0fcab5419e8Zhijun He // device is not supported. 40618fe0ae08d49b0fe4b6414a3841bd0fcab5419e8Zhijun He } catch(CameraRuntimeException e) { 40718fe0ae08d49b0fe4b6414a3841bd0fcab5419e8Zhijun He throw e.asChecked(); 40818fe0ae08d49b0fe4b6414a3841bd0fcab5419e8Zhijun He } catch(RemoteException e) { 40918fe0ae08d49b0fe4b6414a3841bd0fcab5419e8Zhijun He // impossible 41018fe0ae08d49b0fe4b6414a3841bd0fcab5419e8Zhijun He } 41118fe0ae08d49b0fe4b6414a3841bd0fcab5419e8Zhijun He 41218fe0ae08d49b0fe4b6414a3841bd0fcab5419e8Zhijun He if (isDeviceSupported) { 41318fe0ae08d49b0fe4b6414a3841bd0fcab5419e8Zhijun He mDeviceIdList.add(String.valueOf(i)); 41418fe0ae08d49b0fe4b6414a3841bd0fcab5419e8Zhijun He } 415e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin } 416e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin 417e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin } 418e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin return mDeviceIdList; 419e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin } 420e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin 421e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin // TODO: this class needs unit tests 422e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin // TODO: extract class into top level 423ecb323e3ce94f62411b6799f9a0aa42b052de30dZhijun He private class CameraServiceListener extends ICameraServiceListener.Stub { 424e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin 425e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin // Keep up-to-date with ICameraServiceListener.h 426e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin 427e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin // Device physically unplugged 428e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin public static final int STATUS_NOT_PRESENT = 0; 429e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin // Device physically has been plugged in 430e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin // and the camera can be used exclusively 431e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin public static final int STATUS_PRESENT = 1; 432e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin // Device physically has been plugged in 433e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin // but it will not be connect-able until enumeration is complete 434e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin public static final int STATUS_ENUMERATING = 2; 435e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin // Camera is in use by another app and cannot be used exclusively 436e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin public static final int STATUS_NOT_AVAILABLE = 0x80000000; 437e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin 438e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin // Camera ID -> Status map 4394af73c2153747d0624ccc75dfa001cb91982957fEino-Ville Talvala private final ArrayMap<String, Integer> mDeviceStatus = new ArrayMap<String, Integer>(); 440e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin 441e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin private static final String TAG = "CameraServiceListener"; 442e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin 443e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin @Override 444e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin public IBinder asBinder() { 445e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin return this; 446e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin } 447e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin 448e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin private boolean isAvailable(int status) { 449e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin switch (status) { 450e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin case STATUS_PRESENT: 451e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin return true; 452e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin default: 453e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin return false; 454e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin } 455e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin } 456e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin 457e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin private boolean validStatus(int status) { 458e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin switch (status) { 459e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin case STATUS_NOT_PRESENT: 460e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin case STATUS_PRESENT: 461e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin case STATUS_ENUMERATING: 462e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin case STATUS_NOT_AVAILABLE: 463e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin return true; 464e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin default: 465e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin return false; 466e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin } 467e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin } 468e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin 469e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin @Override 470e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin public void onStatusChanged(int status, int cameraId) throws RemoteException { 47170725500dcf3b666b43d50563d64705aab58d2d3Igor Murashkin synchronized(CameraManager.this.mLock) { 472e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin 473e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin Log.v(TAG, 474e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin String.format("Camera id %d has status changed to 0x%x", cameraId, status)); 475e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin 4764af73c2153747d0624ccc75dfa001cb91982957fEino-Ville Talvala final String id = String.valueOf(cameraId); 477e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin 478e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin if (!validStatus(status)) { 479e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin Log.e(TAG, String.format("Ignoring invalid device %d status 0x%x", cameraId, 480e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin status)); 481e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin return; 482e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin } 483e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin 484e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin Integer oldStatus = mDeviceStatus.put(id, status); 485e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin 4867441695049674e457064f289b74b11f62fa5c943Igor Murashkin if (oldStatus != null && oldStatus == status) { 487e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin Log.v(TAG, String.format( 488e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin "Device status changed to 0x%x, which is what it already was", 489e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin status)); 490e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin return; 491e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin } 492e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin 493e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin // TODO: consider abstracting out this state minimization + transition 494e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin // into a separate 495e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin // more easily testable class 496e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin // i.e. (new State()).addState(STATE_AVAILABLE) 497e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin // .addState(STATE_NOT_AVAILABLE) 498e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin // .addTransition(STATUS_PRESENT, STATE_AVAILABLE), 499e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin // .addTransition(STATUS_NOT_PRESENT, STATE_NOT_AVAILABLE) 500e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin // .addTransition(STATUS_ENUMERATING, STATE_NOT_AVAILABLE); 501e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin // .addTransition(STATUS_NOT_AVAILABLE, STATE_NOT_AVAILABLE); 502e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin 503e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin // Translate all the statuses to either 'available' or 'not available' 504e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin // available -> available => no new update 505e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin // not available -> not available => no new update 506e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin if (oldStatus != null && isAvailable(status) == isAvailable(oldStatus)) { 507e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin 508e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin Log.v(TAG, 509e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin String.format( 510e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin "Device status was previously available (%d), " + 511e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin " and is now again available (%d)" + 512e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin "so no new client visible update will be sent", 513e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin isAvailable(status), isAvailable(status))); 514e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin return; 515e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin } 516e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin 5174af73c2153747d0624ccc75dfa001cb91982957fEino-Ville Talvala final int listenerCount = mListenerMap.size(); 5184af73c2153747d0624ccc75dfa001cb91982957fEino-Ville Talvala for (int i = 0; i < listenerCount; i++) { 5194af73c2153747d0624ccc75dfa001cb91982957fEino-Ville Talvala Handler handler = mListenerMap.valueAt(i); 5204af73c2153747d0624ccc75dfa001cb91982957fEino-Ville Talvala final AvailabilityListener listener = mListenerMap.keyAt(i); 521e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin if (isAvailable(status)) { 5224af73c2153747d0624ccc75dfa001cb91982957fEino-Ville Talvala handler.post( 5234af73c2153747d0624ccc75dfa001cb91982957fEino-Ville Talvala new Runnable() { 5245c9eaf6796a4c972710dd5cd23cdfa334fa8ad2eIgor Murashkin @Override 5254af73c2153747d0624ccc75dfa001cb91982957fEino-Ville Talvala public void run() { 5264af73c2153747d0624ccc75dfa001cb91982957fEino-Ville Talvala listener.onCameraAvailable(id); 5274af73c2153747d0624ccc75dfa001cb91982957fEino-Ville Talvala } 5284af73c2153747d0624ccc75dfa001cb91982957fEino-Ville Talvala }); 529e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin } else { 5304af73c2153747d0624ccc75dfa001cb91982957fEino-Ville Talvala handler.post( 5314af73c2153747d0624ccc75dfa001cb91982957fEino-Ville Talvala new Runnable() { 5325c9eaf6796a4c972710dd5cd23cdfa334fa8ad2eIgor Murashkin @Override 5334af73c2153747d0624ccc75dfa001cb91982957fEino-Ville Talvala public void run() { 5344af73c2153747d0624ccc75dfa001cb91982957fEino-Ville Talvala listener.onCameraUnavailable(id); 5354af73c2153747d0624ccc75dfa001cb91982957fEino-Ville Talvala } 5364af73c2153747d0624ccc75dfa001cb91982957fEino-Ville Talvala }); 537e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin } 538e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin } // for 539e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin } // synchronized 540e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin } // onStatusChanged 541e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin } // CameraServiceListener 542e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin} // CameraManager 543