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;
224961bc88d7bab869a5296789d26fcfa31ad5f644Igor Murashkinimport android.hardware.CameraInfo;
2370c2207c34cf0e6b3b383b1b1500ff5385aa51a6Eino-Ville Talvalaimport android.hardware.camera2.impl.CameraMetadataNative;
24feb50af361e4305a25758966b6b5df2738c00259Ruben Brunkimport android.hardware.camera2.legacy.CameraDeviceUserShim;
254961bc88d7bab869a5296789d26fcfa31ad5f644Igor Murashkinimport android.hardware.camera2.legacy.LegacyMetadataMapper;
26bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvalaimport android.hardware.camera2.utils.CameraServiceBinderDecorator;
272f1a2e423e0fbb64467d6fcfa4e82c6384f31210Eino-Ville Talvalaimport android.hardware.camera2.utils.CameraRuntimeException;
2866ef64514464a1bb9c7931993cc8db3d7539f39aRuben Brunkimport android.hardware.camera2.utils.BinderHolder;
29e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkinimport android.os.IBinder;
304af73c2153747d0624ccc75dfa001cb91982957fEino-Ville Talvalaimport android.os.Handler;
314af73c2153747d0624ccc75dfa001cb91982957fEino-Ville Talvalaimport android.os.Looper;
32e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkinimport android.os.RemoteException;
33e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkinimport android.os.ServiceManager;
34e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkinimport android.util.Log;
354af73c2153747d0624ccc75dfa001cb91982957fEino-Ville Talvalaimport android.util.ArrayMap;
36e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin
37e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkinimport java.util.ArrayList;
38e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin
39b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala/**
40b67a3b36fd569e63c1b8ca6b2701c34c7a3927c1Eino-Ville Talvala * <p>A system service manager for detecting, characterizing, and connecting to
41b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala * {@link CameraDevice CameraDevices}.</p>
42b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala *
43b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala * <p>You can get an instance of this class by calling
44b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala * {@link android.content.Context#getSystemService(String) Context.getSystemService()}.</p>
45b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala *
46b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala * <pre>CameraManager manager = (CameraManager) getSystemService(Context.CAMERA_SERVICE);</pre>
47b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala *
48b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala * <p>For more details about communicating with camera devices, read the Camera
492f1a2e423e0fbb64467d6fcfa4e82c6384f31210Eino-Ville Talvala * developer guide or the {@link android.hardware.camera2 camera2}
50b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala * package documentation.</p>
51b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala */
52b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvalapublic final class CameraManager {
53b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala
5485c4388de1fea3d45783f07895c2b113c4cc1ba5Ruben Brunk    private static final String TAG = "CameraManager";
55bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala    private final boolean DEBUG;
5685c4388de1fea3d45783f07895c2b113c4cc1ba5Ruben Brunk
57b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala    /**
58e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin     * This should match the ICameraService definition
59e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin     */
60e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin    private static final String CAMERA_SERVICE_BINDER_NAME = "media.camera";
61e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin    private static final int USE_CALLING_UID = -1;
62e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin
634961bc88d7bab869a5296789d26fcfa31ad5f644Igor Murashkin    @SuppressWarnings("unused")
644961bc88d7bab869a5296789d26fcfa31ad5f644Igor Murashkin    private static final int API_VERSION_1 = 1;
654961bc88d7bab869a5296789d26fcfa31ad5f644Igor Murashkin    private static final int API_VERSION_2 = 2;
664961bc88d7bab869a5296789d26fcfa31ad5f644Igor Murashkin
67bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala    // Access only through getCameraServiceLocked to deal with binder death
68bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala    private ICameraService mCameraService;
69bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala
70e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin    private ArrayList<String> mDeviceIdList;
714af73c2153747d0624ccc75dfa001cb91982957fEino-Ville Talvala
72fd887436bd111e4d2c7307578a51b5070025b7f2Eino-Ville Talvala    private final ArrayMap<AvailabilityCallback, Handler> mCallbackMap =
73fd887436bd111e4d2c7307578a51b5070025b7f2Eino-Ville Talvala            new ArrayMap<AvailabilityCallback, Handler>();
744af73c2153747d0624ccc75dfa001cb91982957fEino-Ville Talvala
75e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin    private final Context mContext;
76e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin    private final Object mLock = new Object();
77e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin
78bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala    private final CameraServiceListener mServiceListener = new CameraServiceListener();
79bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala
80e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin    /**
81b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala     * @hide
82b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala     */
83e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin    public CameraManager(Context context) {
84bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala        DEBUG = Log.isLoggable(TAG, Log.DEBUG);
85bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala        synchronized(mLock) {
86bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala            mContext = context;
8785c4388de1fea3d45783f07895c2b113c4cc1ba5Ruben Brunk
88bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala            connectCameraServiceLocked();
89e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin        }
90b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala    }
91b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala
92b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala    /**
934af73c2153747d0624ccc75dfa001cb91982957fEino-Ville Talvala     * Return the list of currently connected camera devices by
944af73c2153747d0624ccc75dfa001cb91982957fEino-Ville Talvala     * identifier.
954af73c2153747d0624ccc75dfa001cb91982957fEino-Ville Talvala     *
964af73c2153747d0624ccc75dfa001cb91982957fEino-Ville Talvala     * <p>Non-removable cameras use integers starting at 0 for their
97b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala     * identifiers, while removable cameras have a unique identifier for each
98b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala     * individual device, even if they are the same model.</p>
99b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala     *
100b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala     * @return The list of currently connected camera devices.
101b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala     */
1024af73c2153747d0624ccc75dfa001cb91982957fEino-Ville Talvala    public String[] getCameraIdList() throws CameraAccessException {
103e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin        synchronized (mLock) {
104bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala            // ID list creation handles various known failures in device enumeration, so only
105bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala            // exceptions it'll throw are unexpected, and should be propagated upward.
106bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala            return getOrCreateDeviceIdListLocked().toArray(new String[0]);
107e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin        }
108b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala    }
109b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala
110b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala    /**
111fd887436bd111e4d2c7307578a51b5070025b7f2Eino-Ville Talvala     * Register a callback to be notified about camera device availability.
112b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala     *
113fd887436bd111e4d2c7307578a51b5070025b7f2Eino-Ville Talvala     * <p>Registering the same callback again will replace the handler with the
1144af73c2153747d0624ccc75dfa001cb91982957fEino-Ville Talvala     * new one provided.</p>
115e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin     *
116fd887436bd111e4d2c7307578a51b5070025b7f2Eino-Ville Talvala     * <p>The first time a callback is registered, it is immediately called
117bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala     * with the availability status of all currently known camera devices.</p>
118bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala     *
119fd887436bd111e4d2c7307578a51b5070025b7f2Eino-Ville Talvala     * @param callback the new callback to send camera availability notices to
120fd887436bd111e4d2c7307578a51b5070025b7f2Eino-Ville Talvala     * @param handler The handler on which the callback should be invoked, or
1214af73c2153747d0624ccc75dfa001cb91982957fEino-Ville Talvala     * {@code null} to use the current thread's {@link android.os.Looper looper}.
122b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala     */
123fd887436bd111e4d2c7307578a51b5070025b7f2Eino-Ville Talvala    public void registerAvailabilityCallback(AvailabilityCallback callback, Handler handler) {
1244af73c2153747d0624ccc75dfa001cb91982957fEino-Ville Talvala        if (handler == null) {
1254af73c2153747d0624ccc75dfa001cb91982957fEino-Ville Talvala            Looper looper = Looper.myLooper();
1264af73c2153747d0624ccc75dfa001cb91982957fEino-Ville Talvala            if (looper == null) {
1274af73c2153747d0624ccc75dfa001cb91982957fEino-Ville Talvala                throw new IllegalArgumentException(
1284af73c2153747d0624ccc75dfa001cb91982957fEino-Ville Talvala                        "No handler given, and current thread has no looper!");
1294af73c2153747d0624ccc75dfa001cb91982957fEino-Ville Talvala            }
1304af73c2153747d0624ccc75dfa001cb91982957fEino-Ville Talvala            handler = new Handler(looper);
1314af73c2153747d0624ccc75dfa001cb91982957fEino-Ville Talvala        }
1324af73c2153747d0624ccc75dfa001cb91982957fEino-Ville Talvala
133e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin        synchronized (mLock) {
134fd887436bd111e4d2c7307578a51b5070025b7f2Eino-Ville Talvala            Handler oldHandler = mCallbackMap.put(callback, handler);
135fd887436bd111e4d2c7307578a51b5070025b7f2Eino-Ville Talvala            // For new callbacks, provide initial availability information
136bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala            if (oldHandler == null) {
137fd887436bd111e4d2c7307578a51b5070025b7f2Eino-Ville Talvala                mServiceListener.updateCallbackLocked(callback, handler);
138bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala            }
139e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin        }
140b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala    }
141b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala
142b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala    /**
143fd887436bd111e4d2c7307578a51b5070025b7f2Eino-Ville Talvala     * Remove a previously-added callback; the callback will no longer receive connection and
144fd887436bd111e4d2c7307578a51b5070025b7f2Eino-Ville Talvala     * disconnection callbacks.
145b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala     *
146fd887436bd111e4d2c7307578a51b5070025b7f2Eino-Ville Talvala     * <p>Removing a callback that isn't registered has no effect.</p>
147e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin     *
148fd887436bd111e4d2c7307578a51b5070025b7f2Eino-Ville Talvala     * @param callback The callback to remove from the notification list
149b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala     */
150fd887436bd111e4d2c7307578a51b5070025b7f2Eino-Ville Talvala    public void unregisterAvailabilityCallback(AvailabilityCallback callback) {
151e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin        synchronized (mLock) {
152fd887436bd111e4d2c7307578a51b5070025b7f2Eino-Ville Talvala            mCallbackMap.remove(callback);
153e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin        }
154b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala    }
155b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala
156b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala    /**
157b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala     * <p>Query the capabilities of a camera device. These capabilities are
158b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala     * immutable for a given camera.</p>
159b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala     *
160b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala     * @param cameraId The id of the camera device to query
161b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala     * @return The properties of the given camera
162b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala     *
163b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala     * @throws IllegalArgumentException if the cameraId does not match any
164bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala     *         known camera device.
165bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala     * @throws CameraAccessException if the camera is disabled by device policy, or
166bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala     *         the camera device has been disconnected.
167b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala     * @throws SecurityException if the application does not have permission to
168bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala     *         access the camera
169b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala     *
1704af73c2153747d0624ccc75dfa001cb91982957fEino-Ville Talvala     * @see #getCameraIdList
171b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala     * @see android.app.admin.DevicePolicyManager#setCameraDisabled
172b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala     */
17368f40066c914aefc1f88819dd46dd1135fb9f5bcIgor Murashkin    public CameraCharacteristics getCameraCharacteristics(String cameraId)
174b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala            throws CameraAccessException {
175bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala        CameraCharacteristics characteristics = null;
176e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin
177e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin        synchronized (mLock) {
178e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin            if (!getOrCreateDeviceIdListLocked().contains(cameraId)) {
179e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin                throw new IllegalArgumentException(String.format("Camera id %s does not match any" +
180e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin                        " currently connected camera device", cameraId));
181e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin            }
182e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin
183bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala            int id = Integer.valueOf(cameraId);
1844961bc88d7bab869a5296789d26fcfa31ad5f644Igor Murashkin
185bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala            /*
186bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala             * Get the camera characteristics from the camera service directly if it supports it,
187bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala             * otherwise get them from the legacy shim instead.
188bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala             */
1894961bc88d7bab869a5296789d26fcfa31ad5f644Igor Murashkin
190bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala            ICameraService cameraService = getCameraServiceLocked();
191bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala            if (cameraService == null) {
192bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala                throw new CameraAccessException(CameraAccessException.CAMERA_DISCONNECTED,
193bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala                        "Camera service is currently unavailable");
194bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala            }
1954961bc88d7bab869a5296789d26fcfa31ad5f644Igor Murashkin            try {
196bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala                if (!supportsCamera2ApiLocked(cameraId)) {
197bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala                    // Legacy backwards compatibility path; build static info from the camera
198bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala                    // parameters
199bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala                    String[] outParameters = new String[1];
2004961bc88d7bab869a5296789d26fcfa31ad5f644Igor Murashkin
201bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala                    cameraService.getLegacyParameters(id, /*out*/outParameters);
202bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala                    String parameters = outParameters[0];
2034961bc88d7bab869a5296789d26fcfa31ad5f644Igor Murashkin
204bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala                    CameraInfo info = new CameraInfo();
205bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala                    cameraService.getCameraInfo(id, /*out*/info);
2064961bc88d7bab869a5296789d26fcfa31ad5f644Igor Murashkin
207bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala                    characteristics = LegacyMetadataMapper.createCharacteristics(parameters, info);
208bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala                } else {
209bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala                    // Normal path: Get the camera characteristics directly from the camera service
210bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala                    CameraMetadataNative info = new CameraMetadataNative();
2114961bc88d7bab869a5296789d26fcfa31ad5f644Igor Murashkin
212bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala                    cameraService.getCameraCharacteristics(id, info);
213bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala
214bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala                    characteristics = new CameraCharacteristics(info);
215bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala                }
216bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala            } catch (CameraRuntimeException e) {
2174961bc88d7bab869a5296789d26fcfa31ad5f644Igor Murashkin                throw e.asChecked();
218bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala            } catch (RemoteException e) {
219bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala                // Camera service died - act as if the camera was disconnected
220bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala                throw new CameraAccessException(CameraAccessException.CAMERA_DISCONNECTED,
221bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala                        "Camera service is currently unavailable", e);
2224961bc88d7bab869a5296789d26fcfa31ad5f644Igor Murashkin            }
2232001188be30649198972a3199a4322d6f7f5f93dZhijun He        }
224bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala        return characteristics;
225b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala    }
226b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala
227b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala    /**
228cca00c614c24a71dc234c79ad6241efa9f6c7676Eino-Ville Talvala     * Helper for openning a connection to a camera with the given ID.
229b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala     *
230b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala     * @param cameraId The unique identifier of the camera device to open
231fd887436bd111e4d2c7307578a51b5070025b7f2Eino-Ville Talvala     * @param callback The callback for the camera. Must not be null.
232fd887436bd111e4d2c7307578a51b5070025b7f2Eino-Ville Talvala     * @param handler  The handler to invoke the callback on. Must not be null.
233b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala     *
234b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala     * @throws CameraAccessException if the camera is disabled by device policy,
23566ef64514464a1bb9c7931993cc8db3d7539f39aRuben Brunk     * or too many camera devices are already open, or the cameraId does not match
23666ef64514464a1bb9c7931993cc8db3d7539f39aRuben Brunk     * any currently available camera device.
23766ef64514464a1bb9c7931993cc8db3d7539f39aRuben Brunk     *
238b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala     * @throws SecurityException if the application does not have permission to
239b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala     * access the camera
240fd887436bd111e4d2c7307578a51b5070025b7f2Eino-Ville Talvala     * @throws IllegalArgumentException if callback or handler is null.
241cca00c614c24a71dc234c79ad6241efa9f6c7676Eino-Ville Talvala     * @return A handle to the newly-created camera device.
242b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala     *
2434af73c2153747d0624ccc75dfa001cb91982957fEino-Ville Talvala     * @see #getCameraIdList
244b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala     * @see android.app.admin.DevicePolicyManager#setCameraDisabled
245b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala     */
246cca00c614c24a71dc234c79ad6241efa9f6c7676Eino-Ville Talvala    private CameraDevice openCameraDeviceUserAsync(String cameraId,
247fd887436bd111e4d2c7307578a51b5070025b7f2Eino-Ville Talvala            CameraDevice.StateCallback callback, Handler handler)
248868d904306c6a96d94fa0da03515c51c86eefc63Eino-Ville Talvala            throws CameraAccessException {
249574936894d3044445a272b39f2d925af40ece5d8Ruben Brunk        CameraCharacteristics characteristics = getCameraCharacteristics(cameraId);
250cca00c614c24a71dc234c79ad6241efa9f6c7676Eino-Ville Talvala        CameraDevice device = null;
251e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin        try {
252e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin
253e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin            synchronized (mLock) {
25470725500dcf3b666b43d50563d64705aab58d2d3Igor Murashkin
2557fcb357811d4dc1f44624e30ad924e9e580d4cbfEino-Ville Talvala                ICameraDeviceUser cameraUser = null;
25670725500dcf3b666b43d50563d64705aab58d2d3Igor Murashkin
25721547d66a9ce591ff30a3ad4102f7f30a4764d80Igor Murashkin                android.hardware.camera2.impl.CameraDeviceImpl deviceImpl =
25821547d66a9ce591ff30a3ad4102f7f30a4764d80Igor Murashkin                        new android.hardware.camera2.impl.CameraDeviceImpl(
259868d904306c6a96d94fa0da03515c51c86eefc63Eino-Ville Talvala                                cameraId,
260fd887436bd111e4d2c7307578a51b5070025b7f2Eino-Ville Talvala                                callback,
261574936894d3044445a272b39f2d925af40ece5d8Ruben Brunk                                handler,
262574936894d3044445a272b39f2d925af40ece5d8Ruben Brunk                                characteristics);
26370725500dcf3b666b43d50563d64705aab58d2d3Igor Murashkin
26466ef64514464a1bb9c7931993cc8db3d7539f39aRuben Brunk                BinderHolder holder = new BinderHolder();
265feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk
266cca00c614c24a71dc234c79ad6241efa9f6c7676Eino-Ville Talvala                ICameraDeviceCallbacks callbacks = deviceImpl.getCallbacks();
267feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk                int id = Integer.parseInt(cameraId);
268feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk                try {
269bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala                    if (supportsCamera2ApiLocked(cameraId)) {
270a1d662716b3da384dfe3a758f079e0cbd089784aIgor Murashkin                        // Use cameraservice's cameradeviceclient implementation for HAL3.2+ devices
271bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala                        ICameraService cameraService = getCameraServiceLocked();
272bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala                        if (cameraService == null) {
273bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala                            throw new CameraRuntimeException(
274bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala                                CameraAccessException.CAMERA_DISCONNECTED,
275bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala                                "Camera service is currently unavailable");
276bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala                        }
277bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala                        cameraService.connectDevice(callbacks, id,
278bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala                                mContext.getPackageName(), USE_CALLING_UID, holder);
279a1d662716b3da384dfe3a758f079e0cbd089784aIgor Murashkin                        cameraUser = ICameraDeviceUser.Stub.asInterface(holder.getBinder());
280a1d662716b3da384dfe3a758f079e0cbd089784aIgor Murashkin                    } else {
281feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk                        // Use legacy camera implementation for HAL1 devices
282feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk                        Log.i(TAG, "Using legacy camera HAL.");
283feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk                        cameraUser = CameraDeviceUserShim.connectBinderShim(callbacks, id);
284a1d662716b3da384dfe3a758f079e0cbd089784aIgor Murashkin                    }
285a1d662716b3da384dfe3a758f079e0cbd089784aIgor Murashkin                } catch (CameraRuntimeException e) {
286a1d662716b3da384dfe3a758f079e0cbd089784aIgor Murashkin                    if (e.getReason() == CameraAccessException.CAMERA_DEPRECATED_HAL) {
287a1d662716b3da384dfe3a758f079e0cbd089784aIgor Murashkin                        throw new AssertionError("Should've gone down the shim path");
2887fcb357811d4dc1f44624e30ad924e9e580d4cbfEino-Ville Talvala                    } else if (e.getReason() == CameraAccessException.CAMERA_IN_USE ||
2897fcb357811d4dc1f44624e30ad924e9e580d4cbfEino-Ville Talvala                            e.getReason() == CameraAccessException.MAX_CAMERAS_IN_USE ||
2907fcb357811d4dc1f44624e30ad924e9e580d4cbfEino-Ville Talvala                            e.getReason() == CameraAccessException.CAMERA_DISABLED ||
2917fcb357811d4dc1f44624e30ad924e9e580d4cbfEino-Ville Talvala                            e.getReason() == CameraAccessException.CAMERA_DISCONNECTED ||
2927fcb357811d4dc1f44624e30ad924e9e580d4cbfEino-Ville Talvala                            e.getReason() == CameraAccessException.CAMERA_ERROR) {
2937fcb357811d4dc1f44624e30ad924e9e580d4cbfEino-Ville Talvala                        // Received one of the known connection errors
2947fcb357811d4dc1f44624e30ad924e9e580d4cbfEino-Ville Talvala                        // The remote camera device cannot be connected to, so
2957fcb357811d4dc1f44624e30ad924e9e580d4cbfEino-Ville Talvala                        // set the local camera to the startup error state
2967fcb357811d4dc1f44624e30ad924e9e580d4cbfEino-Ville Talvala                        deviceImpl.setRemoteFailure(e);
2977fcb357811d4dc1f44624e30ad924e9e580d4cbfEino-Ville Talvala
2987fcb357811d4dc1f44624e30ad924e9e580d4cbfEino-Ville Talvala                        if (e.getReason() == CameraAccessException.CAMERA_DISABLED ||
2997fcb357811d4dc1f44624e30ad924e9e580d4cbfEino-Ville Talvala                                e.getReason() == CameraAccessException.CAMERA_DISCONNECTED) {
3007fcb357811d4dc1f44624e30ad924e9e580d4cbfEino-Ville Talvala                            // Per API docs, these failures call onError and throw
301bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala                            throw e.asChecked();
3027fcb357811d4dc1f44624e30ad924e9e580d4cbfEino-Ville Talvala                        }
303feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk                    } else {
3047fcb357811d4dc1f44624e30ad924e9e580d4cbfEino-Ville Talvala                        // Unexpected failure - rethrow
305feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk                        throw e;
306feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk                    }
307bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala                } catch (RemoteException e) {
308bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala                    // Camera service died - act as if it's a CAMERA_DISCONNECTED case
309bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala                    CameraRuntimeException ce = new CameraRuntimeException(
310bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala                        CameraAccessException.CAMERA_DISCONNECTED,
311bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala                        "Camera service is currently unavailable", e);
312bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala                    deviceImpl.setRemoteFailure(ce);
313bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala                    throw ce.asChecked();
314feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk                }
31570725500dcf3b666b43d50563d64705aab58d2d3Igor Murashkin
316fd887436bd111e4d2c7307578a51b5070025b7f2Eino-Ville Talvala                // TODO: factor out callback to be non-nested, then move setter to constructor
317868d904306c6a96d94fa0da03515c51c86eefc63Eino-Ville Talvala                // For now, calling setRemoteDevice will fire initial
318868d904306c6a96d94fa0da03515c51c86eefc63Eino-Ville Talvala                // onOpened/onUnconfigured callbacks.
319cca00c614c24a71dc234c79ad6241efa9f6c7676Eino-Ville Talvala                deviceImpl.setRemoteDevice(cameraUser);
320cca00c614c24a71dc234c79ad6241efa9f6c7676Eino-Ville Talvala                device = deviceImpl;
321e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin            }
322e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin
323e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin        } catch (NumberFormatException e) {
324e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin            throw new IllegalArgumentException("Expected cameraId to be numeric, but it was: "
325e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin                    + cameraId);
326e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin        } catch (CameraRuntimeException e) {
32766ef64514464a1bb9c7931993cc8db3d7539f39aRuben Brunk            throw e.asChecked();
328e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin        }
329cca00c614c24a71dc234c79ad6241efa9f6c7676Eino-Ville Talvala        return device;
330b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala    }
331b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala
332b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala    /**
3335c9eaf6796a4c972710dd5cd23cdfa334fa8ad2eIgor Murashkin     * Open a connection to a camera with the given ID.
3345c9eaf6796a4c972710dd5cd23cdfa334fa8ad2eIgor Murashkin     *
3355c9eaf6796a4c972710dd5cd23cdfa334fa8ad2eIgor Murashkin     * <p>Use {@link #getCameraIdList} to get the list of available camera
3365c9eaf6796a4c972710dd5cd23cdfa334fa8ad2eIgor Murashkin     * devices. Note that even if an id is listed, open may fail if the device
3375c9eaf6796a4c972710dd5cd23cdfa334fa8ad2eIgor Murashkin     * is disconnected between the calls to {@link #getCameraIdList} and
3385c9eaf6796a4c972710dd5cd23cdfa334fa8ad2eIgor Murashkin     * {@link #openCamera}.</p>
3395c9eaf6796a4c972710dd5cd23cdfa334fa8ad2eIgor Murashkin     *
340fd887436bd111e4d2c7307578a51b5070025b7f2Eino-Ville Talvala     * <p>Once the camera is successfully opened, {@link CameraDevice.StateCallback#onOpened} will
341cca00c614c24a71dc234c79ad6241efa9f6c7676Eino-Ville Talvala     * be invoked with the newly opened {@link CameraDevice}. The camera device can then be set up
342cca00c614c24a71dc234c79ad6241efa9f6c7676Eino-Ville Talvala     * for operation by calling {@link CameraDevice#createCaptureSession} and
343cca00c614c24a71dc234c79ad6241efa9f6c7676Eino-Ville Talvala     * {@link CameraDevice#createCaptureRequest}</p>
3445c9eaf6796a4c972710dd5cd23cdfa334fa8ad2eIgor Murashkin     *
345cca00c614c24a71dc234c79ad6241efa9f6c7676Eino-Ville Talvala     * <!--
346cca00c614c24a71dc234c79ad6241efa9f6c7676Eino-Ville Talvala     * <p>Since the camera device will be opened asynchronously, any asynchronous operations done
347cca00c614c24a71dc234c79ad6241efa9f6c7676Eino-Ville Talvala     * on the returned CameraDevice instance will be queued up until the device startup has
348fd887436bd111e4d2c7307578a51b5070025b7f2Eino-Ville Talvala     * completed and the callback's {@link CameraDevice.StateCallback#onOpened onOpened} method is
349cca00c614c24a71dc234c79ad6241efa9f6c7676Eino-Ville Talvala     * called. The pending operations are then processed in order.</p>
350cca00c614c24a71dc234c79ad6241efa9f6c7676Eino-Ville Talvala     * -->
3515c9eaf6796a4c972710dd5cd23cdfa334fa8ad2eIgor Murashkin     * <p>If the camera becomes disconnected during initialization
3525c9eaf6796a4c972710dd5cd23cdfa334fa8ad2eIgor Murashkin     * after this function call returns,
353fd887436bd111e4d2c7307578a51b5070025b7f2Eino-Ville Talvala     * {@link CameraDevice.StateCallback#onDisconnected} with a
3545c9eaf6796a4c972710dd5cd23cdfa334fa8ad2eIgor Murashkin     * {@link CameraDevice} in the disconnected state (and
355fd887436bd111e4d2c7307578a51b5070025b7f2Eino-Ville Talvala     * {@link CameraDevice.StateCallback#onOpened} will be skipped).</p>
3565c9eaf6796a4c972710dd5cd23cdfa334fa8ad2eIgor Murashkin     *
357fd887436bd111e4d2c7307578a51b5070025b7f2Eino-Ville Talvala     * <p>If opening the camera device fails, then the device callback's
358fd887436bd111e4d2c7307578a51b5070025b7f2Eino-Ville Talvala     * {@link CameraDevice.StateCallback#onError onError} method will be called, and subsequent
3597fcb357811d4dc1f44624e30ad924e9e580d4cbfEino-Ville Talvala     * calls on the camera device will throw a {@link CameraAccessException}.</p>
3605c9eaf6796a4c972710dd5cd23cdfa334fa8ad2eIgor Murashkin     *
3615c9eaf6796a4c972710dd5cd23cdfa334fa8ad2eIgor Murashkin     * @param cameraId
3625c9eaf6796a4c972710dd5cd23cdfa334fa8ad2eIgor Murashkin     *             The unique identifier of the camera device to open
363fd887436bd111e4d2c7307578a51b5070025b7f2Eino-Ville Talvala     * @param callback
364fd887436bd111e4d2c7307578a51b5070025b7f2Eino-Ville Talvala     *             The callback which is invoked once the camera is opened
3655c9eaf6796a4c972710dd5cd23cdfa334fa8ad2eIgor Murashkin     * @param handler
366fd887436bd111e4d2c7307578a51b5070025b7f2Eino-Ville Talvala     *             The handler on which the callback should be invoked, or
3675c9eaf6796a4c972710dd5cd23cdfa334fa8ad2eIgor Murashkin     *             {@code null} to use the current thread's {@link android.os.Looper looper}.
3685c9eaf6796a4c972710dd5cd23cdfa334fa8ad2eIgor Murashkin     *
3695c9eaf6796a4c972710dd5cd23cdfa334fa8ad2eIgor Murashkin     * @throws CameraAccessException if the camera is disabled by device policy,
3705c9eaf6796a4c972710dd5cd23cdfa334fa8ad2eIgor Murashkin     * or the camera has become or was disconnected.
3715c9eaf6796a4c972710dd5cd23cdfa334fa8ad2eIgor Murashkin     *
372fd887436bd111e4d2c7307578a51b5070025b7f2Eino-Ville Talvala     * @throws IllegalArgumentException if cameraId or the callback was null,
3735c9eaf6796a4c972710dd5cd23cdfa334fa8ad2eIgor Murashkin     * or the cameraId does not match any currently or previously available
3745c9eaf6796a4c972710dd5cd23cdfa334fa8ad2eIgor Murashkin     * camera device.
3755c9eaf6796a4c972710dd5cd23cdfa334fa8ad2eIgor Murashkin     *
3765c9eaf6796a4c972710dd5cd23cdfa334fa8ad2eIgor Murashkin     * @throws SecurityException if the application does not have permission to
3775c9eaf6796a4c972710dd5cd23cdfa334fa8ad2eIgor Murashkin     * access the camera
3785c9eaf6796a4c972710dd5cd23cdfa334fa8ad2eIgor Murashkin     *
3795c9eaf6796a4c972710dd5cd23cdfa334fa8ad2eIgor Murashkin     * @see #getCameraIdList
3805c9eaf6796a4c972710dd5cd23cdfa334fa8ad2eIgor Murashkin     * @see android.app.admin.DevicePolicyManager#setCameraDisabled
3815c9eaf6796a4c972710dd5cd23cdfa334fa8ad2eIgor Murashkin     */
382fd887436bd111e4d2c7307578a51b5070025b7f2Eino-Ville Talvala    public void openCamera(String cameraId, final CameraDevice.StateCallback callback,
3835c9eaf6796a4c972710dd5cd23cdfa334fa8ad2eIgor Murashkin            Handler handler)
3845c9eaf6796a4c972710dd5cd23cdfa334fa8ad2eIgor Murashkin            throws CameraAccessException {
3855c9eaf6796a4c972710dd5cd23cdfa334fa8ad2eIgor Murashkin
3865c9eaf6796a4c972710dd5cd23cdfa334fa8ad2eIgor Murashkin        if (cameraId == null) {
3875c9eaf6796a4c972710dd5cd23cdfa334fa8ad2eIgor Murashkin            throw new IllegalArgumentException("cameraId was null");
388fd887436bd111e4d2c7307578a51b5070025b7f2Eino-Ville Talvala        } else if (callback == null) {
389fd887436bd111e4d2c7307578a51b5070025b7f2Eino-Ville Talvala            throw new IllegalArgumentException("callback was null");
3905c9eaf6796a4c972710dd5cd23cdfa334fa8ad2eIgor Murashkin        } else if (handler == null) {
3915c9eaf6796a4c972710dd5cd23cdfa334fa8ad2eIgor Murashkin            if (Looper.myLooper() != null) {
3925c9eaf6796a4c972710dd5cd23cdfa334fa8ad2eIgor Murashkin                handler = new Handler();
3935c9eaf6796a4c972710dd5cd23cdfa334fa8ad2eIgor Murashkin            } else {
3945c9eaf6796a4c972710dd5cd23cdfa334fa8ad2eIgor Murashkin                throw new IllegalArgumentException(
3955c9eaf6796a4c972710dd5cd23cdfa334fa8ad2eIgor Murashkin                        "Looper doesn't exist in the calling thread");
3965c9eaf6796a4c972710dd5cd23cdfa334fa8ad2eIgor Murashkin            }
3975c9eaf6796a4c972710dd5cd23cdfa334fa8ad2eIgor Murashkin        }
3985c9eaf6796a4c972710dd5cd23cdfa334fa8ad2eIgor Murashkin
399fd887436bd111e4d2c7307578a51b5070025b7f2Eino-Ville Talvala        openCameraDeviceUserAsync(cameraId, callback, handler);
4005c9eaf6796a4c972710dd5cd23cdfa334fa8ad2eIgor Murashkin    }
4015c9eaf6796a4c972710dd5cd23cdfa334fa8ad2eIgor Murashkin
4025c9eaf6796a4c972710dd5cd23cdfa334fa8ad2eIgor Murashkin    /**
403fd887436bd111e4d2c7307578a51b5070025b7f2Eino-Ville Talvala     * A callback for camera devices becoming available or
404b67a3b36fd569e63c1b8ca6b2701c34c7a3927c1Eino-Ville Talvala     * unavailable to open.
4054af73c2153747d0624ccc75dfa001cb91982957fEino-Ville Talvala     *
4064af73c2153747d0624ccc75dfa001cb91982957fEino-Ville Talvala     * <p>Cameras become available when they are no longer in use, or when a new
407b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala     * removable camera is connected. They become unavailable when some
408b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala     * application or service starts using a camera, or when a removable camera
4094af73c2153747d0624ccc75dfa001cb91982957fEino-Ville Talvala     * is disconnected.</p>
4104af73c2153747d0624ccc75dfa001cb91982957fEino-Ville Talvala     *
411fd887436bd111e4d2c7307578a51b5070025b7f2Eino-Ville Talvala     * <p>Extend this callback and pass an instance of the subclass to
412fd887436bd111e4d2c7307578a51b5070025b7f2Eino-Ville Talvala     * {@link CameraManager#registerAvailabilityCallback} to be notified of such availability
413b67a3b36fd569e63c1b8ca6b2701c34c7a3927c1Eino-Ville Talvala     * changes.</p>
414b67a3b36fd569e63c1b8ca6b2701c34c7a3927c1Eino-Ville Talvala     *
415fd887436bd111e4d2c7307578a51b5070025b7f2Eino-Ville Talvala     * @see registerAvailabilityCallback
416b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala     */
417fd887436bd111e4d2c7307578a51b5070025b7f2Eino-Ville Talvala    public static abstract class AvailabilityCallback {
4184af73c2153747d0624ccc75dfa001cb91982957fEino-Ville Talvala
419b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala        /**
420b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala         * A new camera has become available to use.
421b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala         *
4224af73c2153747d0624ccc75dfa001cb91982957fEino-Ville Talvala         * <p>The default implementation of this method does nothing.</p>
4234af73c2153747d0624ccc75dfa001cb91982957fEino-Ville Talvala         *
424b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala         * @param cameraId The unique identifier of the new camera.
425b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala         */
4264af73c2153747d0624ccc75dfa001cb91982957fEino-Ville Talvala        public void onCameraAvailable(String cameraId) {
4274af73c2153747d0624ccc75dfa001cb91982957fEino-Ville Talvala            // default empty implementation
4284af73c2153747d0624ccc75dfa001cb91982957fEino-Ville Talvala        }
429b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala
430b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala        /**
4314af73c2153747d0624ccc75dfa001cb91982957fEino-Ville Talvala         * A previously-available camera has become unavailable for use.
4324af73c2153747d0624ccc75dfa001cb91982957fEino-Ville Talvala         *
4334af73c2153747d0624ccc75dfa001cb91982957fEino-Ville Talvala         * <p>If an application had an active CameraDevice instance for the
4344af73c2153747d0624ccc75dfa001cb91982957fEino-Ville Talvala         * now-disconnected camera, that application will receive a
435fd887436bd111e4d2c7307578a51b5070025b7f2Eino-Ville Talvala         * {@link CameraDevice.StateCallback#onDisconnected disconnection error}.</p>
4364af73c2153747d0624ccc75dfa001cb91982957fEino-Ville Talvala         *
4374af73c2153747d0624ccc75dfa001cb91982957fEino-Ville Talvala         * <p>The default implementation of this method does nothing.</p>
438b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala         *
439b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala         * @param cameraId The unique identifier of the disconnected camera.
440b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala         */
4414af73c2153747d0624ccc75dfa001cb91982957fEino-Ville Talvala        public void onCameraUnavailable(String cameraId) {
4424af73c2153747d0624ccc75dfa001cb91982957fEino-Ville Talvala            // default empty implementation
4434af73c2153747d0624ccc75dfa001cb91982957fEino-Ville Talvala        }
444b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala    }
445e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin
446bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala    /**
447fd887436bd111e4d2c7307578a51b5070025b7f2Eino-Ville Talvala     * Temporary for migrating to Callback naming
448fd887436bd111e4d2c7307578a51b5070025b7f2Eino-Ville Talvala     * @hide
449fd887436bd111e4d2c7307578a51b5070025b7f2Eino-Ville Talvala     */
450fd887436bd111e4d2c7307578a51b5070025b7f2Eino-Ville Talvala    public static abstract class AvailabilityListener extends AvailabilityCallback {
451fd887436bd111e4d2c7307578a51b5070025b7f2Eino-Ville Talvala    }
452fd887436bd111e4d2c7307578a51b5070025b7f2Eino-Ville Talvala
453fd887436bd111e4d2c7307578a51b5070025b7f2Eino-Ville Talvala    /**
454bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala     * Return or create the list of currently connected camera devices.
455bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala     *
456bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala     * <p>In case of errors connecting to the camera service, will return an empty list.</p>
457bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala     */
458e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin    private ArrayList<String> getOrCreateDeviceIdListLocked() throws CameraAccessException {
459e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin        if (mDeviceIdList == null) {
460e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin            int numCameras = 0;
461bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala            ICameraService cameraService = getCameraServiceLocked();
462bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala            ArrayList<String> deviceIdList = new ArrayList<>();
463bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala
464bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala            // If no camera service, then no devices
465bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala            if (cameraService == null) {
466bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala                return deviceIdList;
467bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala            }
468e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin
469e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin            try {
470bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala                numCameras = cameraService.getNumberOfCameras();
471e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin            } catch(CameraRuntimeException e) {
472e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin                throw e.asChecked();
473e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin            } catch (RemoteException e) {
474bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala                // camera service just died - if no camera service, then no devices
475bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala                return deviceIdList;
476e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin            }
477e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin
47818fe0ae08d49b0fe4b6414a3841bd0fcab5419e8Zhijun He            CameraMetadataNative info = new CameraMetadataNative();
479e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin            for (int i = 0; i < numCameras; ++i) {
480e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin                // Non-removable cameras use integers starting at 0 for their
481e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin                // identifiers
48218fe0ae08d49b0fe4b6414a3841bd0fcab5419e8Zhijun He                boolean isDeviceSupported = false;
48318fe0ae08d49b0fe4b6414a3841bd0fcab5419e8Zhijun He                try {
484bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala                    cameraService.getCameraCharacteristics(i, info);
48518fe0ae08d49b0fe4b6414a3841bd0fcab5419e8Zhijun He                    if (!info.isEmpty()) {
48618fe0ae08d49b0fe4b6414a3841bd0fcab5419e8Zhijun He                        isDeviceSupported = true;
48718fe0ae08d49b0fe4b6414a3841bd0fcab5419e8Zhijun He                    } else {
48818fe0ae08d49b0fe4b6414a3841bd0fcab5419e8Zhijun He                        throw new AssertionError("Expected to get non-empty characteristics");
48918fe0ae08d49b0fe4b6414a3841bd0fcab5419e8Zhijun He                    }
49018fe0ae08d49b0fe4b6414a3841bd0fcab5419e8Zhijun He                } catch(IllegalArgumentException  e) {
49118fe0ae08d49b0fe4b6414a3841bd0fcab5419e8Zhijun He                    // Got a BAD_VALUE from service, meaning that this
49218fe0ae08d49b0fe4b6414a3841bd0fcab5419e8Zhijun He                    // device is not supported.
49318fe0ae08d49b0fe4b6414a3841bd0fcab5419e8Zhijun He                } catch(CameraRuntimeException e) {
494bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala                    // DISCONNECTED means that the HAL reported an low-level error getting the
495bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala                    // device info; skip listing the device.  Other errors,
496bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala                    // propagate exception onward
497bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala                    if (e.getReason() != CameraAccessException.CAMERA_DISCONNECTED) {
498bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala                        throw e.asChecked();
499bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala                    }
50018fe0ae08d49b0fe4b6414a3841bd0fcab5419e8Zhijun He                } catch(RemoteException e) {
501bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala                    // Camera service died - no devices to list
502bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala                    deviceIdList.clear();
503bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala                    return deviceIdList;
50418fe0ae08d49b0fe4b6414a3841bd0fcab5419e8Zhijun He                }
50518fe0ae08d49b0fe4b6414a3841bd0fcab5419e8Zhijun He
50618fe0ae08d49b0fe4b6414a3841bd0fcab5419e8Zhijun He                if (isDeviceSupported) {
507bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala                    deviceIdList.add(String.valueOf(i));
508bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala                } else {
509bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala                    Log.w(TAG, "Error querying camera device " + i + " for listing.");
51018fe0ae08d49b0fe4b6414a3841bd0fcab5419e8Zhijun He                }
511e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin
512bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala            }
513bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala            mDeviceIdList = deviceIdList;
514e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin        }
515e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin        return mDeviceIdList;
516e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin    }
517e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin
518b6a781066e6b0f2578cafefdc61c9ba18c0efc2eRuben Brunk    private void handleRecoverableSetupErrors(CameraRuntimeException e, String msg) {
519b6a781066e6b0f2578cafefdc61c9ba18c0efc2eRuben Brunk        int problem = e.getReason();
520b6a781066e6b0f2578cafefdc61c9ba18c0efc2eRuben Brunk        switch (problem) {
521b6a781066e6b0f2578cafefdc61c9ba18c0efc2eRuben Brunk            case CameraAccessException.CAMERA_DISCONNECTED:
522b6a781066e6b0f2578cafefdc61c9ba18c0efc2eRuben Brunk                String errorMsg = CameraAccessException.getDefaultMessage(problem);
523b6a781066e6b0f2578cafefdc61c9ba18c0efc2eRuben Brunk                Log.w(TAG, msg + ": " + errorMsg);
524b6a781066e6b0f2578cafefdc61c9ba18c0efc2eRuben Brunk                break;
525b6a781066e6b0f2578cafefdc61c9ba18c0efc2eRuben Brunk            default:
526b6a781066e6b0f2578cafefdc61c9ba18c0efc2eRuben Brunk                throw new IllegalStateException(msg, e.asChecked());
527b6a781066e6b0f2578cafefdc61c9ba18c0efc2eRuben Brunk        }
528b6a781066e6b0f2578cafefdc61c9ba18c0efc2eRuben Brunk    }
529b6a781066e6b0f2578cafefdc61c9ba18c0efc2eRuben Brunk
5304961bc88d7bab869a5296789d26fcfa31ad5f644Igor Murashkin    /**
5314961bc88d7bab869a5296789d26fcfa31ad5f644Igor Murashkin     * Queries the camera service if it supports the camera2 api directly, or needs a shim.
5324961bc88d7bab869a5296789d26fcfa31ad5f644Igor Murashkin     *
5334961bc88d7bab869a5296789d26fcfa31ad5f644Igor Murashkin     * @param cameraId a non-{@code null} camera identifier
5344961bc88d7bab869a5296789d26fcfa31ad5f644Igor Murashkin     * @return {@code false} if the legacy shim needs to be used, {@code true} otherwise.
5354961bc88d7bab869a5296789d26fcfa31ad5f644Igor Murashkin     */
536bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala    private boolean supportsCamera2ApiLocked(String cameraId) {
537bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala        return supportsCameraApiLocked(cameraId, API_VERSION_2);
5384961bc88d7bab869a5296789d26fcfa31ad5f644Igor Murashkin    }
5394961bc88d7bab869a5296789d26fcfa31ad5f644Igor Murashkin
5404961bc88d7bab869a5296789d26fcfa31ad5f644Igor Murashkin    /**
5414961bc88d7bab869a5296789d26fcfa31ad5f644Igor Murashkin     * Queries the camera service if it supports a camera api directly, or needs a shim.
5424961bc88d7bab869a5296789d26fcfa31ad5f644Igor Murashkin     *
5434961bc88d7bab869a5296789d26fcfa31ad5f644Igor Murashkin     * @param cameraId a non-{@code null} camera identifier
5444961bc88d7bab869a5296789d26fcfa31ad5f644Igor Murashkin     * @param apiVersion the version, i.e. {@code API_VERSION_1} or {@code API_VERSION_2}
5454961bc88d7bab869a5296789d26fcfa31ad5f644Igor Murashkin     * @return {@code true} if connecting will work for that device version.
5464961bc88d7bab869a5296789d26fcfa31ad5f644Igor Murashkin     */
547bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala    private boolean supportsCameraApiLocked(String cameraId, int apiVersion) {
5484961bc88d7bab869a5296789d26fcfa31ad5f644Igor Murashkin        int id = Integer.parseInt(cameraId);
5494961bc88d7bab869a5296789d26fcfa31ad5f644Igor Murashkin
5504961bc88d7bab869a5296789d26fcfa31ad5f644Igor Murashkin        /*
5514961bc88d7bab869a5296789d26fcfa31ad5f644Igor Murashkin         * Possible return values:
552bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala         * - NO_ERROR => CameraX API is supported
553bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala         * - CAMERA_DEPRECATED_HAL => CameraX API is *not* supported (thrown as an exception)
554bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala         * - Remote exception => If the camera service died
5554961bc88d7bab869a5296789d26fcfa31ad5f644Igor Murashkin         *
5564961bc88d7bab869a5296789d26fcfa31ad5f644Igor Murashkin         * Anything else is an unexpected error we don't want to recover from.
5574961bc88d7bab869a5296789d26fcfa31ad5f644Igor Murashkin         */
5584961bc88d7bab869a5296789d26fcfa31ad5f644Igor Murashkin        try {
559bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala            ICameraService cameraService = getCameraServiceLocked();
560bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala            // If no camera service, no support
561bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala            if (cameraService == null) return false;
562bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala
563bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala            int res = cameraService.supportsCameraApi(id, apiVersion);
5644961bc88d7bab869a5296789d26fcfa31ad5f644Igor Murashkin
565bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala            if (res != CameraServiceBinderDecorator.NO_ERROR) {
5664961bc88d7bab869a5296789d26fcfa31ad5f644Igor Murashkin                throw new AssertionError("Unexpected value " + res);
5674961bc88d7bab869a5296789d26fcfa31ad5f644Igor Murashkin            }
5684961bc88d7bab869a5296789d26fcfa31ad5f644Igor Murashkin            return true;
5694961bc88d7bab869a5296789d26fcfa31ad5f644Igor Murashkin        } catch (CameraRuntimeException e) {
570bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala            if (e.getReason() != CameraAccessException.CAMERA_DEPRECATED_HAL) {
5714961bc88d7bab869a5296789d26fcfa31ad5f644Igor Murashkin                throw e;
5724961bc88d7bab869a5296789d26fcfa31ad5f644Igor Murashkin            }
573bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala            // API level is not supported
5744961bc88d7bab869a5296789d26fcfa31ad5f644Igor Murashkin        } catch (RemoteException e) {
575bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala            // Camera service is now down, no support for any API level
576bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala        }
577bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala        return false;
578bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala    }
579bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala
580bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala    /**
581bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala     * Connect to the camera service if it's available, and set up listeners.
582bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala     *
583bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala     * <p>Sets mCameraService to a valid pointer or null if the connection does not succeed.</p>
584bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala     */
585bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala    private void connectCameraServiceLocked() {
586bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala        mCameraService = null;
587bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala        IBinder cameraServiceBinder = ServiceManager.getService(CAMERA_SERVICE_BINDER_NAME);
588bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala        if (cameraServiceBinder == null) {
589bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala            // Camera service is now down, leave mCameraService as null
590bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala            return;
591bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala        }
592bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala        try {
593bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala            cameraServiceBinder.linkToDeath(new CameraServiceDeathListener(), /*flags*/ 0);
594bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala        } catch (RemoteException e) {
595bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala            // Camera service is now down, leave mCameraService as null
596bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala            return;
597bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala        }
598bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala
599bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala        ICameraService cameraServiceRaw = ICameraService.Stub.asInterface(cameraServiceBinder);
600bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala
601bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala        /**
602bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala         * Wrap the camera service in a decorator which automatically translates return codes
603bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala         * into exceptions.
604bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala         */
605bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala        ICameraService cameraService = CameraServiceBinderDecorator.newInstance(cameraServiceRaw);
606bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala
607bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala        try {
608bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala            CameraServiceBinderDecorator.throwOnError(
609bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala                    CameraMetadataNative.nativeSetupGlobalVendorTagDescriptor());
610bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala        } catch (CameraRuntimeException e) {
611bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala            handleRecoverableSetupErrors(e, "Failed to set up vendor tags");
612bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala        }
613bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala
614bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala        try {
615bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala            cameraService.addListener(mServiceListener);
616bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala            mCameraService = cameraService;
617bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala        } catch(CameraRuntimeException e) {
618bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala            // Unexpected failure
619bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala            throw new IllegalStateException("Failed to register a camera service listener",
620bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala                    e.asChecked());
621bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala        } catch (RemoteException e) {
622bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala            // Camera service is now down, leave mCameraService as null
623bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala        }
624bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala    }
625bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala
626bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala    /**
627bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala     * Return a best-effort ICameraService.
628bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala     *
629bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala     * <p>This will be null if the camera service
630bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala     * is not currently available. If the camera service has died since the last
631bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala     * use of the camera service, will try to reconnect to the service.</p>
632bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala     */
633bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala    private ICameraService getCameraServiceLocked() {
634bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala        if (mCameraService == null) {
635bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala            Log.i(TAG, "getCameraServiceLocked: Reconnecting to camera service");
636bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala            connectCameraServiceLocked();
637bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala            if (mCameraService == null) {
638bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala                Log.e(TAG, "Camera service is unavailable");
639bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala            }
640bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala        }
641bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala        return mCameraService;
642bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala    }
643bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala
644bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala    /**
645bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala     * Listener for camera service death.
646bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala     *
647bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala     * <p>The camera service isn't supposed to die under any normal circumstances, but can be turned
648bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala     * off during debug, or crash due to bugs.  So detect that and null out the interface object, so
649bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala     * that the next calls to the manager can try to reconnect.</p>
650bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala     */
651bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala    private class CameraServiceDeathListener implements IBinder.DeathRecipient {
652bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala        public void binderDied() {
653bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala            synchronized(mLock) {
654bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala                mCameraService = null;
655bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala                // Tell listeners that the cameras are _available_, because any existing clients
656bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala                // will have gotten disconnected. This is optimistic under the assumption that the
657bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala                // service will be back shortly.
658bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala                //
659bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala                // Without this, a camera service crash while a camera is open will never signal to
660bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala                // listeners that previously in-use cameras are now available.
661bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala                for (String cameraId : mDeviceIdList) {
662bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala                    mServiceListener.onStatusChangedLocked(CameraServiceListener.STATUS_PRESENT,
663bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala                            cameraId);
664bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala                }
665bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala            }
6664961bc88d7bab869a5296789d26fcfa31ad5f644Igor Murashkin        }
6674961bc88d7bab869a5296789d26fcfa31ad5f644Igor Murashkin    }
6684961bc88d7bab869a5296789d26fcfa31ad5f644Igor Murashkin
669e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin    // TODO: this class needs unit tests
670e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin    // TODO: extract class into top level
671ecb323e3ce94f62411b6799f9a0aa42b052de30dZhijun He    private class CameraServiceListener extends ICameraServiceListener.Stub {
672e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin
673e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin        // Keep up-to-date with ICameraServiceListener.h
674e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin
675e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin        // Device physically unplugged
676e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin        public static final int STATUS_NOT_PRESENT = 0;
677e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin        // Device physically has been plugged in
678e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin        // and the camera can be used exclusively
679e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin        public static final int STATUS_PRESENT = 1;
680e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin        // Device physically has been plugged in
681e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin        // but it will not be connect-able until enumeration is complete
682e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin        public static final int STATUS_ENUMERATING = 2;
683e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin        // Camera is in use by another app and cannot be used exclusively
684e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin        public static final int STATUS_NOT_AVAILABLE = 0x80000000;
685e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin
686e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin        // Camera ID -> Status map
6874af73c2153747d0624ccc75dfa001cb91982957fEino-Ville Talvala        private final ArrayMap<String, Integer> mDeviceStatus = new ArrayMap<String, Integer>();
688e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin
689e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin        private static final String TAG = "CameraServiceListener";
690e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin
691e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin        @Override
692e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin        public IBinder asBinder() {
693e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin            return this;
694e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin        }
695e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin
696e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin        private boolean isAvailable(int status) {
697e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin            switch (status) {
698e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin                case STATUS_PRESENT:
699e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin                    return true;
700e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin                default:
701e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin                    return false;
702e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin            }
703e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin        }
704e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin
705e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin        private boolean validStatus(int status) {
706e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin            switch (status) {
707e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin                case STATUS_NOT_PRESENT:
708e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin                case STATUS_PRESENT:
709e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin                case STATUS_ENUMERATING:
710e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin                case STATUS_NOT_AVAILABLE:
711e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin                    return true;
712e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin                default:
713e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin                    return false;
714e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin            }
715e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin        }
716e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin
717fd887436bd111e4d2c7307578a51b5070025b7f2Eino-Ville Talvala        private void postSingleUpdate(final AvailabilityCallback callback, final Handler handler,
718bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala                final String id, final int status) {
719bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala            if (isAvailable(status)) {
720bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala                handler.post(
721bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala                    new Runnable() {
722bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala                        @Override
723bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala                        public void run() {
724fd887436bd111e4d2c7307578a51b5070025b7f2Eino-Ville Talvala                            callback.onCameraAvailable(id);
725bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala                        }
726bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala                    });
727bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala            } else {
728bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala                handler.post(
729bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala                    new Runnable() {
730bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala                        @Override
731bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala                        public void run() {
732fd887436bd111e4d2c7307578a51b5070025b7f2Eino-Ville Talvala                            callback.onCameraUnavailable(id);
733bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala                        }
734bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala                    });
735bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala            }
736bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala        }
737bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala
738bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala        /**
739bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala         * Send the state of all known cameras to the provided listener, to initialize
740bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala         * the listener's knowledge of camera state.
741bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala         */
742fd887436bd111e4d2c7307578a51b5070025b7f2Eino-Ville Talvala        public void updateCallbackLocked(AvailabilityCallback callback, Handler handler) {
743bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala            for (int i = 0; i < mDeviceStatus.size(); i++) {
744bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala                String id = mDeviceStatus.keyAt(i);
745bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala                Integer status = mDeviceStatus.valueAt(i);
746fd887436bd111e4d2c7307578a51b5070025b7f2Eino-Ville Talvala                postSingleUpdate(callback, handler, id, status);
747bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala            }
748bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala        }
749bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala
750e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin        @Override
751e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin        public void onStatusChanged(int status, int cameraId) throws RemoteException {
75270725500dcf3b666b43d50563d64705aab58d2d3Igor Murashkin            synchronized(CameraManager.this.mLock) {
753bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala                onStatusChangedLocked(status, String.valueOf(cameraId));
754bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala            }
755bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala        }
756e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin
757bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala        public void onStatusChangedLocked(int status, String id) {
758bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala            if (DEBUG) {
759e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin                Log.v(TAG,
760bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala                        String.format("Camera id %s has status changed to 0x%x", id, status));
761bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala            }
762e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin
763bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala            if (!validStatus(status)) {
764bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala                Log.e(TAG, String.format("Ignoring invalid device %s status 0x%x", id,
765bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala                                status));
766bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala                return;
767bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala            }
768e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin
769bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala            Integer oldStatus = mDeviceStatus.put(id, status);
770e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin
771bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala            if (oldStatus != null && oldStatus == status) {
772bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala                if (DEBUG) {
773e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin                    Log.v(TAG, String.format(
774bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala                        "Device status changed to 0x%x, which is what it already was",
775bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala                        status));
776e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin                }
777bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala                return;
778bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala            }
779e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin
780bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala            // TODO: consider abstracting out this state minimization + transition
781bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala            // into a separate
782bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala            // more easily testable class
783bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala            // i.e. (new State()).addState(STATE_AVAILABLE)
784bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala            //                   .addState(STATE_NOT_AVAILABLE)
785bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala            //                   .addTransition(STATUS_PRESENT, STATE_AVAILABLE),
786bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala            //                   .addTransition(STATUS_NOT_PRESENT, STATE_NOT_AVAILABLE)
787bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala            //                   .addTransition(STATUS_ENUMERATING, STATE_NOT_AVAILABLE);
788bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala            //                   .addTransition(STATUS_NOT_AVAILABLE, STATE_NOT_AVAILABLE);
789bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala
790bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala            // Translate all the statuses to either 'available' or 'not available'
791bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala            //  available -> available         => no new update
792bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala            //  not available -> not available => no new update
793bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala            if (oldStatus != null && isAvailable(status) == isAvailable(oldStatus)) {
794bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala                if (DEBUG) {
795e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin                    Log.v(TAG,
796e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin                            String.format(
797bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala                                "Device status was previously available (%d), " +
798bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala                                " and is now again available (%d)" +
799bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala                                "so no new client visible update will be sent",
800bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala                                isAvailable(status), isAvailable(status)));
801e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin                }
802bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala                return;
803bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala            }
804bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala
805fd887436bd111e4d2c7307578a51b5070025b7f2Eino-Ville Talvala            final int callbackCount = mCallbackMap.size();
806fd887436bd111e4d2c7307578a51b5070025b7f2Eino-Ville Talvala            for (int i = 0; i < callbackCount; i++) {
807fd887436bd111e4d2c7307578a51b5070025b7f2Eino-Ville Talvala                Handler handler = mCallbackMap.valueAt(i);
808fd887436bd111e4d2c7307578a51b5070025b7f2Eino-Ville Talvala                final AvailabilityCallback callback = mCallbackMap.keyAt(i);
809bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala
810fd887436bd111e4d2c7307578a51b5070025b7f2Eino-Ville Talvala                postSingleUpdate(callback, handler, id, status);
811bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala            }
812bd9b106806f9792be210cc2d9848d8b1f4b9664dEino-Ville Talvala        } // onStatusChangedLocked
813e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin
814e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin    } // CameraServiceListener
815e363fbb2647aeb5ef4c87160d84c6b9ae8d45598Igor Murashkin} // CameraManager
816