You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
605 lines
20 KiB
605 lines
20 KiB
package com.otaliastudios.cameraview.demo;
|
|
|
|
import android.graphics.Color;
|
|
import androidx.annotation.NonNull;
|
|
import androidx.core.util.Pair;
|
|
|
|
import android.graphics.ImageFormat;
|
|
import android.view.View;
|
|
import android.view.ViewGroup;
|
|
|
|
import com.otaliastudios.cameraview.CameraListener;
|
|
import com.otaliastudios.cameraview.CameraOptions;
|
|
import com.otaliastudios.cameraview.CameraView;
|
|
import com.otaliastudios.cameraview.controls.Control;
|
|
import com.otaliastudios.cameraview.gesture.Gesture;
|
|
import com.otaliastudios.cameraview.gesture.GestureAction;
|
|
import com.otaliastudios.cameraview.overlay.Overlay;
|
|
import com.otaliastudios.cameraview.overlay.OverlayLayout;
|
|
|
|
import java.util.ArrayList;
|
|
import java.util.Arrays;
|
|
import java.util.Collection;
|
|
import java.util.List;
|
|
|
|
/**
|
|
* Controls that we want to display in a ControlView.
|
|
*/
|
|
@SuppressWarnings("WeakerAccess")
|
|
public abstract class Option<T> {
|
|
|
|
private String name;
|
|
|
|
private Option(@NonNull String name) {
|
|
this.name = name;
|
|
}
|
|
|
|
@SuppressWarnings("WeakerAccess")
|
|
@NonNull
|
|
public final String getName() {
|
|
return name;
|
|
}
|
|
|
|
@NonNull
|
|
public abstract T get(@NonNull CameraView view);
|
|
|
|
@NonNull
|
|
public abstract Collection<T> getAll(@NonNull CameraView view, @NonNull CameraOptions options);
|
|
|
|
public abstract void set(@NonNull CameraView view, @NonNull T value);
|
|
|
|
@NonNull
|
|
public String toString(@NonNull T value) {
|
|
return String.valueOf(value).replace("_", " ").toLowerCase();
|
|
}
|
|
|
|
public static class Width extends Option<Integer> {
|
|
public Width() {
|
|
super("Width");
|
|
}
|
|
|
|
@NonNull
|
|
@Override
|
|
public Collection<Integer> getAll(@NonNull CameraView view, @NonNull CameraOptions options) {
|
|
View root = (View) view.getParent();
|
|
List<Integer> list = new ArrayList<>();
|
|
int boundary = root.getWidth();
|
|
if (boundary == 0) boundary = 1000;
|
|
int step = boundary / 10;
|
|
list.add(ViewGroup.LayoutParams.WRAP_CONTENT);
|
|
list.add(ViewGroup.LayoutParams.MATCH_PARENT);
|
|
for (int i = step; i < boundary; i += step) {
|
|
list.add(i);
|
|
}
|
|
return list;
|
|
}
|
|
|
|
@NonNull
|
|
@Override
|
|
public Integer get(@NonNull CameraView view) {
|
|
return view.getLayoutParams().width;
|
|
}
|
|
|
|
@Override
|
|
public void set(@NonNull CameraView view, @NonNull Integer value) {
|
|
view.getLayoutParams().width = (int) value;
|
|
view.setLayoutParams(view.getLayoutParams());
|
|
}
|
|
|
|
@NonNull
|
|
@Override
|
|
public String toString(@NonNull Integer value) {
|
|
if (value == ViewGroup.LayoutParams.MATCH_PARENT) return "match parent";
|
|
if (value == ViewGroup.LayoutParams.WRAP_CONTENT) return "wrap content";
|
|
return super.toString(value);
|
|
}
|
|
}
|
|
|
|
public static class Height extends Option<Integer> {
|
|
public Height() {
|
|
super("Height");
|
|
}
|
|
|
|
@NonNull
|
|
@Override
|
|
public Collection<Integer> getAll(@NonNull CameraView view, @NonNull CameraOptions options) {
|
|
View root = (View) view.getParent();
|
|
ArrayList<Integer> list = new ArrayList<>();
|
|
int boundary = root.getHeight();
|
|
if (boundary == 0) boundary = 1000;
|
|
int step = boundary / 10;
|
|
list.add(ViewGroup.LayoutParams.WRAP_CONTENT);
|
|
list.add(ViewGroup.LayoutParams.MATCH_PARENT);
|
|
for (int i = step; i < boundary; i += step) {
|
|
list.add(i);
|
|
}
|
|
return list;
|
|
}
|
|
|
|
@NonNull
|
|
@Override
|
|
public Integer get(@NonNull CameraView view) {
|
|
return view.getLayoutParams().height;
|
|
}
|
|
|
|
@Override
|
|
public void set(@NonNull CameraView view, @NonNull Integer value) {
|
|
view.getLayoutParams().height = (int) value;
|
|
view.setLayoutParams(view.getLayoutParams());
|
|
}
|
|
|
|
@NonNull
|
|
@Override
|
|
public String toString(@NonNull Integer value) {
|
|
if (value == ViewGroup.LayoutParams.MATCH_PARENT) return "match parent";
|
|
if (value == ViewGroup.LayoutParams.WRAP_CONTENT) return "wrap content";
|
|
return super.toString(value);
|
|
}
|
|
}
|
|
|
|
private static abstract class ControlOption<T extends Control> extends Option<T> {
|
|
private final Class<T> controlClass;
|
|
|
|
ControlOption(@NonNull Class<T> controlClass, String name) {
|
|
super(name);
|
|
this.controlClass = controlClass;
|
|
}
|
|
|
|
@Override
|
|
public void set(@NonNull CameraView view, @NonNull T value) {
|
|
view.set(value);
|
|
}
|
|
|
|
@NonNull
|
|
@Override
|
|
public T get(@NonNull CameraView view) {
|
|
return view.get(controlClass);
|
|
}
|
|
|
|
@NonNull
|
|
@Override
|
|
public Collection<T> getAll(@NonNull CameraView view, @NonNull CameraOptions options) {
|
|
return options.getSupportedControls(controlClass);
|
|
}
|
|
}
|
|
|
|
public static class Mode extends ControlOption<com.otaliastudios.cameraview.controls.Mode> {
|
|
public Mode() {
|
|
super(com.otaliastudios.cameraview.controls.Mode.class, "Mode");
|
|
}
|
|
}
|
|
|
|
public static class Engine extends ControlOption<com.otaliastudios.cameraview.controls.Engine> {
|
|
public Engine() {
|
|
super(com.otaliastudios.cameraview.controls.Engine.class, "Engine");
|
|
}
|
|
|
|
@Override
|
|
public void set(final @NonNull CameraView view, final @NonNull com.otaliastudios.cameraview.controls.Engine value) {
|
|
boolean started = view.isOpened();
|
|
if (started) {
|
|
view.addCameraListener(new CameraListener() {
|
|
@Override
|
|
public void onCameraClosed() {
|
|
super.onCameraClosed();
|
|
view.removeCameraListener(this);
|
|
view.setEngine(value);
|
|
view.open();
|
|
}
|
|
});
|
|
view.close();
|
|
} else {
|
|
view.setEngine(value);
|
|
}
|
|
}
|
|
}
|
|
|
|
public static class Preview extends ControlOption<com.otaliastudios.cameraview.controls.Preview> {
|
|
public Preview() {
|
|
super(com.otaliastudios.cameraview.controls.Preview.class, "Preview Surface");
|
|
}
|
|
|
|
@Override
|
|
public void set(final @NonNull CameraView view, final @NonNull com.otaliastudios.cameraview.controls.Preview value) {
|
|
boolean opened = view.isOpened();
|
|
if (opened) {
|
|
view.addCameraListener(new CameraListener() {
|
|
@Override
|
|
public void onCameraClosed() {
|
|
super.onCameraClosed();
|
|
view.removeCameraListener(this);
|
|
applyPreview(view, value);
|
|
view.open();
|
|
}
|
|
});
|
|
view.close();
|
|
} else {
|
|
applyPreview(view, value);
|
|
}
|
|
}
|
|
|
|
// This is really tricky since the preview can only be changed when not attached to window.
|
|
private void applyPreview(@NonNull CameraView cameraView,
|
|
@NonNull com.otaliastudios.cameraview.controls.Preview newPreview) {
|
|
ViewGroup.LayoutParams params = cameraView.getLayoutParams();
|
|
ViewGroup parent = (ViewGroup) cameraView.getParent();
|
|
int index = 0;
|
|
for (int i = 0; i < parent.getChildCount(); i++) {
|
|
if (parent.getChildAt(i) == cameraView) {
|
|
index = i;
|
|
break;
|
|
}
|
|
}
|
|
parent.removeView(cameraView);
|
|
cameraView.setPreview(newPreview);
|
|
parent.addView(cameraView, index, params);
|
|
}
|
|
}
|
|
|
|
public static class Flash extends ControlOption<com.otaliastudios.cameraview.controls.Flash> {
|
|
public Flash() {
|
|
super(com.otaliastudios.cameraview.controls.Flash.class, "Flash");
|
|
}
|
|
}
|
|
|
|
public static class WhiteBalance extends ControlOption<com.otaliastudios.cameraview.controls.WhiteBalance> {
|
|
public WhiteBalance() {
|
|
super(com.otaliastudios.cameraview.controls.WhiteBalance.class, "White Balance");
|
|
}
|
|
}
|
|
|
|
public static class Hdr extends ControlOption<com.otaliastudios.cameraview.controls.Hdr> {
|
|
public Hdr() {
|
|
super(com.otaliastudios.cameraview.controls.Hdr.class, "HDR");
|
|
}
|
|
}
|
|
|
|
public static class PictureMetering extends Option<Boolean> {
|
|
|
|
public PictureMetering() {
|
|
super("Picture Metering");
|
|
}
|
|
|
|
@NonNull
|
|
@Override
|
|
public Boolean get(@NonNull CameraView view) {
|
|
return view.getPictureMetering();
|
|
}
|
|
|
|
@NonNull
|
|
@Override
|
|
public Collection<Boolean> getAll(@NonNull CameraView view, @NonNull CameraOptions options) {
|
|
return Arrays.asList(true, false);
|
|
}
|
|
|
|
@Override
|
|
public void set(@NonNull CameraView view, @NonNull Boolean value) {
|
|
view.setPictureMetering(value);
|
|
}
|
|
}
|
|
|
|
public static class PictureSnapshotMetering extends Option<Boolean> {
|
|
|
|
public PictureSnapshotMetering() {
|
|
super("Picture Snapshot Metering");
|
|
}
|
|
|
|
@NonNull
|
|
@Override
|
|
public Boolean get(@NonNull CameraView view) {
|
|
return view.getPictureSnapshotMetering();
|
|
}
|
|
|
|
@NonNull
|
|
@Override
|
|
public Collection<Boolean> getAll(@NonNull CameraView view, @NonNull CameraOptions options) {
|
|
return Arrays.asList(true, false);
|
|
}
|
|
|
|
@Override
|
|
public void set(@NonNull CameraView view, @NonNull Boolean value) {
|
|
view.setPictureSnapshotMetering(value);
|
|
}
|
|
}
|
|
|
|
public static class VideoCodec extends ControlOption<com.otaliastudios.cameraview.controls.VideoCodec> {
|
|
public VideoCodec() {
|
|
super(com.otaliastudios.cameraview.controls.VideoCodec.class, "Video Codec");
|
|
}
|
|
}
|
|
|
|
public static class AudioCodec extends ControlOption<com.otaliastudios.cameraview.controls.AudioCodec> {
|
|
public AudioCodec() {
|
|
super(com.otaliastudios.cameraview.controls.AudioCodec.class, "Audio Codec");
|
|
}
|
|
}
|
|
|
|
public static class Audio extends ControlOption<com.otaliastudios.cameraview.controls.Audio> {
|
|
public Audio() {
|
|
super(com.otaliastudios.cameraview.controls.Audio.class, "Audio");
|
|
}
|
|
}
|
|
|
|
private static abstract class GestureOption extends Option<GestureAction> {
|
|
private final Gesture gesture;
|
|
private final GestureAction[] allActions = GestureAction.values();
|
|
|
|
GestureOption(@NonNull Gesture gesture, String name) {
|
|
super(name);
|
|
this.gesture = gesture;
|
|
}
|
|
|
|
@Override
|
|
public void set(@NonNull CameraView view, @NonNull GestureAction value) {
|
|
view.mapGesture(gesture, value);
|
|
}
|
|
|
|
@NonNull
|
|
@Override
|
|
public GestureAction get(@NonNull CameraView view) {
|
|
return view.getGestureAction(gesture);
|
|
}
|
|
|
|
@NonNull
|
|
@Override
|
|
public Collection<GestureAction> getAll(@NonNull CameraView view, @NonNull CameraOptions options) {
|
|
List<GestureAction> list = new ArrayList<>();
|
|
for (GestureAction action : allActions) {
|
|
if (gesture.isAssignableTo(action) && options.supports(action)) {
|
|
list.add(action);
|
|
}
|
|
}
|
|
return list;
|
|
}
|
|
}
|
|
|
|
public static class Pinch extends GestureOption {
|
|
public Pinch() {
|
|
super(Gesture.PINCH, "Pinch");
|
|
}
|
|
}
|
|
|
|
public static class HorizontalScroll extends GestureOption {
|
|
public HorizontalScroll() {
|
|
super(Gesture.SCROLL_HORIZONTAL, "Horizontal Scroll");
|
|
}
|
|
}
|
|
|
|
public static class VerticalScroll extends GestureOption {
|
|
public VerticalScroll() {
|
|
super(Gesture.SCROLL_VERTICAL, "Vertical Scroll");
|
|
}
|
|
}
|
|
|
|
public static class Tap extends GestureOption {
|
|
public Tap() {
|
|
super(Gesture.TAP, "Tap");
|
|
}
|
|
}
|
|
|
|
public static class LongTap extends GestureOption {
|
|
public LongTap() {
|
|
super(Gesture.LONG_TAP, "Long Tap");
|
|
}
|
|
}
|
|
|
|
private static abstract class OverlayOption extends Option<Boolean> {
|
|
private View overlay;
|
|
private Overlay.Target target;
|
|
|
|
OverlayOption(@NonNull Overlay.Target target, @NonNull String name, @NonNull View overlay) {
|
|
super(name);
|
|
this.overlay = overlay;
|
|
this.target = target;
|
|
}
|
|
|
|
@NonNull
|
|
@Override
|
|
public Collection<Boolean> getAll(@NonNull CameraView view, @NonNull CameraOptions options) {
|
|
return Arrays.asList(true, false);
|
|
}
|
|
|
|
@NonNull
|
|
@Override
|
|
public Boolean get(@NonNull CameraView view) {
|
|
OverlayLayout.LayoutParams params = (OverlayLayout.LayoutParams) overlay.getLayoutParams();
|
|
switch (target) {
|
|
case PREVIEW: return params.drawOnPreview;
|
|
case PICTURE_SNAPSHOT: return params.drawOnPictureSnapshot;
|
|
case VIDEO_SNAPSHOT: return params.drawOnVideoSnapshot;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
@Override
|
|
public void set(@NonNull CameraView view, @NonNull Boolean value) {
|
|
OverlayLayout.LayoutParams params = (OverlayLayout.LayoutParams) overlay.getLayoutParams();
|
|
switch (target) {
|
|
case PREVIEW: params.drawOnPreview = value; break;
|
|
case PICTURE_SNAPSHOT: params.drawOnPictureSnapshot = value; break;
|
|
case VIDEO_SNAPSHOT: params.drawOnVideoSnapshot = value; break;
|
|
}
|
|
overlay.setLayoutParams(params);
|
|
}
|
|
}
|
|
|
|
public static class OverlayInPreview extends OverlayOption {
|
|
public OverlayInPreview(@NonNull View overlay) {
|
|
super(Overlay.Target.PREVIEW, "Overlay in Preview", overlay);
|
|
}
|
|
}
|
|
|
|
public static class OverlayInPictureSnapshot extends OverlayOption {
|
|
public OverlayInPictureSnapshot(@NonNull View overlay) {
|
|
super(Overlay.Target.PICTURE_SNAPSHOT, "Overlay in Picture Snapshot", overlay);
|
|
}
|
|
}
|
|
|
|
public static class OverlayInVideoSnapshot extends OverlayOption {
|
|
public OverlayInVideoSnapshot(@NonNull View overlay) {
|
|
super(Overlay.Target.VIDEO_SNAPSHOT, "Overlay in Video Snapshot", overlay);
|
|
}
|
|
}
|
|
|
|
public static class Grid extends ControlOption<com.otaliastudios.cameraview.controls.Grid> {
|
|
public Grid() {
|
|
super(com.otaliastudios.cameraview.controls.Grid.class, "Grid Lines");
|
|
}
|
|
}
|
|
|
|
public static class GridColor extends Option<Pair<Integer, String>> {
|
|
|
|
public GridColor() {
|
|
super("Grid Color");
|
|
}
|
|
|
|
private static final List<Pair<Integer, String>> ALL = Arrays.asList(
|
|
new Pair<>(Color.argb(160, 255, 255, 255), "default"),
|
|
new Pair<>(Color.WHITE, "white"),
|
|
new Pair<>(Color.BLACK, "black"),
|
|
new Pair<>(Color.YELLOW, "yellow")
|
|
);
|
|
|
|
@NonNull
|
|
@Override
|
|
public Collection<Pair<Integer, String>> getAll(@NonNull CameraView view, @NonNull CameraOptions options) {
|
|
return ALL;
|
|
}
|
|
|
|
@NonNull
|
|
@Override
|
|
public Pair<Integer, String> get(@NonNull CameraView view) {
|
|
for (Pair<Integer, String> pair : ALL) {
|
|
//noinspection ConstantConditions
|
|
if (pair.first == view.getGridColor()) {
|
|
return pair;
|
|
}
|
|
}
|
|
throw new RuntimeException("Could not find grid color");
|
|
}
|
|
|
|
@Override
|
|
public void set(@NonNull CameraView view, @NonNull Pair<Integer, String> value) {
|
|
//noinspection ConstantConditions
|
|
view.setGridColor(value.first);
|
|
}
|
|
|
|
@NonNull
|
|
@Override
|
|
public String toString(@NonNull Pair<Integer, String> value) {
|
|
//noinspection ConstantConditions
|
|
return value.second;
|
|
}
|
|
}
|
|
|
|
public static class UseDeviceOrientation extends Option<Boolean> {
|
|
public UseDeviceOrientation() {
|
|
super("Use Device Orientation");
|
|
}
|
|
|
|
@NonNull
|
|
@Override
|
|
public Collection<Boolean> getAll(@NonNull CameraView view, @NonNull CameraOptions options) {
|
|
return Arrays.asList(true, false);
|
|
}
|
|
|
|
@NonNull
|
|
@Override
|
|
public Boolean get(@NonNull CameraView view) {
|
|
return view.getUseDeviceOrientation();
|
|
}
|
|
|
|
@Override
|
|
public void set(@NonNull CameraView view, @NonNull Boolean value) {
|
|
view.setUseDeviceOrientation(value);
|
|
}
|
|
}
|
|
|
|
public static class PreviewFrameRate extends Option<Integer> {
|
|
public PreviewFrameRate() {
|
|
super("Preview FPS");
|
|
}
|
|
|
|
@NonNull
|
|
@Override
|
|
public Collection<Integer> getAll(@NonNull CameraView view, @NonNull CameraOptions options) {
|
|
float min = options.getPreviewFrameRateMinValue();
|
|
float max = options.getPreviewFrameRateMaxValue();
|
|
float delta = max - min;
|
|
List<Integer> result = new ArrayList<>();
|
|
if (min == 0F && max == 0F) {
|
|
return result; // empty list
|
|
} else if (delta < 0.005F) {
|
|
result.add(Math.round(min));
|
|
return result; // single value
|
|
} else {
|
|
final int steps = 3;
|
|
final float step = delta / steps;
|
|
for (int i = 0; i <= steps; i++) {
|
|
result.add(Math.round(min));
|
|
min += step;
|
|
}
|
|
return result;
|
|
}
|
|
}
|
|
|
|
@NonNull
|
|
@Override
|
|
public Integer get(@NonNull CameraView view) {
|
|
return Math.round(view.getPreviewFrameRate());
|
|
}
|
|
|
|
@Override
|
|
public void set(@NonNull CameraView view, @NonNull Integer value) {
|
|
view.setPreviewFrameRate((float) value);
|
|
}
|
|
}
|
|
|
|
public static class PictureFormat extends ControlOption<com.otaliastudios.cameraview.controls.PictureFormat> {
|
|
public PictureFormat() {
|
|
super(com.otaliastudios.cameraview.controls.PictureFormat.class, "Picture Format");
|
|
}
|
|
}
|
|
|
|
public static class FrameProcessingFormat extends Option<Integer> {
|
|
|
|
FrameProcessingFormat() {
|
|
super("Frame Processing Format");
|
|
}
|
|
|
|
@Override
|
|
public void set(@NonNull CameraView view, @NonNull Integer value) {
|
|
view.setFrameProcessingFormat(value);
|
|
}
|
|
|
|
@NonNull
|
|
@Override
|
|
public Integer get(@NonNull CameraView view) {
|
|
return view.getFrameProcessingFormat();
|
|
}
|
|
|
|
@NonNull
|
|
@Override
|
|
public Collection<Integer> getAll(@NonNull CameraView view, @NonNull CameraOptions options) {
|
|
return options.getSupportedFrameProcessingFormats();
|
|
}
|
|
|
|
@NonNull
|
|
@Override
|
|
public String toString(@NonNull Integer value) {
|
|
switch (value) {
|
|
case ImageFormat.NV21: return "NV21";
|
|
case ImageFormat.NV16: return "NV16";
|
|
case ImageFormat.JPEG: return "JPEG";
|
|
case ImageFormat.YUY2: return "YUY2";
|
|
case ImageFormat.YUV_420_888: return "YUV_420_888";
|
|
case ImageFormat.YUV_422_888: return "YUV_422_888";
|
|
case ImageFormat.YUV_444_888: return "YUV_444_888";
|
|
case ImageFormat.RAW10: return "RAW10";
|
|
case ImageFormat.RAW12: return "RAW12";
|
|
case ImageFormat.RAW_SENSOR: return "RAW_SENSOR";
|
|
}
|
|
return super.toString(value);
|
|
}
|
|
}
|
|
}
|
|
|