blob: 27be3c7d365eac2df5ce1042bfe0619f93138520 [file] [log] [blame]
/*
* Copyright (C) 2012 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.camera.activity;
import android.app.Activity;
import android.app.Instrumentation;
import android.hardware.Camera;
import android.hardware.Camera.AutoFocusCallback;
import android.hardware.Camera.CameraInfo;
import android.hardware.Camera.Parameters;
import android.hardware.Camera.PictureCallback;
import android.hardware.Camera.ShutterCallback;
import android.test.ActivityInstrumentationTestCase2;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.View;
import com.android.camera.CameraHolder;
import com.android.camera.CameraManager.CameraProxy;
import com.android.camera.Util;
import com.android.gallery3d.R;
import static com.google.testing.littlemock.LittleMock.mock;
import static com.google.testing.littlemock.LittleMock.doAnswer;
import static com.google.testing.littlemock.LittleMock.doReturn;
import static com.google.testing.littlemock.LittleMock.anyObject;
import com.google.testing.littlemock.AppDataDirGuesser;
import com.google.testing.littlemock.ArgumentCaptor;
import com.google.testing.littlemock.Captor;
import com.google.testing.littlemock.LittleMock;
import com.google.testing.littlemock.Mock;
import java.io.File;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.io.IOException;
import java.util.concurrent.Callable;
public class CameraTestCase<T extends Activity> extends ActivityInstrumentationTestCase2<T> {
protected CameraInfo mCameraInfo[];
protected CameraProxy mMockCamera[];
protected CameraInfo mOneCameraInfo[];
protected CameraProxy mOneMockCamera[];
private static Parameters mParameters;
private byte[] mBlankJpeg;
@Mock private CameraProxy mMockBackCamera;
@Mock private CameraProxy mMockFrontCamera;
@Captor private ArgumentCaptor<ShutterCallback> mShutterCallback;
@Captor private ArgumentCaptor<PictureCallback> mRawPictureCallback;
@Captor private ArgumentCaptor<PictureCallback> mJpegPictureCallback;
@Captor private ArgumentCaptor<AutoFocusCallback> mAutoFocusCallback;
Callable<Object> mAutoFocusCallable = new AutoFocusCallable();
Callable<Object> mTakePictureCallable = new TakePictureCallable();
private class TakePictureCallable implements Callable<Object> {
@Override
public Object call() throws Exception {
Runnable runnable = new Runnable() {
@Override
public void run() {
readBlankJpeg();
Camera camera = mOneMockCamera[0].getCamera();
mShutterCallback.getValue().onShutter();
mRawPictureCallback.getValue().onPictureTaken(null, camera);
mJpegPictureCallback.getValue().onPictureTaken(mBlankJpeg, camera);
}
};
// Probably need some delay. Make sure shutter callback is called
// after onShutterButtonFocus(false).
getActivity().findViewById(R.id.gl_root_view).postDelayed(runnable, 50);
return null;
}
}
private class AutoFocusCallable implements Callable<Object> {
@Override
public Object call() throws Exception {
Runnable runnable = new Runnable() {
@Override
public void run() {
Camera camera = mOneMockCamera[0].getCamera();
mAutoFocusCallback.getValue().onAutoFocus(true, camera);
}
};
// Need some delay. Otherwise, focus callback will be run before
// onShutterButtonClick
getActivity().findViewById(R.id.gl_root_view).postDelayed(runnable, 50);
return null;
}
}
public CameraTestCase(Class<T> activityClass) {
super(activityClass);
}
@Override
protected void setUp() throws Exception {
super.setUp();
AppDataDirGuesser.setInstance(new AppDataDirGuesser() {
@Override
public File guessSuitableDirectoryForGeneratedClasses() {
return getInstrumentation().getTargetContext().getCacheDir();
}
});
AppDataDirGuesser.getsInstance().guessSuitableDirectoryForGeneratedClasses();
LittleMock.initMocks(this);
mCameraInfo = new CameraInfo[2];
mCameraInfo[0] = new CameraInfo();
mCameraInfo[0].facing = CameraInfo.CAMERA_FACING_BACK;
mCameraInfo[1] = new CameraInfo();
mCameraInfo[1].facing = CameraInfo.CAMERA_FACING_FRONT;
mMockCamera = new CameraProxy[2];
mMockCamera[0] = mMockBackCamera;
mMockCamera[1] = mMockFrontCamera;
doReturn(getParameters()).when(mMockCamera[0]).getParameters();
doReturn(getParameters()).when(mMockCamera[1]).getParameters();
mOneCameraInfo = new CameraInfo[1];
mOneCameraInfo[0] = new CameraInfo();
mOneCameraInfo[0].facing = CameraInfo.CAMERA_FACING_BACK;
mOneMockCamera = new CameraProxy[1];
mOneMockCamera[0] = mMockBackCamera;
doReturn(getParameters()).when(mOneMockCamera[0]).getParameters();
// Mock takePicture call.
doAnswer(mTakePictureCallable).when(mMockBackCamera).takePicture(
mShutterCallback.capture(), mRawPictureCallback.capture(),
(PictureCallback) anyObject(), mJpegPictureCallback.capture());
// Mock autoFocus call.
doAnswer(mAutoFocusCallable).when(mMockBackCamera).autoFocus(
mAutoFocusCallback.capture());
}
private void readBlankJpeg() {
InputStream ins = getActivity().getResources().openRawResource(R.raw.blank);
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
int size = 0;
// Read the entire resource into a local byte buffer.
byte[] buffer = new byte[1024];
try {
while((size = ins.read(buffer, 0, 1024)) >= 0){
outputStream.write(buffer, 0, size);
}
} catch (IOException e) {
// ignore
} finally {
Util.closeSilently(ins);
}
mBlankJpeg = outputStream.toByteArray();
}
@Override
protected void tearDown() throws Exception {
super.tearDown();
CameraHolder.injectMockCamera(null, null);
}
protected void internalTestFailToConnect() throws Exception {
CameraHolder.injectMockCamera(mCameraInfo, null);
getActivity();
Instrumentation inst = getInstrumentation();
inst.waitForIdleSync();
inst.sendKeyDownUpSync(KeyEvent.KEYCODE_DPAD_CENTER); // close dialog
}
protected void performClick(final int id) {
Activity activity = getActivity();
getInstrumentation().waitForIdleSync();
assertNotNull(activity.findViewById(id));
Instrumentation inst = getInstrumentation();
inst.runOnMainSync(new Runnable() {
@Override
public void run() {
View v = getActivity().findViewById(id);
float x = (v.getLeft() + v.getRight()) / 2;
float y = (v.getTop() + v.getBottom()) / 2;
MotionEvent down = MotionEvent.obtain(0, 0,
MotionEvent.ACTION_DOWN, x, y, 0, 0, 0, 0, 0, 0, 0);
MotionEvent up = MotionEvent.obtain(0, 0,
MotionEvent.ACTION_UP, x, y, 0, 0, 0, 0, 0, 0, 0);
View parent = (View) v.getParent();
parent.dispatchTouchEvent(down);
parent.dispatchTouchEvent(up);
}
});
inst.waitForIdleSync();
}
protected void assertViewNotExist(int id) {
Activity activity = getActivity();
getInstrumentation().waitForIdleSync();
assertNull(activity.findViewById(id));
}
protected void assertViewNotVisible(int id) {
Activity activity = getActivity();
getInstrumentation().waitForIdleSync();
View view = activity.findViewById(id);
assertTrue(view.getVisibility() != View.VISIBLE);
}
protected static Parameters getParameters() {
synchronized (CameraTestCase.class) {
if (mParameters == null) {
mParameters = android.hardware.Camera.getEmptyParameters();
mParameters.unflatten("preview-format-values=yuv420sp,yuv420p,yuv422i-yuyv,yuv420p;" +
"preview-format=yuv420sp;" +
"preview-size-values=800x480;preview-size=800x480;" +
"picture-size-values=320x240;picture-size=320x240;" +
"jpeg-thumbnail-size-values=320x240,0x0;jpeg-thumbnail-width=320;jpeg-thumbnail-height=240;" +
"jpeg-thumbnail-quality=60;jpeg-quality=95;" +
"preview-frame-rate-values=30,15;preview-frame-rate=30;" +
"focus-mode-values=continuous-video,auto,macro,infinity,continuous-picture;focus-mode=auto;" +
"preview-fps-range-values=(15000,30000);preview-fps-range=15000,30000;" +
"scene-mode-values=auto,action,night;scene-mode=auto;" +
"flash-mode-values=off,on,auto,torch;flash-mode=off;" +
"whitebalance-values=auto,daylight,fluorescent,incandescent;whitebalance=auto;" +
"effect-values=none,mono,sepia;effect=none;" +
"zoom-supported=true;zoom-ratios=100,200,400;max-zoom=2;" +
"picture-format-values=jpeg;picture-format=jpeg;" +
"min-exposure-compensation=-30;max-exposure-compensation=30;" +
"exposure-compensation=0;exposure-compensation-step=0.1;" +
"horizontal-view-angle=40;vertical-view-angle=40;");
}
}
return mParameters;
}
}