Closed 782891085 closed 7 years ago
Didn't try with a device like this. Can you provide the stacktrace for the crash?
here is the stacktrace in stacktrace.txt.But I don't think it's your problem, because it doesn't have permission, and developers call it and cause it to crash. Or you can throw an exception here to avoid crashing.
10-16 10:13:40.458 27197-27197/com.zjx.qrcodereaderviewtest E/AndroidRuntime: FATAL EXCEPTION: main java.lang.RuntimeException: Fail to connect to camera service at android.hardware.Camera.native_setup(Native Method) at android.hardware.Camera.<init>(Camera.java:434) at android.hardware.Camera.open(Camera.java:393) at com.google.zxing.client.android.camera.open.OpenCameraInterface.open(OpenCameraInterface.java:76) at com.google.zxing.client.android.camera.CameraManager.openDriver(CameraManager.java:104) at com.dlazaro66.qrcodereaderview.QRCodeReaderView.surfaceCreated(QRCodeReaderView.java:213) at android.view.SurfaceView.updateWindow(SurfaceView.java:622) at android.view.SurfaceView.access$000(SurfaceView.java:90) at android.view.SurfaceView$3.onPreDraw(SurfaceView.java:185) at android.view.ViewTreeObserver.dispatchOnPreDraw(ViewTreeObserver.java:680) at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:2217) at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1211) at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:5039) at android.view.Choreographer$CallbackRecord.run(Choreographer.java:776) at android.view.Choreographer.doCallbacks(Choreographer.java:579) at android.view.Choreographer.doFrame(Choreographer.java:548) at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:762) at android.os.Handler.handleCallback(Handler.java:800) at android.os.Handler.dispatchMessage(Handler.java:100) at android.os.Looper.loop(Looper.java:194) at android.app.ActivityThread.main(ActivityThread.java:5433) at java.lang.reflect.Method.invokeNative(Native Method) at java.lang.reflect.Method.invoke(Method.java:525) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:922) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:689) at dalvik.system.NativeStart.main(Native Method)
OpenDriver method blocking UI problem, I made some modifications to QRCodeReaderView and made a simple DEMO, but I'm not sure that I will make other problems caused by this modification. These files can be found in the attachment. Thank you.
Here's my revised qrcodereaderview.
`/*
import android.content.Context; import android.content.pm.PackageManager; import android.graphics.Point; import android.graphics.PointF; import android.hardware.Camera; import android.os.AsyncTask; import android.util.AttributeSet; import android.util.Log; import android.view.Surface; import android.view.SurfaceHolder; import android.view.SurfaceView; import android.view.WindowManager;
import com.dlazaro66.qrcodereaderview.Orientation; import com.dlazaro66.qrcodereaderview.QRToViewPointTransformer; import com.google.zxing.BinaryBitmap; import com.google.zxing.ChecksumException; import com.google.zxing.DecodeHintType; import com.google.zxing.FormatException; import com.google.zxing.NotFoundException; import com.google.zxing.PlanarYUVLuminanceSource; import com.google.zxing.Result; import com.google.zxing.ResultPoint; import com.google.zxing.client.android.camera.CameraManager; import com.google.zxing.common.HybridBinarizer; import com.google.zxing.qrcode.QRCodeReader;
import java.io.IOException; import java.lang.ref.WeakReference; import java.util.Map; import static android.hardware.Camera.getCameraInfo;
public class QRCodeReaderView extends SurfaceView implements SurfaceHolder.Callback, Camera.PreviewCallback { private QRCodeReaderView.OnCameraOpenDriverErrorListener mOnCameraOpenDriverErrorListener;
public interface OnCameraOpenDriverErrorListener {
void OnCameraOpenDriverError(Exception e);
}
public void setOnCameraOpenDriverErrorListener(QRCodeReaderView.OnCameraOpenDriverErrorListener onCameraOpenDriverErrorListener) {
mOnCameraOpenDriverErrorListener = onCameraOpenDriverErrorListener;
}
public interface OnQRCodeReadListener {
void onQRCodeRead(String text, PointF[] points);
}
private QRCodeReaderView.OnQRCodeReadListener mOnQRCodeReadListener;
private static final String TAG = QRCodeReaderView.class.getName();
private QRCodeReader mQRCodeReader;
private int mPreviewWidth;
private int mPreviewHeight;
private CameraManager mCameraManager;
private boolean mQrDecodingEnabled = true;
private DecodeFrameTask decodeFrameTask;
private Map<DecodeHintType, Object> decodeHints;
public QRCodeReaderView(Context context) {
this(context, null);
}
public QRCodeReaderView(Context context, AttributeSet attrs) {
super(context, attrs);
initCamera();
}
public void initCamera() {
if (isInEditMode()) {
return;
}
if (checkCameraHardware()) {
mCameraManager = new CameraManager(getContext());
mCameraManager.setPreviewCallback(this);
setBackCamera();
getHolder().addCallback(this);
} else {
throw new RuntimeException("Error: Camera not found");
}
}
/**
* Set the callback to return decoding result
*
* @param onQRCodeReadListener the listener
*/
public void setOnQRCodeReadListener(QRCodeReaderView.OnQRCodeReadListener onQRCodeReadListener) {
mOnQRCodeReadListener = onQRCodeReadListener;
}
/**
* Set QR decoding enabled/disabled.
* default value is true
*
* @param qrDecodingEnabled decoding enabled/disabled.
*/
public void setQRDecodingEnabled(boolean qrDecodingEnabled) {
this.mQrDecodingEnabled = qrDecodingEnabled;
}
/**
* Set QR hints required for decoding
*
* @param decodeHints hints for decoding qrcode
*/
public void setDecodeHints(Map<DecodeHintType, Object> decodeHints) {
this.decodeHints = decodeHints;
}
/**
* Starts camera preview and decoding
*/
public void startCamera() {
if (mCameraManager != null) {
mCameraManager.startPreview();
}
}
/**
* Stop camera preview and decoding
*/
public void stopCamera() {
if (mCameraManager != null) {
mCameraManager.stopPreview();
}
}
/**
* Set Camera autofocus interval value
* default value is 5000 ms.
*
* @param autofocusIntervalInMs autofocus interval value
*/
public void setAutofocusInterval(long autofocusIntervalInMs) {
if (mCameraManager != null) {
mCameraManager.setAutofocusInterval(autofocusIntervalInMs);
}
}
/**
* Trigger an auto focus
*/
public void forceAutoFocus() {
if (mCameraManager != null) {
mCameraManager.forceAutoFocus();
}
}
/**
* Set Torch enabled/disabled.
* default value is false
*
* @param enabled torch enabled/disabled.
*/
public void setTorchEnabled(boolean enabled) {
if (mCameraManager != null) {
mCameraManager.setTorchEnabled(enabled);
}
}
/**
* Allows user to specify the camera ID, rather than determine
* it automatically based on available cameras and their orientation.
*
* @param cameraId camera ID of the camera to use. A negative value means "no preference".
*/
public void setPreviewCameraId(int cameraId) {
if (mCameraManager != null) {
mCameraManager.setPreviewCameraId(cameraId);
}
}
/**
* Camera preview from device back camera
*/
public void setBackCamera() {
setPreviewCameraId(Camera.CameraInfo.CAMERA_FACING_BACK);
}
/**
* Camera preview from device front camera
*/
public void setFrontCamera() {
setPreviewCameraId(Camera.CameraInfo.CAMERA_FACING_FRONT);
}
@Override
public void onDetachedFromWindow() {
super.onDetachedFromWindow();
if (decodeFrameTask != null) {
decodeFrameTask.cancel(true);
decodeFrameTask = null;
}
}
/****************************************************
* SurfaceHolder.Callback,Camera.PreviewCallback
****************************************************/
@Override
public void surfaceCreated(final SurfaceHolder holder) {
startInit();
}
public void startInit() {
new InitThread().start();
}
private class InitThread extends Thread {
@Override
public void run() {
super.run();
init(getHolder());
}
}
private void init(SurfaceHolder holder) {
long s = System.currentTimeMillis();
if (mCameraManager == null) {
return;
}
try {
// Indicate camera, our View dimensions
mCameraManager.openDriver(holder, QRCodeReaderView.this.getWidth(), QRCodeReaderView.this.getHeight());
} catch (IOException e1) {
Log.w(TAG, "Can not openDriver: " + e1.getMessage());
mCameraManager.closeDriver();
} catch (final RuntimeException e) {
//zjx:If don't get permission, it will crash
Log.w(TAG, "Can not openDriver: " + e.getMessage());
if (mOnCameraOpenDriverErrorListener != null) {
post(new Runnable() {
@Override
public void run() {
mOnCameraOpenDriverErrorListener.OnCameraOpenDriverError(e);
}
});
}
mCameraManager.closeDriver();
}
try {
mQRCodeReader = new QRCodeReader();
mCameraManager.startPreview();
} catch (Exception e2) {
Log.e(TAG, "Exception: " + e2.getMessage());
mCameraManager.closeDriver();
}
if (holder.getSurface() == null) {
Log.e(TAG, "Error: preview surface does not exist");
return;
}
if (mCameraManager == null) {
return;
}
if (mCameraManager.getPreviewSize() == null) {
Log.e(TAG, "Error: preview size does not exist");
return;
}
mPreviewWidth = mCameraManager.getPreviewSize().x;
mPreviewHeight = mCameraManager.getPreviewSize().y;
mCameraManager.stopPreview();
// Fix the camera sensor rotation
mCameraManager.setPreviewCallback(this);
mCameraManager.setDisplayOrientation(getCameraDisplayOrientation());
mCameraManager.startPreview();
long e = System.currentTimeMillis();
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
Log.e(TAG, "surfaceChanged:end ");
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
mCameraManager.setPreviewCallback(null);
mCameraManager.stopPreview();
mCameraManager.closeDriver();
}
// Called when camera take a frame
@Override
public void onPreviewFrame(byte[] data, Camera camera) {
if (!mQrDecodingEnabled || decodeFrameTask != null
&& decodeFrameTask.getStatus() == AsyncTask.Status.RUNNING) {
return;
}
decodeFrameTask = new DecodeFrameTask(this, decodeHints);
decodeFrameTask.execute(data);
}
/**
* Check if this device has a camera
*/
private boolean checkCameraHardware() {
if (getContext().getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA)) {
// this device has a camera
return true;
} else if (getContext().getPackageManager()
.hasSystemFeature(PackageManager.FEATURE_CAMERA_FRONT)) {
// this device has a front camera
return true;
} else {
// this device has any camera
return getContext().getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA_ANY);
}
}
/**
* Fix for the camera Sensor on some devices (ex.: Nexus 5x)
*/
@SuppressWarnings("deprecation")
private int getCameraDisplayOrientation() {
if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.GINGERBREAD) {
return 90;
}
Camera.CameraInfo info = new Camera.CameraInfo();
getCameraInfo(mCameraManager.getPreviewCameraId(), info);
WindowManager windowManager =
(WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE);
int rotation = windowManager.getDefaultDisplay().getRotation();
int degrees = 0;
switch (rotation) {
case Surface.ROTATION_0:
degrees = 0;
break;
case Surface.ROTATION_90:
degrees = 90;
break;
case Surface.ROTATION_180:
degrees = 180;
break;
case Surface.ROTATION_270:
degrees = 270;
break;
default:
break;
}
int result;
if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
result = (info.orientation + degrees) % 360;
result = (360 - result) % 360; // compensate the mirror
} else { // back-facing
result = (info.orientation - degrees + 360) % 360;
}
return result;
}
private static class DecodeFrameTask extends AsyncTask<byte[], Void, Result> {
private final WeakReference<QRCodeReaderView> viewRef;
private final WeakReference<Map<DecodeHintType, Object>> hintsRef;
private final QRToViewPointTransformer qrToViewPointTransformer =
new QRToViewPointTransformer();
public DecodeFrameTask(QRCodeReaderView view, Map<DecodeHintType, Object> hints) {
viewRef = new WeakReference<>(view);
hintsRef = new WeakReference<>(hints);
}
@Override
protected Result doInBackground(byte[]... params) {
final QRCodeReaderView view = viewRef.get();
if (view == null) {
return null;
}
final PlanarYUVLuminanceSource source =
view.mCameraManager.buildLuminanceSource(params[0], view.mPreviewWidth,
view.mPreviewHeight);
final HybridBinarizer hybBin = new HybridBinarizer(source);
final BinaryBitmap bitmap = new BinaryBitmap(hybBin);
try {
return view.mQRCodeReader.decode(bitmap, hintsRef.get());
} catch (ChecksumException e) {
Log.d(TAG, "ChecksumException", e);
} catch (NotFoundException e) {
Log.d(TAG, "No QR Code found");
} catch (FormatException e) {
Log.d(TAG, "FormatException", e);
} catch (Exception e) {
} finally {
view.mQRCodeReader.reset();
}
return null;
}
@Override
protected void onPostExecute(Result result) {
super.onPostExecute(result);
final QRCodeReaderView view = viewRef.get();
// Notify we found a QRCode
if (view != null && result != null && view.mOnQRCodeReadListener != null) {
// Transform resultPoints to View coordinates
final PointF[] transformedPoints =
transformToViewCoordinates(view, result.getResultPoints());
view.mOnQRCodeReadListener.onQRCodeRead(result.getText(), transformedPoints);
}
}
/**
* Transform result to surfaceView coordinates
* <p>
* This method is needed because coordinates are given in landscape camera coordinates when
* device is in portrait mode and different coordinates otherwise.
*
* @return a new PointF array with transformed points
*/
private PointF[] transformToViewCoordinates(QRCodeReaderView view, ResultPoint[] resultPoints) {
int orientationDegrees = view.getCameraDisplayOrientation();
Orientation orientation =
orientationDegrees == 90 || orientationDegrees == 270 ? Orientation.PORTRAIT
: Orientation.LANDSCAPE;
Point viewSize = new Point(view.getWidth(), view.getHeight());
Point cameraPreviewSize = view.mCameraManager.getPreviewSize();
boolean isMirrorCamera =
view.mCameraManager.getPreviewCameraId() == Camera.CameraInfo.CAMERA_FACING_FRONT;
return qrToViewPointTransformer.transform(resultPoints, isMirrorCamera, orientation, viewSize,
cameraPreviewSize);
}
}
}
`
It's definitely a permission grant issue, please take a look at the example code, and make sure you ask for it before using the library
OpenDriver this method will cause some cell phone crashes, like some mobile phone version is less than 23, but it has its own permission management, such as HUAWEI H30-T00.