blob: 339f005c2bc4d68fb0070c0c7e6b07eedc27e727 [file] [log] [blame]
Doris Liuffa62372013-01-31 19:03:48 -08001/*
2 * Copyright (C) 2012 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.camera.activity;
18
19import android.app.Activity;
20import android.app.Instrumentation;
21import android.hardware.Camera;
22import android.hardware.Camera.AutoFocusCallback;
23import android.hardware.Camera.CameraInfo;
24import android.hardware.Camera.Parameters;
25import android.hardware.Camera.PictureCallback;
26import android.hardware.Camera.ShutterCallback;
27import android.test.ActivityInstrumentationTestCase2;
28import android.view.KeyEvent;
29import android.view.MotionEvent;
30import android.view.View;
31
32import com.android.camera.CameraHolder;
Angus Kong20fad242013-11-11 18:23:46 -080033import com.android.camera.app.CameraManager.CameraProxy;
Angus Kongb50b5cb2013-08-09 14:55:20 -070034import com.android.camera.util.CameraUtil;
John Reck26ac2612013-02-15 16:08:26 -080035import com.android.gallery3d.R;
Doris Liuffa62372013-01-31 19:03:48 -080036
37import static com.google.testing.littlemock.LittleMock.mock;
38import static com.google.testing.littlemock.LittleMock.doAnswer;
39import static com.google.testing.littlemock.LittleMock.doReturn;
40import static com.google.testing.littlemock.LittleMock.anyObject;
41import com.google.testing.littlemock.AppDataDirGuesser;
42import com.google.testing.littlemock.ArgumentCaptor;
43import com.google.testing.littlemock.Captor;
44import com.google.testing.littlemock.LittleMock;
45import com.google.testing.littlemock.Mock;
46
47import java.io.File;
48import java.io.ByteArrayOutputStream;
49import java.io.InputStream;
50import java.io.IOException;
51import java.util.concurrent.Callable;
52
53
54public class CameraTestCase<T extends Activity> extends ActivityInstrumentationTestCase2<T> {
55 protected CameraInfo mCameraInfo[];
56 protected CameraProxy mMockCamera[];
57 protected CameraInfo mOneCameraInfo[];
58 protected CameraProxy mOneMockCamera[];
59 private static Parameters mParameters;
60 private byte[] mBlankJpeg;
61 @Mock private CameraProxy mMockBackCamera;
62 @Mock private CameraProxy mMockFrontCamera;
63 @Captor private ArgumentCaptor<ShutterCallback> mShutterCallback;
64 @Captor private ArgumentCaptor<PictureCallback> mRawPictureCallback;
65 @Captor private ArgumentCaptor<PictureCallback> mJpegPictureCallback;
66 @Captor private ArgumentCaptor<AutoFocusCallback> mAutoFocusCallback;
67 Callable<Object> mAutoFocusCallable = new AutoFocusCallable();
68 Callable<Object> mTakePictureCallable = new TakePictureCallable();
69
70 private class TakePictureCallable implements Callable<Object> {
71 @Override
72 public Object call() throws Exception {
73 Runnable runnable = new Runnable() {
74 @Override
75 public void run() {
76 readBlankJpeg();
77 Camera camera = mOneMockCamera[0].getCamera();
78 mShutterCallback.getValue().onShutter();
79 mRawPictureCallback.getValue().onPictureTaken(null, camera);
80 mJpegPictureCallback.getValue().onPictureTaken(mBlankJpeg, camera);
81 }
82 };
83 // Probably need some delay. Make sure shutter callback is called
84 // after onShutterButtonFocus(false).
85 getActivity().findViewById(R.id.gl_root_view).postDelayed(runnable, 50);
86 return null;
87 }
88 }
89
90 private class AutoFocusCallable implements Callable<Object> {
91 @Override
92 public Object call() throws Exception {
93 Runnable runnable = new Runnable() {
94 @Override
95 public void run() {
96 Camera camera = mOneMockCamera[0].getCamera();
97 mAutoFocusCallback.getValue().onAutoFocus(true, camera);
98 }
99 };
100 // Need some delay. Otherwise, focus callback will be run before
101 // onShutterButtonClick
102 getActivity().findViewById(R.id.gl_root_view).postDelayed(runnable, 50);
103 return null;
104 }
105 }
106
107 public CameraTestCase(Class<T> activityClass) {
108 super(activityClass);
109 }
110
111 @Override
112 protected void setUp() throws Exception {
113 super.setUp();
114 AppDataDirGuesser.setInstance(new AppDataDirGuesser() {
115 @Override
116 public File guessSuitableDirectoryForGeneratedClasses() {
117 return getInstrumentation().getTargetContext().getCacheDir();
118 }
119 });
120 AppDataDirGuesser.getsInstance().guessSuitableDirectoryForGeneratedClasses();
121 LittleMock.initMocks(this);
122 mCameraInfo = new CameraInfo[2];
123 mCameraInfo[0] = new CameraInfo();
124 mCameraInfo[0].facing = CameraInfo.CAMERA_FACING_BACK;
125 mCameraInfo[1] = new CameraInfo();
126 mCameraInfo[1].facing = CameraInfo.CAMERA_FACING_FRONT;
127 mMockCamera = new CameraProxy[2];
128 mMockCamera[0] = mMockBackCamera;
129 mMockCamera[1] = mMockFrontCamera;
130 doReturn(getParameters()).when(mMockCamera[0]).getParameters();
131 doReturn(getParameters()).when(mMockCamera[1]).getParameters();
132
133 mOneCameraInfo = new CameraInfo[1];
134 mOneCameraInfo[0] = new CameraInfo();
135 mOneCameraInfo[0].facing = CameraInfo.CAMERA_FACING_BACK;
136 mOneMockCamera = new CameraProxy[1];
137 mOneMockCamera[0] = mMockBackCamera;
138 doReturn(getParameters()).when(mOneMockCamera[0]).getParameters();
139
140 // Mock takePicture call.
141 doAnswer(mTakePictureCallable).when(mMockBackCamera).takePicture(
142 mShutterCallback.capture(), mRawPictureCallback.capture(),
143 (PictureCallback) anyObject(), mJpegPictureCallback.capture());
144
145 // Mock autoFocus call.
146 doAnswer(mAutoFocusCallable).when(mMockBackCamera).autoFocus(
147 mAutoFocusCallback.capture());
148 }
149
150 private void readBlankJpeg() {
151 InputStream ins = getActivity().getResources().openRawResource(R.raw.blank);
152 ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
153 int size = 0;
154
155 // Read the entire resource into a local byte buffer.
156 byte[] buffer = new byte[1024];
157 try {
158 while((size = ins.read(buffer, 0, 1024)) >= 0){
159 outputStream.write(buffer, 0, size);
160 }
161 } catch (IOException e) {
162 // ignore
163 } finally {
Angus Kongb50b5cb2013-08-09 14:55:20 -0700164 CameraUtil.closeSilently(ins);
Doris Liuffa62372013-01-31 19:03:48 -0800165 }
166 mBlankJpeg = outputStream.toByteArray();
167 }
168
169 @Override
170 protected void tearDown() throws Exception {
171 super.tearDown();
172 CameraHolder.injectMockCamera(null, null);
173 }
174
175 protected void internalTestFailToConnect() throws Exception {
176 CameraHolder.injectMockCamera(mCameraInfo, null);
177
178 getActivity();
179 Instrumentation inst = getInstrumentation();
180 inst.waitForIdleSync();
181 inst.sendKeyDownUpSync(KeyEvent.KEYCODE_DPAD_CENTER); // close dialog
182 }
183
184 protected void performClick(final int id) {
185 Activity activity = getActivity();
186 getInstrumentation().waitForIdleSync();
187 assertNotNull(activity.findViewById(id));
188 Instrumentation inst = getInstrumentation();
189 inst.runOnMainSync(new Runnable() {
190 @Override
191 public void run() {
192 View v = getActivity().findViewById(id);
193 float x = (v.getLeft() + v.getRight()) / 2;
194 float y = (v.getTop() + v.getBottom()) / 2;
195 MotionEvent down = MotionEvent.obtain(0, 0,
196 MotionEvent.ACTION_DOWN, x, y, 0, 0, 0, 0, 0, 0, 0);
197 MotionEvent up = MotionEvent.obtain(0, 0,
198 MotionEvent.ACTION_UP, x, y, 0, 0, 0, 0, 0, 0, 0);
199 View parent = (View) v.getParent();
200 parent.dispatchTouchEvent(down);
201 parent.dispatchTouchEvent(up);
202 }
203 });
204 inst.waitForIdleSync();
205 }
206
207 protected void assertViewNotExist(int id) {
208 Activity activity = getActivity();
209 getInstrumentation().waitForIdleSync();
210 assertNull(activity.findViewById(id));
211 }
212
213 protected void assertViewNotVisible(int id) {
214 Activity activity = getActivity();
215 getInstrumentation().waitForIdleSync();
216 View view = activity.findViewById(id);
217 assertTrue(view.getVisibility() != View.VISIBLE);
218 }
219
220 protected static Parameters getParameters() {
221 synchronized (CameraTestCase.class) {
222 if (mParameters == null) {
223 mParameters = android.hardware.Camera.getEmptyParameters();
224 mParameters.unflatten("preview-format-values=yuv420sp,yuv420p,yuv422i-yuyv,yuv420p;" +
225 "preview-format=yuv420sp;" +
226 "preview-size-values=800x480;preview-size=800x480;" +
227 "picture-size-values=320x240;picture-size=320x240;" +
228 "jpeg-thumbnail-size-values=320x240,0x0;jpeg-thumbnail-width=320;jpeg-thumbnail-height=240;" +
229 "jpeg-thumbnail-quality=60;jpeg-quality=95;" +
230 "preview-frame-rate-values=30,15;preview-frame-rate=30;" +
231 "focus-mode-values=continuous-video,auto,macro,infinity,continuous-picture;focus-mode=auto;" +
232 "preview-fps-range-values=(15000,30000);preview-fps-range=15000,30000;" +
233 "scene-mode-values=auto,action,night;scene-mode=auto;" +
234 "flash-mode-values=off,on,auto,torch;flash-mode=off;" +
235 "whitebalance-values=auto,daylight,fluorescent,incandescent;whitebalance=auto;" +
236 "effect-values=none,mono,sepia;effect=none;" +
237 "zoom-supported=true;zoom-ratios=100,200,400;max-zoom=2;" +
238 "picture-format-values=jpeg;picture-format=jpeg;" +
239 "min-exposure-compensation=-30;max-exposure-compensation=30;" +
240 "exposure-compensation=0;exposure-compensation-step=0.1;" +
241 "horizontal-view-angle=40;vertical-view-angle=40;");
242 }
243 }
244 return mParameters;
245 }
246}