From ebbb0bc56355abbeff26fa6ef1305d8e4d6957a8 Mon Sep 17 00:00:00 2001 From: Johnson Lu Date: Sat, 15 Dec 2018 11:50:46 +0800 Subject: [PATCH] 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 --- .../wifi_dpp_qrcode_scanner_fragment.xml | 19 +++--- .../wifi_dpp_qrcode_scanner_fragment.xml | 16 ++--- .../wifi/dpp/WifiDppQrCodeBaseFragment.java | 13 ---- .../dpp/WifiDppQrCodeScannerFragment.java | 49 ++++++++------- .../settings/wifi/qrcode/QrCamera.java | 63 +++++++++++++++---- .../settings/wifi/qrcode/QrPreviewLayout.java | 50 +++++++++++++++ .../settings/wifi/qrcode/QrCameraTest.java | 15 +++-- 7 files changed, 155 insertions(+), 70 deletions(-) create mode 100644 src/com/android/settings/wifi/qrcode/QrPreviewLayout.java diff --git a/res/layout-land/wifi_dpp_qrcode_scanner_fragment.xml b/res/layout-land/wifi_dpp_qrcode_scanner_fragment.xml index 0c938f82ede..fb50def7649 100644 --- a/res/layout-land/wifi_dpp_qrcode_scanner_fragment.xml +++ b/res/layout-land/wifi_dpp_qrcode_scanner_fragment.xml @@ -24,20 +24,19 @@ - - + + android:layout_width="wrap_content" + android:layout_height="match_parent"/> - + android:layout_width="wrap_content" + android:layout_height="match_parent"/> + - - + - + { 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(); diff --git a/src/com/android/settings/wifi/qrcode/QrPreviewLayout.java b/src/com/android/settings/wifi/qrcode/QrPreviewLayout.java new file mode 100644 index 00000000000..56566aeefb6 --- /dev/null +++ b/src/com/android/settings/wifi/qrcode/QrPreviewLayout.java @@ -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); + } + } +} diff --git a/tests/robotests/src/com/android/settings/wifi/qrcode/QrCameraTest.java b/tests/robotests/src/com/android/settings/wifi/qrcode/QrCameraTest.java index e32ac6b5a8b..0ef02737007 100644 --- a/tests/robotests/src/com/android/settings/wifi/qrcode/QrCameraTest.java +++ b/tests/robotests/src/com/android/settings/wifi/qrcode/QrCameraTest.java @@ -22,9 +22,11 @@ import static org.mockito.Mockito.mock; import android.content.Context; import android.graphics.Bitmap; +import android.graphics.Color; +import android.graphics.Matrix; import android.graphics.Rect; +import android.graphics.SurfaceTexture; import android.util.Size; -import android.view.SurfaceHolder; import com.android.settings.R; @@ -48,7 +50,7 @@ import org.robolectric.RuntimeEnvironment; public class QrCameraTest { @Mock - private SurfaceHolder mSurfaceHolder; + private SurfaceTexture mSurfaceTexture; private QrCamera mCamera; private Context mContext; @@ -78,6 +80,11 @@ public class QrCameraTest { mCameraCallbacked = true; mCallbackSignal.countDown(); } + + @Override + public void setTransform(Matrix transform) { + // Do nothing + } } private ScannerTestCallback mScannerCallback; @@ -87,7 +94,7 @@ public class QrCameraTest { mContext = RuntimeEnvironment.application; mScannerCallback = new ScannerTestCallback(); mCamera = new QrCamera(mContext, mScannerCallback); - mSurfaceHolder = mock(SurfaceHolder.class); + mSurfaceTexture = mock(SurfaceTexture.class); mQrCode = ""; mCameraCallbacked = false; mCallbackSignal = null; @@ -96,7 +103,7 @@ public class QrCameraTest { @Test public void testCamera_Init_Callback() throws InterruptedException { mCallbackSignal = new CountDownLatch(1); - mCamera.start(mSurfaceHolder); + mCamera.start(mSurfaceTexture); mCallbackSignal.await(5000, TimeUnit.MILLISECONDS); assertThat(mCameraCallbacked).isTrue(); }