1/*
2 * Copyright (C) 2013 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.mediaframeworktest.integration;
18
19import android.hardware.CameraInfo;
20import android.hardware.ICamera;
21import android.hardware.ICameraClient;
22import android.hardware.ICameraService;
23import android.hardware.ICameraServiceListener;
24import android.hardware.camera2.ICameraDeviceCallbacks;
25import android.hardware.camera2.ICameraDeviceUser;
26import android.hardware.camera2.impl.CameraMetadataNative;
27import android.hardware.camera2.impl.CaptureResultExtras;
28import android.hardware.camera2.impl.PhysicalCaptureResultInfo;
29import android.os.Binder;
30import android.os.IBinder;
31import android.os.RemoteException;
32import android.os.ServiceSpecificException;
33import android.test.AndroidTestCase;
34import android.test.suitebuilder.annotation.SmallTest;
35import android.util.Log;
36
37/**
38 * <p>
39 * Junit / Instrumentation test case for the camera2 api
40 * </p>
41 * <p>
42 * To run only tests in this class:
43 * </p>
44 *
45 * <pre>
46 * adb shell am instrument \
47 *   -e class com.android.mediaframeworktest.integration.CameraBinderTest \
48 *   -w com.android.mediaframeworktest/.MediaFrameworkIntegrationTestRunner
49 * </pre>
50 */
51public class CameraBinderTest extends AndroidTestCase {
52    private static final int MAX_PARAMETERS_LENGTH = 100;
53
54    static String TAG = "CameraBinderTest";
55
56    // From ICameraService.h
57    private static final int API_VERSION_1 = 1;
58    private static final int API_VERSION_2 = 2;
59
60    private static final int CAMERA_TYPE_BACKWARD_COMPATIBLE = 0;
61    private static final int CAMERA_TYPE_ALL = 1;
62
63    protected CameraBinderTestUtils mUtils;
64
65    public CameraBinderTest() {
66    }
67
68    @Override
69    protected void setUp() throws Exception {
70        super.setUp();
71
72        mUtils = new CameraBinderTestUtils(getContext());
73    }
74
75    @SmallTest
76    public void testNumberOfCameras() throws Exception {
77
78        int numCameras = mUtils.getCameraService().getNumberOfCameras(CAMERA_TYPE_ALL);
79        assertTrue("At least this many cameras: " + mUtils.getGuessedNumCameras(),
80                numCameras >= mUtils.getGuessedNumCameras());
81        Log.v(TAG, "Number of cameras " + numCameras);
82    }
83
84    @SmallTest
85    public void testCameraInfo() throws Exception {
86        for (int cameraId = 0; cameraId < mUtils.getGuessedNumCameras(); ++cameraId) {
87
88            CameraInfo info = mUtils.getCameraService().getCameraInfo(cameraId);
89            assertTrue("Facing was not set for camera " + cameraId, info.info.facing != -1);
90            assertTrue("Orientation was not set for camera " + cameraId,
91                    info.info.orientation != -1);
92
93            Log.v(TAG, "Camera " + cameraId + " info: facing " + info.info.facing
94                    + ", orientation " + info.info.orientation);
95        }
96    }
97
98    @SmallTest
99    public void testGetLegacyParameters() throws Exception {
100        for (int cameraId = 0; cameraId < mUtils.getGuessedNumCameras(); ++cameraId) {
101
102            String parameters = mUtils.getCameraService().getLegacyParameters(cameraId);
103            assertNotNull(parameters);
104            assertTrue("Parameters should have at least one character in it",
105                    parameters.length() > 0);
106
107            int end = parameters.length();
108            if (end > MAX_PARAMETERS_LENGTH) {
109                end = MAX_PARAMETERS_LENGTH;
110            }
111
112            Log.v(TAG, "Camera " + cameraId + " parameters: " + parameters.substring(0, end));
113        }
114    }
115
116    /** The camera2 api is only supported on HAL3.2+ devices */
117    @SmallTest
118    public void testSupportsCamera2Api() throws Exception {
119        for (int cameraId = 0; cameraId < mUtils.getGuessedNumCameras(); ++cameraId) {
120            boolean supports = mUtils.getCameraService().supportsCameraApi(
121                String.valueOf(cameraId), API_VERSION_2);
122
123            Log.v(TAG, "Camera " + cameraId + " supports api2: " + supports);
124        }
125    }
126
127    /** The camera1 api is supported on *all* devices regardless of HAL version */
128    @SmallTest
129    public void testSupportsCamera1Api() throws Exception {
130        for (int cameraId = 0; cameraId < mUtils.getGuessedNumCameras(); ++cameraId) {
131
132            boolean supports = mUtils.getCameraService().supportsCameraApi(
133                String.valueOf(cameraId), API_VERSION_1);
134            assertTrue(
135                    "Camera service returned false when queried if it supports camera1 api " +
136                    " for camera ID " + cameraId, supports);
137        }
138    }
139
140    static abstract class DummyBase extends Binder implements android.os.IInterface {
141        @Override
142        public IBinder asBinder() {
143            return this;
144        }
145    }
146
147    static class DummyCameraClient extends DummyBase implements ICameraClient {
148    }
149
150    @SmallTest
151    public void testConnect() throws Exception {
152        for (int cameraId = 0; cameraId < mUtils.getGuessedNumCameras(); ++cameraId) {
153
154            ICameraClient dummyCallbacks = new DummyCameraClient();
155
156            String clientPackageName = getContext().getPackageName();
157
158            ICamera cameraUser = mUtils.getCameraService()
159                    .connect(dummyCallbacks, cameraId, clientPackageName,
160                            ICameraService.USE_CALLING_UID,
161                            ICameraService.USE_CALLING_PID);
162            assertNotNull(String.format("Camera %s was null", cameraId), cameraUser);
163
164            Log.v(TAG, String.format("Camera %s connected", cameraId));
165
166            cameraUser.disconnect();
167        }
168    }
169
170    @SmallTest
171    public void testConnectLegacy() throws Exception {
172        final int CAMERA_HAL_API_VERSION_1_0 = 0x100;
173        for (int cameraId = 0; cameraId < mUtils.getGuessedNumCameras(); ++cameraId) {
174            ICamera cameraUser = null;
175            ICameraClient dummyCallbacks = new DummyCameraClient();
176
177            String clientPackageName = getContext().getPackageName();
178
179            try {
180                cameraUser = mUtils.getCameraService()
181                        .connectLegacy(dummyCallbacks, cameraId, CAMERA_HAL_API_VERSION_1_0,
182                                clientPackageName,
183                                ICameraService.USE_CALLING_UID);
184                assertNotNull(String.format("Camera %s was null", cameraId), cameraUser);
185
186                Log.v(TAG, String.format("Camera %s connected as HAL1 legacy device", cameraId));
187            } catch (RuntimeException e) {
188                // Not all camera device support openLegacy.
189                Log.i(TAG, "Unable to open camera as HAL1 legacy camera device " + e);
190            } finally {
191                if (cameraUser != null) {
192                    cameraUser.disconnect();
193                }
194            }
195        }
196    }
197
198    static class DummyCameraDeviceCallbacks extends ICameraDeviceCallbacks.Stub {
199
200        /*
201         * (non-Javadoc)
202         * @see
203         * android.hardware.camera2.ICameraDeviceCallbacks#onCameraError(int,
204         * android.hardware.camera2.CaptureResultExtras)
205         */
206        @Override
207        public void onDeviceError(int errorCode, CaptureResultExtras resultExtras)
208                throws RemoteException {
209            // TODO Auto-generated method stub
210
211        }
212
213        /*
214         * (non-Javadoc)
215         * @see
216         * android.hardware.camera2.ICameraDeviceCallbacks#onCaptureStarted(
217         * android.hardware.camera2.CaptureResultExtras, long)
218         */
219        @Override
220        public void onCaptureStarted(CaptureResultExtras resultExtras, long timestamp)
221                throws RemoteException {
222            // TODO Auto-generated method stub
223
224        }
225
226        /*
227         * (non-Javadoc)
228         * @see
229         * android.hardware.camera2.ICameraDeviceCallbacks#onResultReceived(
230         * android.hardware.camera2.impl.CameraMetadataNative,
231         * android.hardware.camera2.CaptureResultExtras)
232         */
233        @Override
234        public void onResultReceived(CameraMetadataNative result, CaptureResultExtras resultExtras,
235                PhysicalCaptureResultInfo physicalResults[]) throws RemoteException {
236            // TODO Auto-generated method stub
237
238        }
239
240        /*
241         * (non-Javadoc)
242         * @see android.hardware.camera2.ICameraDeviceCallbacks#onCameraIdle()
243         */
244        @Override
245        public void onDeviceIdle() throws RemoteException {
246            // TODO Auto-generated method stub
247
248        }
249
250        /*
251         * (non-Javadoc)
252         * @see android.hardware.camera2.ICameraDeviceCallbacks#onPrepared()
253         */
254        @Override
255        public void onPrepared(int streamId) throws RemoteException {
256            // TODO Auto-generated method stub
257
258        }
259
260        /*
261         * (non-Javadoc)
262         * @see android.hardware.camera2.ICameraDeviceCallbacks#onRequestQueueEmpty()
263         */
264        @Override
265        public void onRequestQueueEmpty() throws RemoteException {
266            // TODO Auto-generated method stub
267
268        }
269
270        /*
271         * (non-Javadoc)
272         * @see android.hardware.camera2.ICameraDeviceCallbacks#onRepeatingRequestError()
273         */
274        @Override
275        public void onRepeatingRequestError(long lastFrameNumber, int repeatingRequestId) {
276            // TODO Auto-generated method stub
277        }
278    }
279
280    @SmallTest
281    public void testConnectDevice() throws Exception {
282        for (int cameraId = 0; cameraId < mUtils.getGuessedNumCameras(); ++cameraId) {
283
284            ICameraDeviceCallbacks dummyCallbacks = new DummyCameraDeviceCallbacks();
285
286            String clientPackageName = getContext().getPackageName();
287
288            ICameraDeviceUser cameraUser =
289                    mUtils.getCameraService().connectDevice(
290                        dummyCallbacks, String.valueOf(cameraId),
291                        clientPackageName,
292                        ICameraService.USE_CALLING_UID);
293            assertNotNull(String.format("Camera %s was null", cameraId), cameraUser);
294
295            Log.v(TAG, String.format("Camera %s connected", cameraId));
296
297            cameraUser.disconnect();
298        }
299    }
300
301    static class DummyCameraServiceListener extends ICameraServiceListener.Stub {
302        @Override
303        public void onStatusChanged(int status, String cameraId)
304                throws RemoteException {
305            Log.v(TAG, String.format("Camera %s has status changed to 0x%x", cameraId, status));
306        }
307        public void onTorchStatusChanged(int status, String cameraId)
308                throws RemoteException {
309            Log.v(TAG, String.format("Camera %s has torch status changed to 0x%x",
310                    cameraId, status));
311        }
312    }
313
314    /**
315     * <pre>
316     * adb shell am instrument \
317     *   -e class 'com.android.mediaframeworktest.integration.CameraBinderTest#testAddRemoveListeners' \
318     *   -w com.android.mediaframeworktest/.MediaFrameworkIntegrationTestRunner
319     * </pre>
320     */
321    @SmallTest
322    public void testAddRemoveListeners() throws Exception {
323        for (int cameraId = 0; cameraId < mUtils.getGuessedNumCameras(); ++cameraId) {
324
325            ICameraServiceListener listener = new DummyCameraServiceListener();
326
327            try {
328                mUtils.getCameraService().removeListener(listener);
329                fail("Listener was removed before added");
330            } catch (ServiceSpecificException e) {
331                assertEquals("Listener was removed before added",
332                        e.errorCode, ICameraService.ERROR_ILLEGAL_ARGUMENT);
333            }
334
335            mUtils.getCameraService().addListener(listener);
336
337            try {
338                mUtils.getCameraService().addListener(listener);
339                fail("Listener was wrongly added again");
340            } catch (ServiceSpecificException e) {
341                assertEquals("Listener was wrongly added again",
342                        e.errorCode, ICameraService.ERROR_ALREADY_EXISTS);
343            }
344
345            mUtils.getCameraService().removeListener(listener);
346
347            try {
348                mUtils.getCameraService().removeListener(listener);
349                fail("Listener was wrongly removed twice");
350            } catch (ServiceSpecificException e) {
351                assertEquals("Listener was wrongly removed twice",
352                        e.errorCode, ICameraService.ERROR_ILLEGAL_ARGUMENT);
353            }
354        }
355    }
356}
357