Adjust camera preview area to square

1.Choose the smaller size of both dimensions as its size.
2.Set transform matrix to crop and center the preview picture.

Bug: 118797380
Test: make RunSettingsRoboTests
Change-Id: Ic65fb1fe0c5082995d6903f50dda48eec16c3fb1
This commit is contained in:
Johnson Lu
2018-12-15 11:50:46 +08:00
parent c748b6eeef
commit ebbb0bc563
7 changed files with 155 additions and 70 deletions

View File

@@ -17,7 +17,10 @@
package com.android.settings.wifi.qrcode;
import android.content.Context;
import android.content.res.Configuration;
import android.graphics.Matrix;
import android.graphics.Rect;
import android.graphics.SurfaceTexture;
import android.hardware.Camera;
import android.hardware.Camera.CameraInfo;
import android.hardware.Camera.Parameters;
@@ -29,7 +32,6 @@ import android.util.ArrayMap;
import android.util.Log;
import android.util.Size;
import android.view.Surface;
import android.view.SurfaceHolder;
import android.view.WindowManager;
import com.google.zxing.BarcodeFormat;
import com.google.zxing.BinaryBitmap;
@@ -50,7 +52,7 @@ import androidx.annotation.VisibleForTesting;
/**
* Manage the camera for the QR scanner and help the decoder to get the image inside the scanning
* frame. Caller prepares a {@link SurfaceHolder} then call {@link #start(SurfaceHolder)} to
* frame. Caller prepares a {@link SurfaceTexture} then call {@link #start(SurfaceTexture)} to
* start QR Code scanning. The scanning result will return by ScannerCallback interface. Caller
* can also call {@link #stop()} to halt QR Code scanning before the result returned.
*/
@@ -90,12 +92,11 @@ public class QrCamera extends Handler {
* The function start camera preview and capture pictures to decode QR code continuously in a
* background task.
*
* @param surfaceHolder the Surface to be used for live preview, must already contain a surface
* when this method is called.
* @param surface The surface to be used for live preview.
*/
public void start(SurfaceHolder surfaceHolder) {
public void start(SurfaceTexture surface) {
if (mDecodeTask == null) {
mDecodeTask = new DecodingTask(surfaceHolder);
mDecodeTask = new DecodingTask(surface);
// Execute in the separate thread pool to prevent block other AsyncTask.
mDecodeTask.executeOnExecutor(Executors.newSingleThreadExecutor());
}
@@ -144,6 +145,13 @@ public class QrCamera extends Handler {
* @return The rectangle would like to crop from the camera preview shot.
*/
Rect getFramePosition(Size previewSize, int cameraOrientation);
/**
* Sets the transform to associate with preview area.
*
* @param transform The transform to apply to the content of preview
*/
void setTransform(Matrix transform);
}
private void setCameraParameter() {
@@ -200,15 +208,15 @@ public class QrCamera extends Handler {
private class DecodingTask extends AsyncTask<Void, Void, String> {
private QrYuvLuminanceSource mImage;
private SurfaceHolder mSurfaceHolder;
private SurfaceTexture mSurface;
private DecodingTask(SurfaceHolder surfaceHolder) {
mSurfaceHolder = surfaceHolder;
private DecodingTask(SurfaceTexture surface) {
mSurface = surface;
}
@Override
protected String doInBackground(Void... tmp) {
if (!initCamera(mSurfaceHolder)) {
if (!initCamera(mSurface)) {
return null;
}
@@ -253,7 +261,7 @@ public class QrCamera extends Handler {
}
}
private boolean initCamera(SurfaceHolder surfaceHolder) {
private boolean initCamera(SurfaceTexture surface) {
final int numberOfCameras = Camera.getNumberOfCameras();
Camera.CameraInfo cameraInfo = new Camera.CameraInfo();
try {
@@ -261,7 +269,7 @@ public class QrCamera extends Handler {
Camera.getCameraInfo(i, cameraInfo);
if (cameraInfo.facing == CameraInfo.CAMERA_FACING_BACK) {
mCamera = Camera.open(i);
mCamera.setPreviewDisplay(surfaceHolder);
mCamera.setPreviewTexture(surface);
mCameraOrientation = cameraInfo.orientation;
break;
}
@@ -272,6 +280,7 @@ public class QrCamera extends Handler {
return false;
}
setCameraParameter();
setTransformationMatrix(mScannerCallback.getViewSize());
if (!startPreview()) {
Log.e(TAG, "Error to init Camera");
mCamera = null;
@@ -288,6 +297,36 @@ public class QrCamera extends Handler {
}
}
/** Set transfom matrix to crop and center the preview picture */
private void setTransformationMatrix(Size viewSize) {
// Check aspect ratio, can only handle square view.
final int viewRatio = (int)getRatio(viewSize.getWidth(), viewSize.getHeight());
if (viewRatio != 1) {
throw new IllegalArgumentException("Preview area should be square");
}
final boolean isPortrait = mContext.get().getResources().getConfiguration().orientation
== Configuration.ORIENTATION_PORTRAIT ? true : false;
final int previewWidth = isPortrait ? mPreviewSize.getWidth() : mPreviewSize.getHeight();
final int previewHeight = isPortrait ? mPreviewSize.getHeight() : mPreviewSize.getWidth();
final float ratioPreview = (float) getRatio(previewWidth, previewHeight);
// Calculate transformation matrix.
float scaleX = 1.0f;
float scaleY = 1.0f;
if (previewWidth > previewHeight) {
scaleY = scaleX / ratioPreview;
} else {
scaleX = scaleY / ratioPreview;
}
// Set the transform matrix.
final Matrix matrix = new Matrix();
matrix.setScale(scaleX, scaleY);
mScannerCallback.setTransform(matrix);
}
private QrYuvLuminanceSource getFrameImage(byte[] imageData) {
final Rect frame = mScannerCallback.getFramePosition(mPreviewSize, mCameraOrientation);
final Camera.Size size = mParameters.getPictureSize();