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 com.android.mediaframeworktest.MediaFrameworkTest;
20import com.android.mediaframeworktest.CameraTestHelper;
21
22import java.io.BufferedWriter;
23import java.io.File;
24import java.io.FileWriter;
25import java.io.IOException;
26import java.io.Writer;
27import java.util.concurrent.Semaphore;
28import java.util.concurrent.TimeUnit;
29import java.util.HashMap;
30import java.util.List;
31import java.util.Map;
32
33import android.hardware.Camera;
34import android.hardware.Camera.Parameters;
35import android.os.Environment;
36import android.os.Handler;
37import android.os.Looper;
38import android.test.ActivityInstrumentationTestCase2;
39import android.test.suitebuilder.annotation.LargeTest;
40import android.util.FloatMath;
41import android.util.Log;
42import android.view.SurfaceHolder;
43import com.android.mediaframeworktest.CameraStressTestRunner;
44
45import junit.framework.Assert;
46
47/**
48 * Junit / Instrumentation test case for the following camera APIs:
49 * - flash
50 * - exposure compensation
51 * - white balance
52 * - focus mode
53 *
54 * adb shell am instrument
55 *  -e class com.android.mediaframeworktest.functional.camera.CameraFunctionalTest
56 *  -w com.android.mediaframework/.CameraStressTestRunner
57 */
58public class CameraFunctionalTest extends ActivityInstrumentationTestCase2<MediaFrameworkTest> {
59    private static final long WAIT_TIMEOUT = 10 * 1000; // 10 seconds
60    private CameraTestHelper mCameraTestHelper;
61    private Handler mHandler;
62    private Thread mLooperThread;
63    private Writer mOutput;
64
65    private String TAG = "CameraFunctionalTest";
66
67    public CameraFunctionalTest() {
68        super("com.android.mediaframeworktest", MediaFrameworkTest.class);
69    }
70
71    protected void setUp() throws Exception {
72        final Semaphore sem = new Semaphore(0);
73        mLooperThread = new Thread() {
74            @Override
75            public void run() {
76                Log.v(TAG, "starting looper");
77                Looper.prepare();
78                mHandler = new Handler();
79                sem.release();
80                Looper.loop();
81                Log.v(TAG, "quit looper");
82            }
83        };
84        mLooperThread.start();
85        if (!sem.tryAcquire(WAIT_TIMEOUT, TimeUnit.MILLISECONDS)) {
86            fail("Failed to start the looper.");
87        }
88        getActivity();
89        super.setUp();
90
91        mCameraTestHelper = new CameraTestHelper();
92    }
93
94    @Override
95    protected void tearDown() throws Exception {
96        if (mHandler != null) {
97            mHandler.getLooper().quit();
98            mHandler = null;
99        }
100        if (mLooperThread != null) {
101            mLooperThread.join(WAIT_TIMEOUT);
102            if (mLooperThread.isAlive()) {
103                fail("Failed to stop the looper.");
104            }
105            mLooperThread = null;
106        }
107        super.tearDown();
108    }
109
110    private void runOnLooper(final Runnable command) throws InterruptedException {
111        final Semaphore sem = new Semaphore(0);
112        mHandler.post(new Runnable() {
113            @Override
114            public void run() {
115                try {
116                    command.run();
117                } finally {
118                    sem.release();
119                }
120            }
121        });
122        if (!sem.tryAcquire(WAIT_TIMEOUT, TimeUnit.MILLISECONDS)) {
123            fail("Failed to run the command on the looper.");
124        }
125    }
126
127    /**
128     * Functional test iterating on the range of supported exposure compensation levels
129     */
130    @LargeTest
131    public void testFunctionalCameraExposureCompensation() throws Exception {
132        try {
133            SurfaceHolder surfaceHolder = MediaFrameworkTest.mSurfaceView.getHolder();
134            Parameters params = mCameraTestHelper.getCameraParameters();
135
136            int min = params.getMinExposureCompensation();
137            int max = params.getMaxExposureCompensation();
138            assertFalse("Adjusting exposure not supported", (max == 0 && min == 0));
139            float step = params.getExposureCompensationStep();
140            int stepsPerEV = (int) Math.round(Math.pow((double) step, -1));
141
142            // only get integer values for exposure compensation
143            for (int i = min; i <= max; i += stepsPerEV) {
144                runOnLooper(new Runnable() {
145                    @Override
146                    public void run() {
147                        mCameraTestHelper.setupCameraTest();
148                    }
149                });
150                Log.v(TAG, "Setting exposure compensation index to " + i);
151                params.setExposureCompensation(i);
152                mCameraTestHelper.setParameters(params);
153                mCameraTestHelper.startCameraPreview(surfaceHolder);
154                mCameraTestHelper.capturePhoto();
155            }
156            mCameraTestHelper.cleanupTestImages();
157        } catch (Exception e) {
158            Log.e(TAG, e.toString());
159            fail("Camera exposure compensation test Exception");
160        }
161    }
162
163    /**
164     * Functional test iterating on the various flash modes (on, off, auto, torch)
165     */
166    @LargeTest
167    public void testFunctionalCameraFlashModes() throws Exception {
168        try {
169            SurfaceHolder surfaceHolder = MediaFrameworkTest.mSurfaceView.getHolder();
170            Parameters params = mCameraTestHelper.getCameraParameters();
171            List<String> supportedFlashModes = params.getSupportedFlashModes();
172            assertNotNull("No flash modes supported", supportedFlashModes);
173
174            for (int i = 0; i < supportedFlashModes.size(); i++) {
175                runOnLooper(new Runnable() {
176                    @Override
177                    public void run() {
178                        mCameraTestHelper.setupCameraTest();
179                    }
180                });
181                Log.v(TAG, "Setting flash mode to " + supportedFlashModes.get(i));
182                params.setFlashMode(supportedFlashModes.get(i));
183                mCameraTestHelper.setParameters(params);
184                mCameraTestHelper.startCameraPreview(surfaceHolder);
185                mCameraTestHelper.capturePhoto();
186            }
187            mCameraTestHelper.cleanupTestImages();
188        } catch (Exception e) {
189            Log.e(TAG, e.toString());
190            fail("Camera flash mode test Exception");
191        }
192    }
193
194    /**
195     * Functional test iterating on the various focus modes (auto, infinitiy, macro, etc.)
196     */
197    @LargeTest
198    public void testFunctionalCameraFocusModes() throws Exception {
199        try {
200            SurfaceHolder surfaceHolder = MediaFrameworkTest.mSurfaceView.getHolder();
201            Parameters params = mCameraTestHelper.getCameraParameters();
202            List<String> supportedFocusModes = params.getSupportedFocusModes();
203            assertNotNull("No focus modes supported", supportedFocusModes);
204
205            for (int i = 0; i < supportedFocusModes.size(); i++) {
206                runOnLooper(new Runnable() {
207                    @Override
208                    public void run() {
209                        mCameraTestHelper.setupCameraTest();
210                    }
211                });
212                Log.v(TAG, "Setting focus mode to: " + supportedFocusModes.get(i));
213                params.setFocusMode(supportedFocusModes.get(i));
214                mCameraTestHelper.setParameters(params);
215                mCameraTestHelper.startCameraPreview(surfaceHolder);
216                mCameraTestHelper.capturePhoto();
217            }
218            mCameraTestHelper.cleanupTestImages();
219        } catch (Exception e) {
220            Log.e(TAG, e.toString());
221            fail("Camera focus modes test Exception");
222        }
223    }
224
225    /**
226     * Functional test iterating on the various white balances (auto, daylight, cloudy, etc.)
227     */
228    @LargeTest
229    public void testFunctionalCameraWhiteBalance() throws Exception {
230        try {
231            SurfaceHolder surfaceHolder = MediaFrameworkTest.mSurfaceView.getHolder();
232            Parameters params = mCameraTestHelper.getCameraParameters();
233            List<String> supportedWhiteBalance = params.getSupportedWhiteBalance();
234            assertNotNull("No white balance modes supported", supportedWhiteBalance);
235
236            for (int i = 0; i < supportedWhiteBalance.size(); i++) {
237                runOnLooper(new Runnable() {
238                    @Override
239                    public void run() {
240                        mCameraTestHelper.setupCameraTest();
241                    }
242                });
243                Log.v(TAG, "Setting white balance to: " + supportedWhiteBalance.get(i));
244                params.setWhiteBalance(supportedWhiteBalance.get(i));
245                mCameraTestHelper.setParameters(params);
246                mCameraTestHelper.startCameraPreview(surfaceHolder);
247                mCameraTestHelper.capturePhoto();
248            }
249            mCameraTestHelper.cleanupTestImages();
250        } catch (Exception e) {
251            Log.e(TAG, e.toString());
252            fail("Camera focus modes test Exception");
253        }
254    }
255}
256