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:
@@ -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();
|
||||
|
50
src/com/android/settings/wifi/qrcode/QrPreviewLayout.java
Normal file
50
src/com/android/settings/wifi/qrcode/QrPreviewLayout.java
Normal file
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright (C) 2018 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.settings.wifi.qrcode;
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.Log;
|
||||
import android.widget.FrameLayout;
|
||||
|
||||
/**
|
||||
* A customize square {@link FrameLayout}.
|
||||
* This is used for camera preview. Choose the smaller size of both dimensions as length and width.
|
||||
*/
|
||||
public class QrPreviewLayout extends FrameLayout {
|
||||
public QrPreviewLayout(Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
public QrPreviewLayout(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
}
|
||||
|
||||
public QrPreviewLayout(Context context, AttributeSet attrs, int defStyle) {
|
||||
super(context, attrs, defStyle);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
||||
// Choose the smaller size of the two dimensions.
|
||||
if (MeasureSpec.getSize(widthMeasureSpec) > MeasureSpec.getSize(heightMeasureSpec)) {
|
||||
super.onMeasure(heightMeasureSpec, heightMeasureSpec);
|
||||
} else {
|
||||
super.onMeasure(widthMeasureSpec, widthMeasureSpec);
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user