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