Fix "twitchy fingers" bug in CameraView

better diagnostic information, too.

Fixes #4422
Closes #4427
// FREEBIE
This commit is contained in:
Jake McGinty 2015-11-06 13:14:09 -08:00 committed by Moxie Marlinspike
parent 56a3c99289
commit 5fd5b1e1ed
2 changed files with 35 additions and 38 deletions

View File

@ -1,10 +1,7 @@
package org.thoughtcrime.securesms.components.camera; package org.thoughtcrime.securesms.components.camera;
import android.annotation.TargetApi;
import android.hardware.Camera; import android.hardware.Camera;
import android.hardware.Camera.Parameters;
import android.hardware.Camera.Size; import android.hardware.Camera.Size;
import android.os.Build.VERSION;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
import android.support.annotation.Nullable; import android.support.annotation.Nullable;
@ -14,24 +11,13 @@ import java.util.List;
@SuppressWarnings("deprecation") @SuppressWarnings("deprecation")
public class CameraUtils { public class CameraUtils {
@TargetApi(11)
public static @Nullable Size getPreferredPreviewSize(int orientation, int width, int height, @NonNull Camera camera) {
final Parameters parameters = camera.getParameters();
final Size preferredSize = VERSION.SDK_INT > 11
? parameters.getPreferredPreviewSizeForVideo()
: null;
return preferredSize == null ? getBestAspectPreviewSize(orientation, width, height, parameters)
: preferredSize;
}
/* /*
* modified from: https://github.com/commonsguy/cwac-camera/blob/master/camera/src/com/commonsware/cwac/camera/CameraUtils.java * modified from: https://github.com/commonsguy/cwac-camera/blob/master/camera/src/com/commonsware/cwac/camera/CameraUtils.java
*/ */
public static @Nullable Size getBestAspectPreviewSize(int displayOrientation, public static @Nullable Size getPreferredPreviewSize(int displayOrientation,
int width, int width,
int height, int height,
Parameters parameters) { @NonNull Camera camera) {
double targetRatio = (double)width / height; double targetRatio = (double)width / height;
Size optimalSize = null; Size optimalSize = null;
double minDiff = Double.MAX_VALUE; double minDiff = Double.MAX_VALUE;
@ -40,7 +26,7 @@ public class CameraUtils {
targetRatio = (double)height / width; targetRatio = (double)height / width;
} }
List<Size> sizes = parameters.getSupportedPreviewSizes(); List<Size> sizes = camera.getParameters().getSupportedPreviewSizes();
Collections.sort(sizes, Collections.reverseOrder(new SizeComparator())); Collections.sort(sizes, Collections.reverseOrder(new SizeComparator()));

View File

@ -90,12 +90,9 @@ public class CameraView extends FrameLayout {
@Override @Override
protected @Nullable Camera onRunBackground() { protected @Nullable Camera onRunBackground() {
try { try {
if (cameraId >= 0) { return Camera.open(cameraId);
return Camera.open(cameraId);
} else {
return null;
}
} catch (Exception e) { } catch (Exception e) {
Log.w(TAG, e);
return null; return null;
} }
} }
@ -103,6 +100,7 @@ public class CameraView extends FrameLayout {
@Override @Override
protected void onPostMain(@Nullable Camera camera) { protected void onPostMain(@Nullable Camera camera) {
if (camera == null) { if (camera == null) {
Log.w(TAG, "tried to open camera but got null");
if (listener != null) listener.onCameraFail(); if (listener != null) listener.onCameraFail();
return; return;
} }
@ -132,17 +130,23 @@ public class CameraView extends FrameLayout {
if (!started) return; if (!started) return;
started = false; started = false;
Log.w(TAG, "onPause() queued"); Log.w(TAG, "onPause() queued");
final Optional<Camera> cameraToDestroy = camera;
enqueueTask(new SerialAsyncTask<Void>() { enqueueTask(new SerialAsyncTask<Void>() {
private Optional<Camera> cameraToDestroy;
@Override protected void onPreMain() { @Override protected void onPreMain() {
cameraToDestroy = camera;
camera = Optional.absent(); camera = Optional.absent();
} }
@Override protected Void onRunBackground() { @Override protected Void onRunBackground() {
if (cameraToDestroy.isPresent()) { if (cameraToDestroy.isPresent()) {
stopPreview(); try {
cameraToDestroy.get().release(); stopPreview();
cameraToDestroy.get().release();
Log.w(TAG, "released old camera instance");
} catch (Exception e) {
Log.w(TAG, e);
}
} }
return null; return null;
} }
@ -171,6 +175,7 @@ public class CameraView extends FrameLayout {
camera.get()); camera.get());
final Parameters parameters = camera.get().getParameters(); final Parameters parameters = camera.get().getParameters();
if (preferredPreviewSize != null && !parameters.getPreviewSize().equals(preferredPreviewSize)) { if (preferredPreviewSize != null && !parameters.getPreviewSize().equals(preferredPreviewSize)) {
Log.w(TAG, "setting preview size to " + preferredPreviewSize.width + "x" + preferredPreviewSize.height);
stopPreview(); stopPreview();
parameters.setPreviewSize(preferredPreviewSize.width, preferredPreviewSize.height); parameters.setPreviewSize(preferredPreviewSize.width, preferredPreviewSize.height);
camera.get().setParameters(parameters); camera.get().setParameters(parameters);
@ -239,7 +244,6 @@ public class CameraView extends FrameLayout {
} }
} }
@TargetApi(14) @TargetApi(14)
private void onCameraReady() { private void onCameraReady() {
if (!camera.isPresent()) return; if (!camera.isPresent()) return;
@ -262,8 +266,8 @@ public class CameraView extends FrameLayout {
if (camera.isPresent()) { if (camera.isPresent()) {
try { try {
camera.get().setPreviewDisplay(surface.getHolder()); camera.get().setPreviewDisplay(surface.getHolder());
startPreview(); requestLayout();
} catch (IOException e) { } catch (Exception e) {
Log.w(TAG, e); Log.w(TAG, e);
} }
} }
@ -273,13 +277,21 @@ public class CameraView extends FrameLayout {
private void startPreview() { private void startPreview() {
if (camera.isPresent()) { if (camera.isPresent()) {
camera.get().startPreview(); try {
camera.get().startPreview();
} catch (Exception e) {
Log.w(TAG, e);
}
} }
} }
private void stopPreview() { private void stopPreview() {
if (camera.isPresent()) { if (camera.isPresent()) {
camera.get().stopPreview(); try {
camera.get().stopPreview();
} catch (Exception e) {
Log.w(TAG, e);
}
} }
} }
@ -304,8 +316,7 @@ public class CameraView extends FrameLayout {
if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) { if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
displayOrientation = (info.orientation + degrees ) % 360; displayOrientation = (info.orientation + degrees ) % 360;
displayOrientation = (360 - displayOrientation) % 360; displayOrientation = (360 - displayOrientation) % 360;
} } else {
else {
displayOrientation = (info.orientation - degrees + 360) % 360; displayOrientation = (info.orientation - degrees + 360) % 360;
} }
@ -401,7 +412,7 @@ public class CameraView extends FrameLayout {
Log.w(TAG, "previewFormat: " + camera.getParameters().getPreviewFormat()); Log.w(TAG, "previewFormat: " + camera.getParameters().getPreviewFormat());
Log.w(TAG, "croppingRect: " + croppingRect.toString()); Log.w(TAG, "croppingRect: " + croppingRect.toString());
Log.w(TAG, "rotation: " + rotation); Log.w(TAG, "rotation: " + rotation);
new RotatePreviewAsyncTask(previewSize, rotation, croppingRect).execute(data); new CaptureTask(previewSize, rotation, croppingRect).execute(data);
} }
}); });
} }
@ -430,7 +441,6 @@ public class CameraView extends FrameLayout {
return visibleRect; return visibleRect;
} }
@SuppressWarnings("SuspiciousNameCombination") @SuppressWarnings("SuspiciousNameCombination")
private void rotateRect(Rect rect) { private void rotateRect(Rect rect) {
rect.set(rect.top, rect.left, rect.bottom, rect.right); rect.set(rect.top, rect.left, rect.bottom, rect.right);
@ -495,12 +505,12 @@ public class CameraView extends FrameLayout {
} }
} }
private class RotatePreviewAsyncTask extends AsyncTask<byte[], Void, byte[]> { private class CaptureTask extends AsyncTask<byte[], Void, byte[]> {
private final Size previewSize; private final Size previewSize;
private final int rotation; private final int rotation;
private final Rect croppingRect; private final Rect croppingRect;
public RotatePreviewAsyncTask(Size previewSize, int rotation, Rect croppingRect) { public CaptureTask(Size previewSize, int rotation, Rect croppingRect) {
this.previewSize = previewSize; this.previewSize = previewSize;
this.rotation = rotation; this.rotation = rotation;
this.croppingRect = croppingRect; this.croppingRect = croppingRect;
@ -516,6 +526,7 @@ public class CameraView extends FrameLayout {
rotation, rotation,
croppingRect); croppingRect);
} catch (IOException e) { } catch (IOException e) {
Log.w(TAG, e);
return null; return null;
} }
} }