blob: 8b989e1c2071e34eb58641cfa12ff7327f1a5b5d [file] [log] [blame]
/*
* Copyright (C) 2013 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.fov;
import com.android.cts.verifier.R;
import android.app.Activity;
import android.content.SharedPreferences;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.RectF;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.widget.Button;
import android.widget.SeekBar;
import android.widget.SeekBar.OnSeekBarChangeListener;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
/**
* Shows the picture taken and lets the user specify the field of view (FOV).
*/
public class DetermineFovActivity extends Activity {
private static final float FOV_ADJUSTMENT_RANGE = 20;
private static final int SEEKBAR_MAX_VALUE = 100;
private static final float TEXT_SIZE = 16;
private static final float TEXT_PADDING = 0.2f;
private static final String DEFAULT_MARKER_DISTANCE = "36.8";
private static final String DEFAULT_TARGET_DISTANCE = "99.7";
private float mMarkerDistanceCm;
private SurfaceView mSurfaceView;
private SurfaceHolder mSurfaceHolder;
private Bitmap mPhotoBitmap;
private float mFovMinDegrees;
private float mFovMaxDegrees;
private float mFovDegrees;
private float mReportedFovDegrees;
private SeekBar mSeekBar;
private Button mDoneButton;
private float mTargetDistanceCm;
private String mMeasuredText;
private String mReportedText;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.camera_fov_calibration_determine_fov);
File pictureFile = PhotoCaptureActivity.getPictureFile(this);
try {
mPhotoBitmap =
BitmapFactory.decodeStream(new FileInputStream(pictureFile));
} catch (IOException e) {
e.printStackTrace();
}
mSurfaceView = (SurfaceView) findViewById(R.id.camera_fov_photo_surface);
mSurfaceHolder = mSurfaceView.getHolder();
mSurfaceHolder.addCallback(new SurfaceHolder.Callback() {
@Override
public void surfaceDestroyed(SurfaceHolder holder) {}
@Override
public void surfaceCreated(SurfaceHolder holder) {
drawContents();
}
@Override
public void surfaceChanged(
SurfaceHolder holder, int format, int width, int height) {
drawContents();
}
});
mSeekBar = (SeekBar) findViewById(R.id.camera_fov_seekBar);
mSeekBar.setMax(SEEKBAR_MAX_VALUE);
mSeekBar.setOnSeekBarChangeListener(new OnSeekBarChangeListener() {
@Override
public void onStopTrackingTouch(SeekBar seekBar) {}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {}
@Override
public void onProgressChanged(
SeekBar seekBar, int progress, boolean fromUser) {
mFovDegrees = seekBarProgressToFovDegrees(progress);
drawContents();
}
});
mDoneButton = (Button) findViewById(R.id.camera_fov_fov_done);
mDoneButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
setResult(RESULT_OK);
CtsTestHelper.storeCtsTestResult(DetermineFovActivity.this,
mReportedFovDegrees, mFovDegrees);
finish();
}
});
}
private int fovToSeekBarProgress(float fovDegrees) {
return Math.round((fovDegrees - mFovMinDegrees)
/ (mFovMaxDegrees - mFovMinDegrees) * SEEKBAR_MAX_VALUE);
}
private float seekBarProgressToFovDegrees(int progress) {
float degrees = mFovMinDegrees + (float) progress / SEEKBAR_MAX_VALUE
* (mFovMaxDegrees - mFovMinDegrees);
// keep only 2 decimal places.
return (int) (degrees * 100) / 100.0f;
}
@Override
protected void onResume() {
super.onResume();
setResult(RESULT_CANCELED);
mMarkerDistanceCm = getMarkerDistance();
mTargetDistanceCm = getTargetDistance();
mReportedFovDegrees = PhotoCaptureActivity.getReportedFovDegrees();
mFovDegrees = mReportedFovDegrees > 80 ? 60 : mReportedFovDegrees;
mFovMaxDegrees = mFovDegrees + FOV_ADJUSTMENT_RANGE / 2;
mFovMinDegrees = mFovDegrees - FOV_ADJUSTMENT_RANGE / 2;
mMeasuredText = getResources().getString(R.string.camera_fov_displayed_fov_label);
mReportedText = getResources().getString(R.string.camera_fov_reported_fov_label);
mSeekBar.setProgress(fovToSeekBarProgress(mFovDegrees));
drawContents();
}
private float getMarkerDistance() {
// Get the marker distance from the preferences.
SharedPreferences prefs =
PreferenceManager.getDefaultSharedPreferences(this);
return Float.parseFloat(prefs.getString(
CalibrationPreferenceActivity.OPTION_MARKER_DISTANCE,
DEFAULT_MARKER_DISTANCE));
}
private float getTargetDistance() {
// Get the marker distance from the preferences.
SharedPreferences prefs =
PreferenceManager.getDefaultSharedPreferences(this);
return Float.parseFloat(prefs.getString(
CalibrationPreferenceActivity.OPTION_TARGET_DISTANCE,
DEFAULT_TARGET_DISTANCE));
}
private float focalLengthPixels(float fovDegrees, float imageWidth) {
return (float) (imageWidth
/ (2 * Math.tan(fovDegrees / 2 * Math.PI / 180.0f)));
}
private void drawContents() {
SurfaceHolder holder = mSurfaceView.getHolder();
Canvas canvas = holder.lockCanvas();
if (canvas == null || mPhotoBitmap == null) {
return;
}
int canvasWidth = canvas.getWidth();
int canvasHeight = canvas.getHeight();
int photoWidth = mPhotoBitmap.getWidth();
int photoHeight = mPhotoBitmap.getHeight();
RectF drawRect = new RectF();
// Determine if the canvas aspect ratio is larger than that of the photo.
float scale = (float) canvasWidth / photoWidth;
int scaledHeight = (int) (scale * photoHeight);
if (scaledHeight < canvasHeight) {
// If the aspect ratio is smaller, set the destination rectangle to pad
// vertically.
int pad = (canvasHeight - scaledHeight) / 2;
drawRect.set(0, pad, canvasWidth, pad + scaledHeight - 1);
} else {
// Set the destination rectangle to pad horizontally.
scale = (float) canvasHeight / photoHeight;
float scaledWidth = scale * photoWidth;
float pad = (canvasWidth - scaledWidth) / 2;
drawRect.set(pad, 0, pad + scaledWidth - 1, canvasHeight);
}
// Draw the photo.
canvas.drawColor(Color.BLACK);
canvas.drawBitmap(mPhotoBitmap, null, drawRect, null);
// Draw the fov indicator text.
Paint paint = new Paint();
paint.setColor(0xffffffff);
float textSize = TEXT_SIZE * DetermineFovActivity.this.getResources()
.getDisplayMetrics().scaledDensity;
paint.setTextSize(textSize);
canvas.drawText(mMeasuredText + " " + mFovDegrees + " degrees.", textSize,
2 * textSize * (1.0f + TEXT_PADDING), paint);
canvas.drawText(mReportedText + " " + mReportedFovDegrees + " degrees.",
textSize, textSize * (1.0f + TEXT_PADDING), paint);
// Draw the image center circle.
paint.setColor(Color.BLACK);
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeWidth(3);
float dstWidth = drawRect.right - drawRect.left + 1;
float dstHeight = drawRect.bottom - drawRect.top + 1;
float centerX = drawRect.left + dstWidth / 2;
canvas.drawLine(centerX, drawRect.top, centerX, drawRect.bottom, paint);
// Project the markers into the scaled image with the given field of view.
float markerX = mMarkerDistanceCm / 2;
float markerZ = mTargetDistanceCm;
float focalLength = focalLengthPixels(mFovDegrees, dstWidth);
float dx = markerX / markerZ * focalLength;
float projectedMarkerLeft = dstWidth / 2 - dx;
float projectedMarkerRight = dstWidth / 2 + dx;
// Draw the marker lines over the image.
paint.setColor(Color.GREEN);
paint.setStrokeWidth(2);
float markerImageLeft = projectedMarkerLeft + drawRect.left;
canvas.drawLine(
markerImageLeft, drawRect.top, markerImageLeft, drawRect.bottom, paint);
float markerImageRight = projectedMarkerRight + drawRect.left;
canvas.drawLine(markerImageRight, drawRect.top, markerImageRight,
drawRect.bottom, paint);
holder.unlockCanvasAndPost(canvas);
}
}