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.functional.camera;
18
19import android.hardware.Camera;
20import android.hardware.Camera.PictureCallback;
21import android.hardware.Camera.ShutterCallback;
22import android.os.Environment;
23import android.os.Handler;
24import android.os.Looper;
25import android.test.ActivityInstrumentationTestCase2;
26import android.test.suitebuilder.annotation.LargeTest;
27import android.util.FloatMath;
28import android.util.Log;
29import android.view.SurfaceHolder;
30
31import java.util.concurrent.Semaphore;
32import java.util.concurrent.TimeUnit;
33import java.util.List;
34
35import com.android.mediaframeworktest.MediaFrameworkTest;
36import com.android.mediaframeworktest.CameraStressTestRunner;
37import com.android.mediaframeworktest.CameraTestHelper;
38import junit.framework.Assert;
39
40/**
41 * Junit / Instrumentation test case for camera API pairwise testing
42 * Settings tested against: flash mode, exposure compensation, white balance,
43 *  scene mode, picture size, and geotagging
44 *
45 * adb shell am instrument
46 *  - e class com.android.mediaframeworktest.stress.CameraPairwiseTest
47 *  - w com.android.mediaframeworktest/.CameraStressTestRunner
48 */
49public class CameraPairwiseTest extends ActivityInstrumentationTestCase2<MediaFrameworkTest> {
50    private CameraTestHelper mCameraTestHelper;
51    private Handler mHandler;
52    private Thread mLooperThread;
53    private String TAG = "CameraPairwiseTest";
54
55    private static final long WAIT_TIMEOUT = 10 * 1000; // 10 seconds
56
57    // coordinates of the Getty Museuem in Los Angeles
58    private static final double MOCK_LATITUDE = 34.076621;
59    private static final double MOCK_LONGITUDE = -118.473215;
60
61    // camera setting enums
62    public enum Flash { ON, OFF, AUTO };
63    public enum Exposure { MIN, MAX, NONE };
64    public enum WhiteBalance { DAYLIGHT, FLUORESCENT, CLOUDY, INCANDESCENT, AUTO };
65    public enum SceneMode { SUNSET, ACTION, PARTY, NIGHT, AUTO };
66    public enum PictureSize { SMALL, MEDIUM, LARGE };
67    public enum Geotagging { ON, OFF };
68
69    public CameraPairwiseTest() {
70        super("com.android.mediaframeworktest", MediaFrameworkTest.class);
71    }
72
73    protected void setUp() throws Exception {
74        final Semaphore sem = new Semaphore(0);
75        mLooperThread = new Thread() {
76            @Override
77            public void run() {
78                Log.v(TAG, "starting looper");
79                Looper.prepare();
80                mHandler = new Handler();
81                sem.release();
82                Looper.loop();
83                Log.v(TAG, "quit looper");
84            }
85        };
86        mLooperThread.start();
87        if (!sem.tryAcquire(WAIT_TIMEOUT, TimeUnit.MILLISECONDS)) {
88            fail("Failed to start the looper.");
89        }
90        getActivity();
91        super.setUp();
92
93        mCameraTestHelper = new CameraTestHelper();
94    }
95
96    @Override
97    protected void tearDown() throws Exception {
98        if (mHandler != null) {
99            mHandler.getLooper().quit();
100            mHandler = null;
101        }
102        if (mLooperThread != null) {
103            mLooperThread.join(WAIT_TIMEOUT);
104            if (mLooperThread.isAlive()) {
105                fail("Failed to stop the looper.");
106            }
107            mLooperThread = null;
108        }
109        super.tearDown();
110    }
111
112    private void runOnLooper(final Runnable command) throws InterruptedException {
113        final Semaphore sem = new Semaphore(0);
114        mHandler.post(new Runnable() {
115            @Override
116            public void run() {
117                try {
118                    command.run();
119                } finally {
120                    sem.release();
121                }
122            }
123        });
124        if (!sem.tryAcquire(WAIT_TIMEOUT, TimeUnit.MILLISECONDS)) {
125            fail("Failed to run the command on the looper.");
126        }
127    }
128
129    /**
130     * Flash: Auto / Exposure: None / WB: Daylight
131     * Scene: Sunset / Pic: Medium / Geo: off
132     */
133    @LargeTest
134    public void testCameraPairwiseScenario01() throws Exception {
135        genericPairwiseTestCase(Flash.AUTO, Exposure.NONE, WhiteBalance.DAYLIGHT, SceneMode.SUNSET,
136                PictureSize.MEDIUM, Geotagging.OFF);
137    }
138
139    /**
140     * Flash: On / Exposure: Min / WB: Fluorescent
141     * Scene: Auto / Pic: Large / Geo: on
142     */
143    @LargeTest
144    public void testCameraPairwiseScenario02() throws Exception {
145        genericPairwiseTestCase(Flash.ON, Exposure.MIN, WhiteBalance.FLUORESCENT, SceneMode.AUTO,
146                PictureSize.LARGE, Geotagging.ON);
147    }
148
149    /**
150     * Flash: Off / Exposure: Max / WB: Auto
151     * Scene: Night / Pic: Small / Geo: on
152     */
153    @LargeTest
154    public void testCameraPairwiseScenario03() throws Exception {
155        genericPairwiseTestCase(Flash.OFF, Exposure.MAX, WhiteBalance.AUTO, SceneMode.NIGHT,
156                PictureSize.SMALL, Geotagging.ON);
157    }
158
159    /**
160     * Flash: Off / Exposure: Max / WB: Cloudy
161     * Scene: Auto / Pic: Med / Geo: off
162     */
163    @LargeTest
164    public void testCameraPairwiseScenario04() throws Exception {
165        genericPairwiseTestCase(Flash.OFF, Exposure.MAX, WhiteBalance.CLOUDY, SceneMode.AUTO,
166                PictureSize.MEDIUM, Geotagging.OFF);
167    }
168
169    /**
170     * Flash: Auto / Exposure: Max / WB: Incandescent
171     * Scene: Auto / Pic: Large / Geo: off
172     */
173    @LargeTest
174    public void testCameraPairwiseScenario05() throws Exception {
175        genericPairwiseTestCase(Flash.AUTO, Exposure.MAX, WhiteBalance.INCANDESCENT,
176                SceneMode.AUTO, PictureSize.LARGE, Geotagging.OFF);
177    }
178
179    /**
180     * Flash: On / Exposure: None / WB: Cloudy
181     * Scene: Auto / Pic: Small / Geo: on
182     */
183    @LargeTest
184    public void testCameraPairwiseScenario06() throws Exception {
185        genericPairwiseTestCase(Flash.ON, Exposure.NONE, WhiteBalance.CLOUDY, SceneMode.AUTO,
186                PictureSize.SMALL, Geotagging.ON);
187    }
188
189    /**
190     * Flash: Auto / Exposure: Min / WB: Auto
191     * Scene: Action / Pic: Small / Geo: on
192     */
193    @LargeTest
194    public void testCameraPairwiseScenario07() throws Exception {
195        genericPairwiseTestCase(Flash.AUTO, Exposure.MIN, WhiteBalance.AUTO, SceneMode.ACTION,
196                PictureSize.SMALL, Geotagging.ON);
197    }
198
199    /**
200     * Flash: On / Exposure: Min / WB: Auto
201     * Scene: Action / Pic: Medium / Geo: off
202     */
203    @LargeTest
204    public void testCameraPairwiseScenario08() throws Exception {
205        genericPairwiseTestCase(Flash.ON, Exposure.MIN, WhiteBalance.AUTO, SceneMode.ACTION,
206                PictureSize.MEDIUM, Geotagging.OFF);
207    }
208
209    /**
210     * Flash: Off / Exposure: Min / WB: Auto
211     * Scene: Night / Pic: Large / Geo: off
212     */
213    @LargeTest
214    public void testCameraPairwiseScenario09() throws Exception {
215        genericPairwiseTestCase(Flash.OFF, Exposure.MIN, WhiteBalance.AUTO, SceneMode.NIGHT,
216                PictureSize.LARGE, Geotagging.OFF);
217    }
218
219    /**
220     * Flash: Off / Exposure: Min / WB: Daylight
221     * Scene: Sunset / Pic: Small / Geo: off
222     */
223    @LargeTest
224    public void testCameraPairwiseScenario10() throws Exception {
225        genericPairwiseTestCase(Flash.OFF, Exposure.MIN, WhiteBalance.DAYLIGHT, SceneMode.SUNSET,
226                PictureSize.SMALL, Geotagging.OFF);
227    }
228
229    /**
230     * Flash: On / Exposure: Max / WB: Daylight
231     * Scene: Sunset / Pic: Large / Geo: on
232     */
233    @LargeTest
234    public void testCameraPairwiseScenario11() throws Exception {
235        genericPairwiseTestCase(Flash.ON, Exposure.MAX, WhiteBalance.DAYLIGHT, SceneMode.SUNSET,
236                PictureSize.LARGE, Geotagging.ON);
237    }
238
239    /**
240     * Flash: Auto / Exposure: Min / WB: Cloudy
241     * Scene: Auto / Pic: Large / Geo: off
242     */
243    @LargeTest
244    public void testCameraPairwiseScenario12() throws Exception {
245        genericPairwiseTestCase(Flash.AUTO, Exposure.MIN, WhiteBalance.CLOUDY, SceneMode.AUTO,
246                PictureSize.LARGE, Geotagging.OFF);
247    }
248
249    /**
250     * Flash: Off / Exposure: None / WB: Auto
251     * Scene: Party / Pic: Medium / Geo: on
252     */
253    @LargeTest
254    public void testCameraPairwiseScenario13() throws Exception {
255        genericPairwiseTestCase(Flash.OFF, Exposure.NONE, WhiteBalance.AUTO, SceneMode.PARTY,
256                PictureSize.MEDIUM, Geotagging.ON);
257    }
258
259    /**
260     * Flash: Auto / Exposure: None / WB: Auto
261     * Scene: Night / Pic: Small / Geo: off
262     */
263    @LargeTest
264    public void testCameraPairwiseScenario14() throws Exception {
265        genericPairwiseTestCase(Flash.AUTO, Exposure.NONE, WhiteBalance.AUTO, SceneMode.NIGHT,
266                PictureSize.SMALL, Geotagging.OFF);
267    }
268
269    /**
270     * Flash: On / Exposure: None / WB: Incandescent
271     * Scene: Auto / Pic: Medium / Geo: on
272     */
273    @LargeTest
274    public void testCameraPairwiseScenario15() throws Exception {
275        genericPairwiseTestCase(Flash.ON, Exposure.NONE, WhiteBalance.INCANDESCENT, SceneMode.AUTO,
276                PictureSize.MEDIUM, Geotagging.ON);
277    }
278
279    /**
280     * Flash: Auto / Exposure: Min / WB: Auto
281     * Scene: Party / Pic: Small / Geo: off
282     */
283    @LargeTest
284    public void testCameraPairwiseScenario16() throws Exception {
285        genericPairwiseTestCase(Flash.AUTO, Exposure.MIN, WhiteBalance.AUTO, SceneMode.PARTY,
286                PictureSize.SMALL, Geotagging.OFF);
287    }
288
289    /**
290     * Flash: Off / Exposure: Min / WB: Incandescent
291     * Scene: Auto / Pic: Small / Geo: off
292     */
293    @LargeTest
294    public void testCameraPairwiseScenario17() throws Exception {
295        genericPairwiseTestCase(Flash.OFF, Exposure.MIN, WhiteBalance.INCANDESCENT, SceneMode.AUTO,
296                PictureSize.SMALL, Geotagging.OFF);
297    }
298
299    /**
300     * Flash: On / Exposure: None / WB: Auto
301     * Scene: Party / Pic: Large / Geo: off
302     */
303    @LargeTest
304    public void testCameraPairwiseScenario18() throws Exception {
305        genericPairwiseTestCase(Flash.ON, Exposure.NONE, WhiteBalance.AUTO, SceneMode.PARTY,
306                PictureSize.LARGE, Geotagging.OFF);
307    }
308
309    /**
310     * Flash Off / Exposure: None / WB: Auto
311     * Scene: Action / Pic: Large / Geo: off
312     */
313    @LargeTest
314    public void testCameraPairwiseScenario19() throws Exception {
315        genericPairwiseTestCase(Flash.OFF, Exposure.NONE, WhiteBalance.AUTO, SceneMode.ACTION,
316                PictureSize.LARGE, Geotagging.OFF);
317    }
318
319    /**
320     * Flash: Off / Exposure: Max / WB: Fluorescent
321     * Scene: Auto / Pic: Medium / Geo: Off
322     */
323    @LargeTest
324    public void testCameraPairwiseScenario20() throws Exception {
325        genericPairwiseTestCase(Flash.OFF, Exposure.MAX, WhiteBalance.FLUORESCENT, SceneMode.AUTO,
326                PictureSize.MEDIUM, Geotagging.OFF);
327    }
328
329    /**
330     * Flash: Off / Exposure: Min / WB: Auto
331     * Scene: Auto / Pic: Medium / Geo: off
332     */
333    public void testCameraPairwiseScenario21() throws Exception {
334        genericPairwiseTestCase(Flash.OFF, Exposure.MIN, WhiteBalance.AUTO, SceneMode.AUTO,
335                PictureSize.MEDIUM, Geotagging.OFF);
336    }
337
338    /**
339     * Flash: On / Exposure: Max / WB: Auto
340     * Scene: Action / Pic: Small / Geo: off
341     */
342    public void testCameraPairwiseScenario22() throws Exception {
343        genericPairwiseTestCase(Flash.ON, Exposure.MAX, WhiteBalance.AUTO, SceneMode.ACTION,
344                PictureSize.SMALL, Geotagging.OFF);
345    }
346
347    /**
348     * Flash: On / Exposure: Max / WB: Auto
349     * Scene: Night / Pic: Medium / Geo: on
350     */
351    public void testCameraPairwiseScenario23() throws Exception {
352        genericPairwiseTestCase(Flash.ON, Exposure.MAX, WhiteBalance.AUTO, SceneMode.NIGHT,
353                PictureSize.MEDIUM, Geotagging.ON);
354    }
355
356    /**
357     * Flash: Auto / Exposure: None / WB: Fluorescent
358     * Scene: Auto / Pic: Small / Geo: on
359     */
360    public void testCameraPairwiseScenario24() throws Exception {
361        genericPairwiseTestCase(Flash.AUTO, Exposure.NONE, WhiteBalance.FLUORESCENT,
362                SceneMode.AUTO, PictureSize.SMALL, Geotagging.ON);
363    }
364
365    /**
366     * Flash: Auto / Exposure: Max / WB: Daylight
367     * Scene: Auto / Pic: Medium / Geo: off
368     */
369    public void testCameraPairwiseScenario25() throws Exception {
370        genericPairwiseTestCase(Flash.AUTO, Exposure.MAX, WhiteBalance.DAYLIGHT, SceneMode.AUTO,
371                PictureSize.MEDIUM, Geotagging.OFF);
372    }
373
374    /**
375     * Flash: Auto / Exposure: Max / WB: Auto
376     * Scene: Party / Pic: Medium / Geo: on
377     */
378    public void testCameraPairwiseScenario26() throws Exception {
379        genericPairwiseTestCase(Flash.AUTO, Exposure.MAX, WhiteBalance.AUTO, SceneMode.PARTY,
380                PictureSize.MEDIUM, Geotagging.ON);
381    }
382
383    /**
384     * Generic pairwise test method
385     */
386    private void genericPairwiseTestCase(Flash flash, Exposure exposure, WhiteBalance whitebalance,
387            SceneMode scenemode, PictureSize picturesize, Geotagging geotagging) throws Exception {
388        try {
389            SurfaceHolder surfaceHolder = MediaFrameworkTest.mSurfaceView.getHolder();
390            Camera.Parameters params = mCameraTestHelper.getCameraParameters();
391
392            runOnLooper(new Runnable() {
393                @Override
394                public void run() {
395                    mCameraTestHelper.setupCameraTest();
396                }
397            });
398
399            // Configure flash setting
400            switch (flash) {
401                case ON:
402                    params.setFlashMode(Camera.Parameters.FLASH_MODE_ON);
403                    break;
404                case OFF:
405                    params.setFlashMode(Camera.Parameters.FLASH_MODE_OFF);
406                    break;
407                case AUTO:
408                    params.setFlashMode(Camera.Parameters.FLASH_MODE_AUTO);
409                    break;
410            }
411
412            // Configure exposure setting
413            switch (exposure) {
414                case MIN:
415                    params.setExposureCompensation(params.getMinExposureCompensation());
416                    break;
417                case MAX:
418                    params.setExposureCompensation(params.getMaxExposureCompensation());
419                    break;
420                case NONE:
421                    params.setExposureCompensation(0);
422                    break;
423            }
424
425            // Configure white balance setting
426            switch (whitebalance) {
427                case DAYLIGHT:
428                    params.setWhiteBalance(Camera.Parameters.WHITE_BALANCE_DAYLIGHT);
429                    break;
430                case FLUORESCENT:
431                    params.setWhiteBalance(Camera.Parameters.WHITE_BALANCE_FLUORESCENT);
432                    break;
433                case INCANDESCENT:
434                    params.setWhiteBalance(Camera.Parameters.WHITE_BALANCE_INCANDESCENT);
435                    break;
436                case CLOUDY:
437                    params.setWhiteBalance(Camera.Parameters.WHITE_BALANCE_CLOUDY_DAYLIGHT);
438                    break;
439                case AUTO:
440                    params.setWhiteBalance(Camera.Parameters.WHITE_BALANCE_AUTO);
441                    break;
442            }
443
444            // Configure scene mode setting
445            switch (scenemode) {
446                case SUNSET:
447                    params.setSceneMode(Camera.Parameters.SCENE_MODE_SUNSET);
448                    break;
449                case ACTION:
450                    params.setSceneMode(Camera.Parameters.SCENE_MODE_ACTION);
451                    break;
452                case PARTY:
453                    params.setSceneMode(Camera.Parameters.SCENE_MODE_PARTY);
454                    break;
455                case NIGHT:
456                    params.setSceneMode(Camera.Parameters.SCENE_MODE_NIGHT);
457                    break;
458                case AUTO:
459                    params.setSceneMode(Camera.Parameters.SCENE_MODE_AUTO);
460                    break;
461            }
462
463            // Configure picture size setting
464            List<Camera.Size> supportedPictureSizes = params.getSupportedPictureSizes();
465            int mid = (int) Math.floor(supportedPictureSizes.size() / 2);
466            int low = supportedPictureSizes.size() - 1;
467            switch (picturesize) {
468                case SMALL:
469                    params.setPictureSize(supportedPictureSizes.get(low).width,
470                            supportedPictureSizes.get(low).height);
471                    break;
472                case MEDIUM:
473                    params.setPictureSize(supportedPictureSizes.get(mid).width,
474                            supportedPictureSizes.get(mid).height);
475                    break;
476                case LARGE:
477                    params.setPictureSize(supportedPictureSizes.get(0).width,
478                            supportedPictureSizes.get(mid).height);
479                    break;
480            }
481
482            // Configure geotagging setting
483            switch (geotagging) {
484                case ON:
485                    params.setGpsLatitude(MOCK_LATITUDE);
486                    params.setGpsLongitude(MOCK_LONGITUDE);
487                    break;
488                case OFF:
489                    break;
490            }
491
492            mCameraTestHelper.setParameters(params);
493            mCameraTestHelper.startCameraPreview(surfaceHolder);
494            mCameraTestHelper.capturePhoto();
495            mCameraTestHelper.cleanupTestImages();
496        } catch (Exception e) {
497            Log.e(TAG, e.toString());
498            fail("Test case failed");
499        }
500    }
501}
502