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