mirror of
https://github.com/oxen-io/session-android.git
synced 2024-11-27 20:15:21 +00:00
update camera preview strategy
// FREEBIE
This commit is contained in:
parent
7817c7697e
commit
4e8e8978f4
@ -3,6 +3,7 @@ package org.thoughtcrime.securesms.components.camera;
|
|||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
import android.hardware.Camera;
|
import android.hardware.Camera;
|
||||||
import android.hardware.Camera.CameraInfo;
|
import android.hardware.Camera.CameraInfo;
|
||||||
|
import android.hardware.Camera.Parameters;
|
||||||
import android.hardware.Camera.Size;
|
import android.hardware.Camera.Size;
|
||||||
import android.support.annotation.NonNull;
|
import android.support.annotation.NonNull;
|
||||||
import android.support.annotation.Nullable;
|
import android.support.annotation.Nullable;
|
||||||
@ -12,40 +13,46 @@ import android.view.Surface;
|
|||||||
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@SuppressWarnings("deprecation")
|
@SuppressWarnings("deprecation")
|
||||||
public class CameraUtils {
|
public class CameraUtils {
|
||||||
|
private static final String TAG = CameraUtils.class.getSimpleName();
|
||||||
/*
|
/*
|
||||||
* 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 getPreferredPreviewSize(int displayOrientation,
|
public static @Nullable Size getPreferredPreviewSize(int displayOrientation,
|
||||||
int width,
|
int width,
|
||||||
int height,
|
int height,
|
||||||
@NonNull Camera camera) {
|
@NonNull Parameters parameters) {
|
||||||
Log.w("CameraUtils", String.format("getPreferredPreviewSize(%d, %d, %d)", displayOrientation, width, height));
|
final int targetWidth = displayOrientation % 180 == 90 ? height : width;
|
||||||
double targetRatio = (double)width / height;
|
final int targetHeight = displayOrientation % 180 == 90 ? width : height;
|
||||||
Size optimalSize = null;
|
final double targetRatio = (double) targetWidth / targetHeight;
|
||||||
double minDiff = Double.MAX_VALUE;
|
|
||||||
|
|
||||||
if (displayOrientation == 90 || displayOrientation == 270) {
|
Log.w(TAG, String.format("getPreferredPreviewSize(%d, %d, %d) -> target %dx%d, AR %.02f",
|
||||||
targetRatio = (double)height / width;
|
displayOrientation, width, height,
|
||||||
}
|
targetWidth, targetHeight, targetRatio));
|
||||||
|
|
||||||
List<Size> sizes = camera.getParameters().getSupportedPreviewSizes();
|
List<Size> sizes = parameters.getSupportedPreviewSizes();
|
||||||
|
List<Size> ideals = new LinkedList<>();
|
||||||
Collections.sort(sizes, Collections.reverseOrder(new SizeComparator()));
|
List<Size> bigEnough = new LinkedList<>();
|
||||||
|
|
||||||
for (Size size : sizes) {
|
for (Size size : sizes) {
|
||||||
double ratio = (double)size.width / size.height;
|
Log.w(TAG, String.format(" %dx%d (%.02f)", size.width, size.height, (float)size.width / size.height));
|
||||||
|
|
||||||
if (Math.abs(ratio - targetRatio) < minDiff) {
|
if (size.height == size.width * targetRatio && size.height >= targetHeight && size.width >= targetWidth) {
|
||||||
optimalSize = size;
|
ideals.add(size);
|
||||||
minDiff = Math.abs(ratio - targetRatio);
|
Log.w(TAG, " (ideal ratio)");
|
||||||
|
} else if (size.width >= targetWidth && size.height >= targetHeight) {
|
||||||
|
bigEnough.add(size);
|
||||||
|
Log.w(TAG, " (good size, suboptimal ratio)");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return optimalSize;
|
if (!ideals.isEmpty()) return Collections.min(ideals, new AreaComparator());
|
||||||
|
else if (!bigEnough.isEmpty()) return Collections.min(bigEnough, new AspectRatioComparator(targetRatio));
|
||||||
|
else return Collections.max(sizes, new AreaComparator());
|
||||||
}
|
}
|
||||||
|
|
||||||
// based on
|
// based on
|
||||||
@ -74,15 +81,26 @@ public class CameraUtils {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class SizeComparator implements Comparator<Size> {
|
private static class AreaComparator implements Comparator<Size> {
|
||||||
@Override
|
@Override
|
||||||
public int compare(Size lhs, Size rhs) {
|
public int compare(Size lhs, Size rhs) {
|
||||||
int left = lhs.width * lhs.height;
|
return Long.signum(lhs.width * lhs.height - rhs.width * rhs.height);
|
||||||
int right = rhs.width * rhs.height;
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (left < right) return -1;
|
private static class AspectRatioComparator extends AreaComparator {
|
||||||
if (left > right) return 1;
|
private final double target;
|
||||||
else return 0;
|
public AspectRatioComparator(double target) {
|
||||||
|
this.target = target;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int compare(Size lhs, Size rhs) {
|
||||||
|
final double lhsDiff = Math.abs(target - (double) lhs.width / lhs.height);
|
||||||
|
final double rhsDiff = Math.abs(target - (double) rhs.width / rhs.height);
|
||||||
|
if (lhsDiff < rhsDiff) return -1;
|
||||||
|
else if (lhsDiff > rhsDiff) return 1;
|
||||||
|
else return super.compare(lhs, rhs);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -58,7 +58,8 @@ public class CameraView extends FrameLayout {
|
|||||||
private @NonNull volatile Optional<Camera> camera = Optional.absent();
|
private @NonNull volatile Optional<Camera> camera = Optional.absent();
|
||||||
private volatile int cameraId = CameraInfo.CAMERA_FACING_BACK;
|
private volatile int cameraId = CameraInfo.CAMERA_FACING_BACK;
|
||||||
|
|
||||||
private boolean started;
|
private @NonNull State state = State.PAUSED;
|
||||||
|
private @Nullable Size previewSize;
|
||||||
private @Nullable CameraViewListener listener;
|
private @Nullable CameraViewListener listener;
|
||||||
private int displayOrientation = -1;
|
private int displayOrientation = -1;
|
||||||
private int outputOrientation = -1;
|
private int outputOrientation = -1;
|
||||||
@ -92,8 +93,8 @@ public class CameraView extends FrameLayout {
|
|||||||
|
|
||||||
@TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)
|
@TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)
|
||||||
public void onResume() {
|
public void onResume() {
|
||||||
if (started) return;
|
if (state != State.PAUSED) return;
|
||||||
started = true;
|
state = State.RESUMED;
|
||||||
Log.w(TAG, "onResume() queued");
|
Log.w(TAG, "onResume() queued");
|
||||||
enqueueTask(new SerialAsyncTask<Camera>() {
|
enqueueTask(new SerialAsyncTask<Camera>() {
|
||||||
@Override
|
@Override
|
||||||
@ -125,8 +126,6 @@ public class CameraView extends FrameLayout {
|
|||||||
synchronized (CameraView.this) {
|
synchronized (CameraView.this) {
|
||||||
CameraView.this.notifyAll();
|
CameraView.this.notifyAll();
|
||||||
}
|
}
|
||||||
requestLayout();
|
|
||||||
invalidate();
|
|
||||||
Log.w(TAG, "onResume() completed");
|
Log.w(TAG, "onResume() completed");
|
||||||
} catch (RuntimeException e) {
|
} catch (RuntimeException e) {
|
||||||
Log.w(TAG, "exception when starting camera preview", e);
|
Log.w(TAG, "exception when starting camera preview", e);
|
||||||
@ -137,8 +136,8 @@ public class CameraView extends FrameLayout {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void onPause() {
|
public void onPause() {
|
||||||
if (!started) return;
|
if (state == State.PAUSED) return;
|
||||||
started = false;
|
state = State.PAUSED;
|
||||||
Log.w(TAG, "onPause() queued");
|
Log.w(TAG, "onPause() queued");
|
||||||
|
|
||||||
enqueueTask(new SerialAsyncTask<Void>() {
|
enqueueTask(new SerialAsyncTask<Void>() {
|
||||||
@ -175,28 +174,7 @@ public class CameraView extends FrameLayout {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public boolean isStarted() {
|
public boolean isStarted() {
|
||||||
return started;
|
return state != State.PAUSED;
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
|
||||||
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
|
|
||||||
|
|
||||||
if (getMeasuredWidth() > 0 && getMeasuredHeight() > 0 && camera.isPresent()) {
|
|
||||||
final Size preferredPreviewSize = CameraUtils.getPreferredPreviewSize(displayOrientation,
|
|
||||||
getMeasuredWidth(),
|
|
||||||
getMeasuredHeight(),
|
|
||||||
camera.get());
|
|
||||||
final Parameters parameters = camera.get().getParameters();
|
|
||||||
if (preferredPreviewSize != null && !parameters.getPreviewSize().equals(preferredPreviewSize)) {
|
|
||||||
Log.w(TAG, "setting preview size to " + preferredPreviewSize.width + "x" + preferredPreviewSize.height);
|
|
||||||
stopPreview();
|
|
||||||
parameters.setPreviewSize(preferredPreviewSize.width, preferredPreviewSize.height);
|
|
||||||
camera.get().setParameters(parameters);
|
|
||||||
requestLayout();
|
|
||||||
startPreview();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("SuspiciousNameCombination")
|
@SuppressWarnings("SuspiciousNameCombination")
|
||||||
@ -207,8 +185,7 @@ public class CameraView extends FrameLayout {
|
|||||||
final int previewWidth;
|
final int previewWidth;
|
||||||
final int previewHeight;
|
final int previewHeight;
|
||||||
|
|
||||||
if (camera.isPresent()) {
|
if (camera.isPresent() && previewSize != null) {
|
||||||
final Size previewSize = camera.get().getParameters().getPreviewSize();
|
|
||||||
if (displayOrientation == 90 || displayOrientation == 270) {
|
if (displayOrientation == 90 || displayOrientation == 270) {
|
||||||
previewWidth = previewSize.height;
|
previewWidth = previewSize.height;
|
||||||
previewHeight = previewSize.width;
|
previewHeight = previewSize.width;
|
||||||
@ -225,7 +202,6 @@ public class CameraView extends FrameLayout {
|
|||||||
Log.w(TAG, "skipping layout due to zero-width/height preview size");
|
Log.w(TAG, "skipping layout due to zero-width/height preview size");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Log.w(TAG, "layout " + width + "x" + height + ", target " + previewWidth + "x" + previewHeight);
|
|
||||||
|
|
||||||
if (width * previewHeight > height * previewWidth) {
|
if (width * previewHeight > height * previewWidth) {
|
||||||
final int scaledChildHeight = previewHeight * width / previewWidth;
|
final int scaledChildHeight = previewHeight * width / previewWidth;
|
||||||
@ -236,11 +212,18 @@ public class CameraView extends FrameLayout {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
|
||||||
|
Log.w(TAG, "onSizeChanged(" + oldw + "x" + oldh + " -> " + w + "x" + h + ")");
|
||||||
|
super.onSizeChanged(w, h, oldw, oldh);
|
||||||
|
if (camera.isPresent()) startPreview(camera.get().getParameters());
|
||||||
|
}
|
||||||
|
|
||||||
public void setListener(@Nullable CameraViewListener listener) {
|
public void setListener(@Nullable CameraViewListener listener) {
|
||||||
this.listener = listener;
|
this.listener = listener;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setPreviewCallback(final PreviewCallback previewCallback) {
|
public void setPreviewCallback(final @NonNull PreviewCallback previewCallback) {
|
||||||
enqueueTask(new PostInitializationTask<Void>() {
|
enqueueTask(new PostInitializationTask<Void>() {
|
||||||
@Override
|
@Override
|
||||||
protected void onPostMain(Void avoid) {
|
protected void onPostMain(Void avoid) {
|
||||||
@ -308,6 +291,7 @@ public class CameraView extends FrameLayout {
|
|||||||
if (camera.isPresent()) {
|
if (camera.isPresent()) {
|
||||||
try {
|
try {
|
||||||
camera.get().setPreviewDisplay(surface.getHolder());
|
camera.get().setPreviewDisplay(surface.getHolder());
|
||||||
|
startPreview(parameters);
|
||||||
requestLayout();
|
requestLayout();
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
Log.w(TAG, e);
|
Log.w(TAG, e);
|
||||||
@ -317,10 +301,24 @@ public class CameraView extends FrameLayout {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private void startPreview() {
|
private void startPreview(final @NonNull Parameters parameters) {
|
||||||
if (camera.isPresent()) {
|
if (this.camera.isPresent()) {
|
||||||
try {
|
try {
|
||||||
camera.get().startPreview();
|
final Camera camera = this.camera.get();
|
||||||
|
final Size preferredPreviewSize = getPreferredPreviewSize(parameters);
|
||||||
|
|
||||||
|
if (preferredPreviewSize != null && !parameters.getPreviewSize().equals(preferredPreviewSize)) {
|
||||||
|
Log.w(TAG, "starting preview with size " + preferredPreviewSize.width + "x" + preferredPreviewSize.height);
|
||||||
|
if (state == State.ACTIVE) stopPreview();
|
||||||
|
previewSize = preferredPreviewSize;
|
||||||
|
parameters.setPreviewSize(preferredPreviewSize.width, preferredPreviewSize.height);
|
||||||
|
camera.setParameters(parameters);
|
||||||
|
} else {
|
||||||
|
previewSize = parameters.getPreviewSize();
|
||||||
|
}
|
||||||
|
camera.startPreview();
|
||||||
|
requestLayout();
|
||||||
|
state = State.ACTIVE;
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
Log.w(TAG, e);
|
Log.w(TAG, e);
|
||||||
}
|
}
|
||||||
@ -331,13 +329,21 @@ public class CameraView extends FrameLayout {
|
|||||||
if (camera.isPresent()) {
|
if (camera.isPresent()) {
|
||||||
try {
|
try {
|
||||||
camera.get().stopPreview();
|
camera.get().stopPreview();
|
||||||
|
state = State.RESUMED;
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
Log.w(TAG, e);
|
Log.w(TAG, e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getCameraPictureOrientation() {
|
private Size getPreferredPreviewSize(@NonNull Parameters parameters) {
|
||||||
|
return CameraUtils.getPreferredPreviewSize(displayOrientation,
|
||||||
|
getMeasuredWidth(),
|
||||||
|
getMeasuredHeight(),
|
||||||
|
parameters);
|
||||||
|
}
|
||||||
|
|
||||||
|
private int getCameraPictureOrientation() {
|
||||||
if (getActivity().getRequestedOrientation() != ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED) {
|
if (getActivity().getRequestedOrientation() != ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED) {
|
||||||
outputOrientation = getCameraPictureRotation(getActivity().getWindowManager()
|
outputOrientation = getCameraPictureRotation(getActivity().getWindowManager()
|
||||||
.getDefaultDisplay()
|
.getDefaultDisplay()
|
||||||
@ -589,4 +595,8 @@ public class CameraView extends FrameLayout {
|
|||||||
return orientation;
|
return orientation;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private enum State {
|
||||||
|
PAUSED, RESUMED, ACTIVE
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user