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