blob: d31bd4a00ff0adb483d03546fd88bf34b3bb8b98 [file] [log] [blame]
/*
* Copyright (C) 2011 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.cts.verifier.camera.analyzer;
import com.android.cts.verifier.PassFailButtons;
import com.android.cts.verifier.R;
import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.ImageFormat;
import android.hardware.Camera;
import android.hardware.Camera.CameraInfo;
import android.hardware.Camera.Size;
import android.os.AsyncTask;
import android.os.Bundle;
import android.text.Html;
import android.text.method.ScrollingMovementMethod;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Button;
import android.os.PowerManager;
import android.os.PowerManager.WakeLock;
import android.content.Context;
import java.io.IOException;
import java.lang.Thread;
import java.util.List;
/**
* Controls the UI activities of the camera quality test app. It is created
* as soon as the app started. Users can launch different quality tests with
* the buttons in the UI. This class will manage the threading for different
* tests. Also it will provide debug output or debug text results for tests.
*/
public class CameraAnalyzerActivity extends PassFailButtons.Activity {
private static final String TAG = "CameraAnalyzer";
private SurfaceView mCameraView;
private ImageView mResultView;
private Button mFindCheckerButton;
private Button mExposureCompensationButton;
private Button mWhiteBalanceButton;
private Button mAutoLockButton;
private Button mMeteringButton;
private ListView mTestList;
private TwoColumnAdapter mAdapter;
private Camera mCamera;
private int mCameraIdx = 0;
private boolean mIsCameraOpen = false;
private PowerManager mPowerManager;
private PowerManager.WakeLock mWakeLock;
private boolean mProcessingPicture = false;
private boolean mTestInProgress = false;
private final Object mProcessingTest = new Object();
private CameraTests mCurrentTest = null;
private long mCheckerCenterAddress;
private long mCheckerRadiusAddress;
private String mResultReport = "";
static final String[] TESTS = new String[] {"Test1", "Test2"};
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.ca_main);
setPassFailButtonClickListeners();
setInfoResources(R.string.camera_analyzer, R.string.ca_info, -1);
mFindCheckerButton = (Button) findViewById(R.id.findcheckerboardbutton);
mExposureCompensationButton = (Button) findViewById(R.id.exposurecompensationbutton);
mWhiteBalanceButton = (Button) findViewById(R.id.whitebalancebutton);
mAutoLockButton = (Button) findViewById(R.id.lockbutton);
mMeteringButton = (Button) findViewById(R.id.meteringbutton);
mCameraView = (SurfaceView) findViewById(R.id.cameraview);
mResultView = (ImageView) findViewById(R.id.resultview);
mTestList = (ListView) findViewById(R.id.ca_tests);
mAdapter = new TwoColumnAdapter(this);
// Initialize the list view.
initializeAdapter();
mTestList.setAdapter(mAdapter);
mTestList.setOnItemClickListener(mListListener);
mFindCheckerButton.setOnClickListener(mFindCheckerListener);
mExposureCompensationButton.setOnClickListener(mExposureCompensationListener);
mWhiteBalanceButton.setOnClickListener(mWhiteBalanceListener);
mAutoLockButton.setOnClickListener(mAutoLockListener);
mMeteringButton.setOnClickListener(mMeteringListener);
mCameraView.getHolder().addCallback(mSurfaceChangeListener);
// Disables all test buttons except the color checker test one.
// They will be enabled after the color checker is located.
mExposureCompensationButton.setEnabled(false);
mWhiteBalanceButton.setEnabled(false);
mAutoLockButton.setEnabled(false);
mMeteringButton.setEnabled(false);
}
@Override
public void onResume() {
super.onResume();
openCamera(mCameraIdx);
Camera.Parameters params = mCamera.getParameters();
params.setPictureFormat(ImageFormat.JPEG);
params.setPictureSize(640, 480);
mCamera.setParameters(params);
Log.v(TAG, "Set resolution to 640*480");
}
@Override
public void onPause() {
super.onPause();
CameraTests.getCamera().release();
mIsCameraOpen = false;
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.ca_menu, menu);
Camera.CameraInfo cameraInfo = new Camera.CameraInfo();
int cameraCount = Camera.getNumberOfCameras();
for (int camIdx = 0; camIdx < cameraCount; ++camIdx) {
MenuItem cameraMenuItem = menu.add(0, camIdx, Menu.NONE,
String.format("Open Camera %d", camIdx));
}
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
if (item.getItemId() != mCameraIdx) {
mCameraIdx = item.getItemId();
new SwitchCameraTask().execute(mCameraIdx);
}
return false;
}
private class SwitchCameraTask extends AsyncTask<Integer, Void, Void> {
@Override
protected Void doInBackground(Integer... camIdx) {
if (mTestInProgress) {
synchronized (mProcessingTest) {
try{
Log.v(TAG, "Waiting for test to finish");
mProcessingTest.wait();
} catch (InterruptedException e){
Log.v(TAG, "test wait fails!");
}
}
}
openCamera((int)camIdx[0]);
return null;
}
}
private synchronized void openCamera(int camIdx) {
if (mIsCameraOpen) {
CameraTests.getCamera().release();
Log.v(TAG, "Releasing the cameratests camera");
}
try {
mCamera = Camera.open(camIdx);
mIsCameraOpen = true;
} catch (RuntimeException e) {
throw new RuntimeException("Failed to open the camera", e);
}
try {
mCamera.setPreviewDisplay(mCameraView.getHolder());
} catch (IOException e) {
throw new RuntimeException("Unable to connect camera to display: " + e);
}
mCamera.startPreview();
CameraTests.setCamera(mCamera);
ColorCheckerTest.getSingletonTest().updateCamera();
//WhiteBalanceTest.getSingletonTest().updateCamera();
//ExposureCompensationTest.getSingletonTest().updateCamera();
//MeteringTest.getSingletonTest().updateCamera();
//AutoLockTest.getSingletonTest().updateCamera();
}
public Camera getCameraInstance() {
return mCamera;
}
public void disableAll() {
mExposureCompensationButton.setEnabled(false);
mWhiteBalanceButton.setEnabled(false);
mAutoLockButton.setEnabled(false);
mMeteringButton.setEnabled(false);
mFindCheckerButton.setEnabled(false);
}
public void enableAll() {
mExposureCompensationButton.setEnabled(true);
mWhiteBalanceButton.setEnabled(true);
mAutoLockButton.setEnabled(true);
mMeteringButton.setEnabled(true);
mFindCheckerButton.setEnabled(true);
}
/**
* Provides an abstraction for the Camera tests. The camera tests will
* run in the background and the results will be shown in the UI thread
* after the tests are processed.
*/
private class DebugOutputProcessingTask extends AsyncTask<Integer,
Integer,
Integer> {
@Override
protected Integer doInBackground(Integer... cameraTestIndex) {
Log.v(TAG, "Do in Background started!");
mPowerManager = (PowerManager) getSystemService(Context.POWER_SERVICE);
mWakeLock = mPowerManager.newWakeLock(
PowerManager.SCREEN_DIM_WAKE_LOCK, "CameraQualityTest");
mWakeLock.acquire();
mTestInProgress = true;
// Processes the camera tests one by one and publishes their
// debug output or debug text results after each test is done.
mCurrentTest.run((int)cameraTestIndex[0]);
publishProgress(cameraTestIndex);
Log.v(TAG, "Do in Background thread returns!");
return cameraTestIndex[0];
}
@Override
protected void onProgressUpdate(Integer... cameraTestIndex) {
Log.v(TAG, "Prepare to get debug output!");
// Copies the debug output image or text results to the UI.
mResultView.setImageBitmap(mCurrentTest.getDebugOutput());
mResultReport += (mCurrentTest.getTestName() + mCurrentTest.getDebugText());
mAdapter.notifyDataSetChanged();
}
@Override
protected void onPostExecute(Integer cameraTestIndex) {
// If the test is to find the color checker, copy the memory
// address of the found color checker centers and radius to the
// CameraTests class' static fields.
if (mCurrentTest.copyCheckerAddress()) {
mCheckerCenterAddress = CameraTests.getCheckerCenter();
mCheckerRadiusAddress = CameraTests.getCheckerRadius();
}
if (mCurrentTest.copyCheckerAddress() ||
!mCurrentTest.getTestName().contains("Color Checker")) {
// Enables the button of all other tests after the color checker
// is found. Now the user can start all other available tests.
enableAll();
}
mWakeLock.release();
mTestInProgress = false;
synchronized (mProcessingTest) {
mProcessingTest.notifyAll();
}
}
}
// Creates and runs a new test to find color checker in the captured image.
// It is invoked when users press the Find color checker button in the UI.
private View.OnClickListener mFindCheckerListener = new View.OnClickListener() {
@Override
public void onClick(View v) {
Log.v(TAG, "Running new color checker finding tests!");
ColorCheckerTest colorCheckerTest = ColorCheckerTest.getSingletonTest();
mCurrentTest = colorCheckerTest;
initializeAdapter();
}
};
// Creates and runs a new test to test the exposure compensation function.
// It is invoked when users press the Exposure Compensation Test button
// in the UI.
private View.OnClickListener mExposureCompensationListener = new View.OnClickListener() {
@Override
public void onClick(View v) {
Log.v(TAG, "Running new exposure compensation tests!");
/*ExposureCompensationTest exposureCompensationTest =
ExposureCompensationTest.getSingletonTest();
mCurrentTest = exposureCompensationTest;
initializeAdapter();*/
// Loads the memory address of the checker centers and radius
// from the this class and set the two values for the new test.
//ExposureCompensationTest.setCheckerAddress(mCheckerCenterAddress,
// mCheckerRadiusAddress);
}
};
// Creates and runs a new test to test the white balance function.
// It is invoked when users press the White Balance Test button in the UI.
private View.OnClickListener mWhiteBalanceListener = new View.OnClickListener() {
@Override
public void onClick(View v) {
Log.v(TAG, "Running new white balance tests!");
/*WhiteBalanceTest whiteBalanceTest = WhiteBalanceTest.getSingletonTest();
mCurrentTest = whiteBalanceTest;
initializeAdapter();*/
// Loads the memory address of the checker centers and radius
// from the this class and set the two values for the new test.
//WhiteBalanceTest.setCheckerAddress(mCheckerCenterAddress, mCheckerRadiusAddress);
}
};
// Creates and runs a new test to test the camera metering function.
// It is invoked when users press the Metering Test button in the UI.
private View.OnClickListener mMeteringListener = new View.OnClickListener() {
@Override
public void onClick(View v) {
Log.v(TAG, "Running new metering tests!");
/*MeteringTest meteringTest = MeteringTest.getSingletonTest();
mCurrentTest = meteringTest;
initializeAdapter();*/
// Loads the memory address of the checker centers and radius
// from the this class and set the two values for the new test.
//MeteringTest.setCheckerAddress(mCheckerCenterAddress, mCheckerRadiusAddress);
}
};
// Creates and runs new tests to test the camera auto exposure lock.
// It is invoked when users press the AWB and AE Lock Test button
// in the UI.
private View.OnClickListener mAutoLockListener = new View.OnClickListener() {
@Override
public void onClick(View v) {
Log.v(TAG, "Running New auto exposure/wb lock tests!");
// Loads the memory address of the checker centers and radius
// from the this class and set the two values for the new test.
//AutoLockTest.setCheckerAddress(mCheckerCenterAddress, mCheckerRadiusAddress);
// Construct all base case test scenearios for the Auto Lock test.
// Detailed documentation on each test can be found in native code.
/*AutoLockTest autoLockTest = AutoLockTest.getSingletonTest();
autoLockTest.setActivity(CameraAnalyzerActivity.this);
mCurrentTest = autoLockTest;
initializeAdapter();*/
}
};
// Creates a list listner that launches the experiment with the user's click
private AdapterView.OnItemClickListener mListListener = new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
Log.v(TAG, String.format("Item %d selected!", position));
if (!mTestInProgress) {
DebugOutputProcessingTask captureTask = new DebugOutputProcessingTask();
disableAll();
captureTask.execute(position);
}
}
};
private SurfaceHolder.Callback mSurfaceChangeListener =
new SurfaceHolder.Callback() {
// Sets the aspect ratio of the camera preview to 4:3
@Override
public void surfaceChanged(SurfaceHolder holder,
int format,
int width,
int height) {
int x = mCameraView.getWidth();
int y = mCameraView.getHeight();
Log.v(TAG, String.format("Measures are %d, %d", x, y));
if ( x > 4.0 / 3.0 * y) {
android.view.ViewGroup.LayoutParams lp = mCameraView.getLayoutParams();
lp.height = y;
lp.width = (int)(4.0 / 3.0 * lp.height);
Log.v(TAG, String.format("params are %d, %d", lp.width, lp.height));
mCameraView.setLayoutParams(lp);
}
try {
mCamera.setPreviewDisplay(mCameraView.getHolder());
} catch (IOException e) {
throw new RuntimeException("Unable to connect camera to display: " + e);
}
CameraTests.setCameraView(mCameraView);
mCamera.startPreview();
}
@Override
public void surfaceCreated(SurfaceHolder holder) {}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {}
};
@Override
public String getTestDetails() {
return mResultReport;
}
class TwoColumnAdapter extends ArrayAdapter<String> {
TwoColumnAdapter(Context context) {
super(context, R.layout.ca_row);
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
LayoutInflater inflater = getLayoutInflater();
View row = inflater.inflate(R.layout.ca_row, parent, false);
TextView nameField = (TextView) row.findViewById(R.id.caTestName);
TextView resultField = (TextView) row.findViewById(R.id.caTestResult);
if (mCurrentTest != null) {
nameField.setText(mCurrentTest.getTestName(position));
resultField.setText(mCurrentTest.getResult(position));
}
return row;
}
}
private void initializeAdapter() {
mAdapter.clear();
if (mCurrentTest != null) {
for (int i = 0; i < mCurrentTest.getNumTests(); ++i) {
mAdapter.add(mCurrentTest.getTestName(i));
}
}
}
public int getCameraIdx() {
return mCameraIdx;
}
}