183 lines
6.1 KiB
Java
183 lines
6.1 KiB
Java
/*
|
|
* Copyright (C) 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 uk.ac.lancaster.auditor.camera;
|
|
|
|
import android.Manifest;
|
|
import android.content.Context;
|
|
import android.content.res.Configuration;
|
|
import android.support.annotation.RequiresPermission;
|
|
import android.util.AttributeSet;
|
|
import android.util.Log;
|
|
import android.view.SurfaceHolder;
|
|
import android.view.SurfaceView;
|
|
import android.view.ViewGroup;
|
|
|
|
import com.google.android.gms.common.images.Size;
|
|
|
|
import java.io.IOException;
|
|
|
|
public class CameraSourcePreview extends ViewGroup {
|
|
private static final String TAG = CameraSourcePreview.class.getSimpleName();
|
|
|
|
private Context mContext;
|
|
private SurfaceView mSurfaceView;
|
|
private boolean mStartRequested;
|
|
private boolean mSurfaceAvailable;
|
|
private CameraSource mCameraSource;
|
|
|
|
public CameraSourcePreview(Context context, AttributeSet attrs) {
|
|
super(context, attrs);
|
|
mContext = context;
|
|
mStartRequested = false;
|
|
mSurfaceAvailable = false;
|
|
|
|
mSurfaceView = new SurfaceView(context);
|
|
mSurfaceView.getHolder().addCallback(new SurfaceCallback());
|
|
addView(mSurfaceView);
|
|
}
|
|
|
|
@RequiresPermission(Manifest.permission.CAMERA)
|
|
public void start(CameraSource cameraSource) throws IOException, SecurityException {
|
|
if (cameraSource == null) {
|
|
stop();
|
|
}
|
|
|
|
mCameraSource = cameraSource;
|
|
|
|
if (mCameraSource != null) {
|
|
mStartRequested = true;
|
|
startIfReady();
|
|
}
|
|
}
|
|
|
|
public void stop() {
|
|
if (mCameraSource != null) {
|
|
mCameraSource.stop();
|
|
}
|
|
}
|
|
|
|
public void release() {
|
|
if (mCameraSource != null) {
|
|
mCameraSource.release();
|
|
mCameraSource = null;
|
|
}
|
|
}
|
|
|
|
@RequiresPermission(Manifest.permission.CAMERA)
|
|
private void startIfReady() throws IOException, SecurityException {
|
|
if (mStartRequested && mSurfaceAvailable) {
|
|
mCameraSource.start(mSurfaceView.getHolder());
|
|
mStartRequested = false;
|
|
}
|
|
}
|
|
|
|
private class SurfaceCallback implements SurfaceHolder.Callback {
|
|
@Override
|
|
public void surfaceCreated(SurfaceHolder surface) {
|
|
mSurfaceAvailable = true;
|
|
try {
|
|
startIfReady();
|
|
} catch (SecurityException se) {
|
|
Log.e(TAG,"Do not have permission to start the camera", se);
|
|
} catch (IOException e) {
|
|
Log.e(TAG, "Could not start camera source.", e);
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void surfaceDestroyed(SurfaceHolder surface) {
|
|
mSurfaceAvailable = false;
|
|
}
|
|
|
|
@Override
|
|
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
|
|
}
|
|
}
|
|
|
|
@Override
|
|
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
|
|
int previewWidth = 320;
|
|
int previewHeight = 240;
|
|
if (mCameraSource != null) {
|
|
Size size = mCameraSource.getPreviewSize();
|
|
if (size != null) {
|
|
previewWidth = size.getWidth();
|
|
previewHeight = size.getHeight();
|
|
}
|
|
}
|
|
|
|
// Swap width and height sizes when in portrait, since it will be rotated 90 degrees
|
|
if (isPortraitMode()) {
|
|
int tmp = previewWidth;
|
|
previewWidth = previewHeight;
|
|
previewHeight = tmp;
|
|
}
|
|
|
|
final int viewWidth = right - left;
|
|
final int viewHeight = bottom - top;
|
|
|
|
int childWidth;
|
|
int childHeight;
|
|
int childXOffset = 0;
|
|
int childYOffset = 0;
|
|
float widthRatio = (float) viewWidth / (float) previewWidth;
|
|
float heightRatio = (float) viewHeight / (float) previewHeight;
|
|
|
|
// To fill the view with the camera preview, while also preserving the correct aspect ratio,
|
|
// it is usually necessary to slightly oversize the child and to crop off portions along one
|
|
// of the dimensions. We scale up based on the dimension requiring the most correction, and
|
|
// compute a crop offset for the other dimension.
|
|
if (widthRatio > heightRatio) {
|
|
childWidth = viewWidth;
|
|
childHeight = (int) ((float) previewHeight * widthRatio);
|
|
childYOffset = (childHeight - viewHeight) / 2;
|
|
} else {
|
|
childWidth = (int) ((float) previewWidth * heightRatio);
|
|
childHeight = viewHeight;
|
|
childXOffset = (childWidth - viewWidth) / 2;
|
|
}
|
|
|
|
for (int i = 0; i < getChildCount(); ++i) {
|
|
// One dimension will be cropped. We shift child over or up by this offset and adjust
|
|
// the size to maintain the proper aspect ratio.
|
|
getChildAt(i).layout(
|
|
-1 * childXOffset, -1 * childYOffset,
|
|
childWidth - childXOffset, childHeight - childYOffset);
|
|
}
|
|
|
|
try {
|
|
startIfReady();
|
|
} catch (IOException e) {
|
|
Log.e(TAG, "Could not start camera source.", e);
|
|
} catch (SecurityException se) {
|
|
Log.e(TAG, "Does not have permission to start the camera.", se);
|
|
}
|
|
}
|
|
|
|
private boolean isPortraitMode() {
|
|
int orientation = mContext.getResources().getConfiguration().orientation;
|
|
if (orientation == Configuration.ORIENTATION_LANDSCAPE) {
|
|
return false;
|
|
}
|
|
if (orientation == Configuration.ORIENTATION_PORTRAIT) {
|
|
return true;
|
|
}
|
|
|
|
Log.d(TAG, "isPortraitMode returning false by default");
|
|
return false;
|
|
}
|
|
}
|