Home | History | Annotate | Download | only in activity
      1 /*
      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 
     17 package com.android.camera.activity;
     18 
     19 import android.app.Activity;
     20 import android.app.Instrumentation;
     21 import android.hardware.Camera;
     22 import android.hardware.Camera.AutoFocusCallback;
     23 import android.hardware.Camera.CameraInfo;
     24 import android.hardware.Camera.Parameters;
     25 import android.hardware.Camera.PictureCallback;
     26 import android.hardware.Camera.ShutterCallback;
     27 import android.test.ActivityInstrumentationTestCase2;
     28 import android.view.KeyEvent;
     29 import android.view.MotionEvent;
     30 import android.view.View;
     31 
     32 import com.android.camera.CameraHolder;
     33 import com.android.camera.CameraManager.CameraProxy;
     34 import com.android.camera.R;
     35 import com.android.camera.Util;
     36 
     37 import static com.google.testing.littlemock.LittleMock.mock;
     38 import static com.google.testing.littlemock.LittleMock.doAnswer;
     39 import static com.google.testing.littlemock.LittleMock.doReturn;
     40 import static com.google.testing.littlemock.LittleMock.anyObject;
     41 import com.google.testing.littlemock.AppDataDirGuesser;
     42 import com.google.testing.littlemock.ArgumentCaptor;
     43 import com.google.testing.littlemock.Captor;
     44 import com.google.testing.littlemock.LittleMock;
     45 import com.google.testing.littlemock.Mock;
     46 
     47 import java.io.File;
     48 import java.io.ByteArrayOutputStream;
     49 import java.io.InputStream;
     50 import java.io.IOException;
     51 import java.util.concurrent.Callable;
     52 
     53 
     54 public 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 {
    164             Util.closeSilently(ins);
    165         }
    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 }
    247