Demo app changes

pull/499/head
Mattia Iavarone 6 years ago
parent dc31c40dd9
commit c0c450bbd2
  1. 34
      cameraview/src/main/java/com/otaliastudios/cameraview/CameraView.java
  2. 22
      demo/src/main/java/com/otaliastudios/cameraview/demo/CameraActivity.java
  3. 274
      demo/src/main/java/com/otaliastudios/cameraview/demo/Control.java
  4. 2
      demo/src/main/java/com/otaliastudios/cameraview/demo/MessageView.java
  5. 444
      demo/src/main/java/com/otaliastudios/cameraview/demo/Option.java
  6. 44
      demo/src/main/java/com/otaliastudios/cameraview/demo/OptionView.java
  7. 0
      demo/src/main/res/layout/option_view.xml

@ -769,6 +769,40 @@ public class CameraView extends FrameLayout implements LifecycleObserver {
} }
} }
/**
* Shorthand for the appropriate get* method.
* For example, if control class is a {@link Grid}, this calls {@link #getGrid()}.
*
* @param controlClass desired value class
*/
@SuppressWarnings("unchecked")
@NonNull
public <T extends Control> T get(@NonNull Class<T> controlClass) {
if (controlClass == Audio.class) {
return (T) getAudio();
} else if (controlClass == Facing.class) {
return (T) getFacing();
} else if (controlClass == Flash.class) {
return (T) getFlash();
} else if (controlClass == Grid.class) {
return (T) getGrid();
} else if (controlClass == Hdr.class) {
return (T) getHdr();
} else if (controlClass == Mode.class) {
return (T) getMode();
} else if (controlClass == WhiteBalance.class) {
return (T) getWhiteBalance();
} else if (controlClass == VideoCodec.class) {
return (T) getVideoCodec();
} else if (controlClass == Preview.class) {
return (T) getPreview();
} else if (controlClass == Engine.class) {
return (T) getEngine();
} else {
throw new IllegalArgumentException("Unknown control class: " + controlClass);
}
}
/** /**
* Controls the preview engine. Should only be called * Controls the preview engine. Should only be called

@ -22,14 +22,12 @@ import com.otaliastudios.cameraview.PictureResult;
import com.otaliastudios.cameraview.controls.Mode; import com.otaliastudios.cameraview.controls.Mode;
import com.otaliastudios.cameraview.VideoResult; import com.otaliastudios.cameraview.VideoResult;
import com.otaliastudios.cameraview.controls.Preview; import com.otaliastudios.cameraview.controls.Preview;
import com.otaliastudios.cameraview.frame.Frame;
import com.otaliastudios.cameraview.frame.FrameProcessor;
import com.otaliastudios.cameraview.size.SizeSelectors;
import java.io.File; import java.io.File;
import java.util.List;
public class CameraActivity extends AppCompatActivity implements View.OnClickListener, ControlView.Callback { public class CameraActivity extends AppCompatActivity implements View.OnClickListener, OptionView.Callback {
private CameraView camera; private CameraView camera;
private ViewGroup controlPanel; private ViewGroup controlPanel;
@ -67,9 +65,9 @@ public class CameraActivity extends AppCompatActivity implements View.OnClickLis
controlPanel = findViewById(R.id.controls); controlPanel = findViewById(R.id.controls);
ViewGroup group = (ViewGroup) controlPanel.getChildAt(0); ViewGroup group = (ViewGroup) controlPanel.getChildAt(0);
Control[] controls = Control.values(); List<Option<?>> options = Option.getAll();
for (Control control : controls) { for (Option option : options) {
ControlView view = new ControlView(this, control, this); OptionView view = new OptionView(this, option, this);
group.addView(view, group.addView(view,
ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT); ViewGroup.LayoutParams.WRAP_CONTENT);
@ -95,7 +93,7 @@ public class CameraActivity extends AppCompatActivity implements View.OnClickLis
public void onCameraOpened(@NonNull CameraOptions options) { public void onCameraOpened(@NonNull CameraOptions options) {
ViewGroup group = (ViewGroup) controlPanel.getChildAt(0); ViewGroup group = (ViewGroup) controlPanel.getChildAt(0);
for (int i = 0; i < group.getChildCount(); i++) { for (int i = 0; i < group.getChildCount(); i++) {
ControlView view = (ControlView) group.getChildAt(i); OptionView view = (OptionView) group.getChildAt(i);
view.onCameraOpened(camera, options); view.onCameraOpened(camera, options);
} }
} }
@ -220,8 +218,8 @@ public class CameraActivity extends AppCompatActivity implements View.OnClickLis
} }
@Override @Override
public boolean onValueChanged(Control control, Object value, String name) { public <T> boolean onValueChanged(@NonNull Option<T> option, @NonNull T value, @NonNull String name) {
if ((control == Control.WIDTH || control == Control.HEIGHT)) { if ((option instanceof Option.Width || option instanceof Option.Height)) {
Preview preview = camera.getPreview(); Preview preview = camera.getPreview();
boolean wrapContent = (Integer) value == ViewGroup.LayoutParams.WRAP_CONTENT; boolean wrapContent = (Integer) value == ViewGroup.LayoutParams.WRAP_CONTENT;
if (preview == Preview.SURFACE && !wrapContent) { if (preview == Preview.SURFACE && !wrapContent) {
@ -230,10 +228,10 @@ public class CameraActivity extends AppCompatActivity implements View.OnClickLis
return false; return false;
} }
} }
control.applyValue(camera, value); option.set(camera, value);
BottomSheetBehavior b = BottomSheetBehavior.from(controlPanel); BottomSheetBehavior b = BottomSheetBehavior.from(controlPanel);
b.setState(BottomSheetBehavior.STATE_HIDDEN); b.setState(BottomSheetBehavior.STATE_HIDDEN);
message("Changed " + control.getName() + " to " + name, false); message("Changed " + option.getName() + " to " + name, false);
return true; return true;
} }

@ -1,274 +0,0 @@
package com.otaliastudios.cameraview.demo;
import android.graphics.Color;
import androidx.annotation.NonNull;
import android.view.View;
import android.view.ViewGroup;
import com.otaliastudios.cameraview.CameraListener;
import com.otaliastudios.cameraview.controls.Audio;
import com.otaliastudios.cameraview.CameraOptions;
import com.otaliastudios.cameraview.CameraView;
import com.otaliastudios.cameraview.controls.Engine;
import com.otaliastudios.cameraview.controls.Flash;
import com.otaliastudios.cameraview.controls.Preview;
import com.otaliastudios.cameraview.gesture.Gesture;
import com.otaliastudios.cameraview.gesture.GestureAction;
import com.otaliastudios.cameraview.controls.Grid;
import com.otaliastudios.cameraview.controls.Hdr;
import com.otaliastudios.cameraview.controls.Mode;
import com.otaliastudios.cameraview.controls.VideoCodec;
import com.otaliastudios.cameraview.controls.WhiteBalance;
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.
*/
public enum Control {
// Layout
WIDTH("Width", false),
HEIGHT("Height", true),
// Some controls
MODE("Mode", false),
FLASH("Flash", false),
WHITE_BALANCE("White balance", false),
HDR("Hdr", true),
// Engine and preview
ENGINE("Engine", false),
PREVIEW("Preview Surface", true),
// Video recording
VIDEO_CODEC("Video codec", false),
AUDIO("Audio", true),
// TODO audio bitRate
// TODO video bitRate
// They are a bit annoying because it's not clear what the default should be.
// Gestures
PINCH("Pinch", false),
HSCROLL("Horizontal scroll", false),
VSCROLL("Vertical scroll", false),
TAP("Single tap", false),
LONG_TAP("Long tap", true),
// Others
GRID("Grid lines", false),
GRID_COLOR("Grid color", false),
USE_DEVICE_ORIENTATION("Use device orientation", true);
private String name;
private boolean last;
Control(String n, boolean l) {
name = n;
last = l;
}
public String getName() {
return name;
}
public boolean isSectionLast() {
return last;
}
public Collection<?> getValues(CameraView view, @NonNull CameraOptions options) {
switch (this) {
case WIDTH:
case HEIGHT:
View root = (View) view.getParent();
ArrayList<Integer> list = new ArrayList<>();
int boundary = this == WIDTH ? root.getWidth() : root.getHeight();
if (boundary == 0) boundary = 1000;
int step = boundary / 10;
// list.add(this == WIDTH ? 300 : 700);
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;
case MODE: return options.getSupportedControls(Mode.class);
case FLASH: return options.getSupportedControls(Flash.class);
case WHITE_BALANCE: return options.getSupportedControls(WhiteBalance.class);
case HDR: return options.getSupportedControls(Hdr.class);
case GRID: return options.getSupportedControls(Grid.class);
case AUDIO: return options.getSupportedControls(Audio.class);
case VIDEO_CODEC: return options.getSupportedControls(VideoCodec.class);
case ENGINE: return options.getSupportedControls(Engine.class);
case PREVIEW: return options.getSupportedControls(Preview.class);
case PINCH:
case HSCROLL:
case VSCROLL:
ArrayList<GestureAction> list1 = new ArrayList<>();
addIfSupported(options, list1, GestureAction.NONE);
addIfSupported(options, list1, GestureAction.ZOOM);
addIfSupported(options, list1, GestureAction.EXPOSURE_CORRECTION);
return list1;
case TAP:
case LONG_TAP:
ArrayList<GestureAction> list2 = new ArrayList<>();
addIfSupported(options, list2, GestureAction.NONE);
addIfSupported(options, list2, GestureAction.TAKE_PICTURE);
addIfSupported(options, list2, GestureAction.AUTO_FOCUS);
return list2;
case GRID_COLOR:
ArrayList<GridColor> list3 = new ArrayList<>();
list3.add(new GridColor(Color.argb(160, 255, 255, 255), "default"));
list3.add(new GridColor(Color.WHITE, "white"));
list3.add(new GridColor(Color.BLACK, "black"));
list3.add(new GridColor(Color.YELLOW, "yellow"));
return list3;
case USE_DEVICE_ORIENTATION:
return Arrays.asList(true, false);
}
return null;
}
private void addIfSupported(CameraOptions options, List<GestureAction> list, GestureAction value) {
if (options.supports(value)) list.add(value);
}
public Object getCurrentValue(CameraView view) {
switch (this) {
case WIDTH: return view.getLayoutParams().width;
case HEIGHT: return view.getLayoutParams().height;
case MODE: return view.getMode();
case FLASH: return view.getFlash();
case WHITE_BALANCE: return view.getWhiteBalance();
case GRID: return view.getGrid();
case GRID_COLOR: return new GridColor(view.getGridColor(), "color");
case AUDIO: return view.getAudio();
case VIDEO_CODEC: return view.getVideoCodec();
case HDR: return view.getHdr();
case PINCH: return view.getGestureAction(Gesture.PINCH);
case HSCROLL: return view.getGestureAction(Gesture.SCROLL_HORIZONTAL);
case VSCROLL: return view.getGestureAction(Gesture.SCROLL_VERTICAL);
case TAP: return view.getGestureAction(Gesture.TAP);
case LONG_TAP: return view.getGestureAction(Gesture.LONG_TAP);
case USE_DEVICE_ORIENTATION: return view.getUseDeviceOrientation();
case ENGINE: return view.getEngine();
case PREVIEW: return view.getPreview();
}
return null;
}
public void applyValue(final CameraView camera, final Object value) {
switch (this) {
case WIDTH:
camera.getLayoutParams().width = (int) value;
camera.setLayoutParams(camera.getLayoutParams());
break;
case HEIGHT:
camera.getLayoutParams().height = (int) value;
camera.setLayoutParams(camera.getLayoutParams());
break;
case MODE:
case FLASH:
case WHITE_BALANCE:
case GRID:
case AUDIO:
case VIDEO_CODEC:
case HDR:
camera.set((com.otaliastudios.cameraview.controls.Control) value);
break;
case PINCH:
camera.mapGesture(Gesture.PINCH, (GestureAction) value);
break;
case HSCROLL:
camera.mapGesture(Gesture.SCROLL_HORIZONTAL, (GestureAction) value);
break;
case VSCROLL:
camera.mapGesture(Gesture.SCROLL_VERTICAL, (GestureAction) value);
break;
case TAP:
camera.mapGesture(Gesture.TAP, (GestureAction) value);
break;
case LONG_TAP:
camera.mapGesture(Gesture.LONG_TAP, (GestureAction) value);
break;
case GRID_COLOR:
camera.setGridColor(((GridColor) value).color);
break;
case USE_DEVICE_ORIENTATION:
camera.setUseDeviceOrientation((Boolean) value);
break;
case ENGINE:
boolean started = camera.isOpened();
if (started) {
camera.addCameraListener(new CameraListener() {
@Override
public void onCameraClosed() {
super.onCameraClosed();
camera.removeCameraListener(this);
camera.setEngine((Engine) value);
camera.open();
}
});
camera.close();
} else {
camera.setEngine((Engine) value);
}
break;
case PREVIEW:
boolean opened = camera.isOpened();
if (opened) {
camera.addCameraListener(new CameraListener() {
@Override
public void onCameraClosed() {
super.onCameraClosed();
camera.removeCameraListener(this);
applyPreview(camera, (Preview) value, true);
}
});
camera.close();
} else {
applyPreview(camera, (Preview) value, false);
}
}
}
// This is really tricky since the preview can only be changed when not attached to window.
private void applyPreview(@NonNull CameraView cameraView, @NonNull Preview newPreview, boolean openWhenDone) {
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);
if (openWhenDone) cameraView.open();
}
static class GridColor {
int color;
String name;
GridColor(int color, String name) {
this.color = color;
this.name = name;
}
@Override
public String toString() {
return name;
}
@Override
public boolean equals(Object obj) {
return obj instanceof GridColor && color == ((GridColor) obj).color;
}
}
}

@ -24,7 +24,7 @@ public class MessageView extends LinearLayout {
public MessageView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { public MessageView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr); super(context, attrs, defStyleAttr);
setOrientation(VERTICAL); setOrientation(VERTICAL);
inflate(context, R.layout.control_view, this); inflate(context, R.layout.option_view, this);
ViewGroup content = findViewById(R.id.content); ViewGroup content = findViewById(R.id.content);
inflate(context, R.layout.spinner_text, content); inflate(context, R.layout.spinner_text, content);
title = findViewById(R.id.title); title = findViewById(R.id.title);

@ -0,0 +1,444 @@
package com.otaliastudios.cameraview.demo;
import android.graphics.Color;
import androidx.annotation.NonNull;
import androidx.core.util.Pair;
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.gesture.Gesture;
import com.otaliastudios.cameraview.gesture.GestureAction;
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.
*/
public abstract class Option<T> {
public static List<Option<?>> getAll() {
return Arrays.asList(
// Layout
new Width(false),
new Height(true),
// Engine and preview
new Mode(false),
new Engine(false),
new Preview(true),
// Some controls
new Flash(false),
new WhiteBalance(false),
new Hdr(true),
// Video recording
new VideoCodec(false),
new Audio(true),
// TODO audio bitRate
// TODO video bitRate
// They are a bit annoying because it's not clear what the default should be.
// Gestures
new Pinch(false),
new HorizontalScroll(false),
new VerticalScroll(false),
new Tap(false),
new LongTap(true),
// Other
new Grid(false),
new GridColor(false),
new UseDeviceOrientation(true)
);
}
private String name;
private boolean hasDividerBelow;
private Option(@NonNull String name, boolean hasDividerBelow) {
this.name = name;
this.hasDividerBelow = hasDividerBelow;
}
@SuppressWarnings("WeakerAccess")
@NonNull
public final String getName() {
return name;
}
@SuppressWarnings("WeakerAccess")
public final boolean hasDividerBelow() {
return hasDividerBelow;
}
@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> {
Width(boolean hasDividerBelow) {
super("Width", hasDividerBelow);
}
@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.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> {
Height(boolean hasDividerBelow) {
super("Height", hasDividerBelow);
}
@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 com.otaliastudios.cameraview.controls.Control> extends Option<T> {
private final Class<T> controlClass;
ControlOption(@NonNull Class<T> controlClass, String name, boolean hasDividerBelow) {
super(name, hasDividerBelow);
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> {
Mode(boolean hasDividerBelow) {
super(com.otaliastudios.cameraview.controls.Mode.class, "Mode", hasDividerBelow);
}
}
public static class Engine extends ControlOption<com.otaliastudios.cameraview.controls.Engine> {
Engine(boolean hasDividerBelow) {
super(com.otaliastudios.cameraview.controls.Engine.class, "Engine", hasDividerBelow);
}
@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> {
Preview(boolean hasDividerBelow) {
super(com.otaliastudios.cameraview.controls.Preview.class, "Preview Surface", hasDividerBelow);
}
@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> {
Flash(boolean hasDividerBelow) {
super(com.otaliastudios.cameraview.controls.Flash.class, "Flash", hasDividerBelow);
}
}
public static class WhiteBalance extends ControlOption<com.otaliastudios.cameraview.controls.WhiteBalance> {
WhiteBalance(boolean hasDividerBelow) {
super(com.otaliastudios.cameraview.controls.WhiteBalance.class, "White Balance", hasDividerBelow);
}
}
public static class Hdr extends ControlOption<com.otaliastudios.cameraview.controls.Hdr> {
Hdr(boolean hasDividerBelow) {
super(com.otaliastudios.cameraview.controls.Hdr.class, "HDR", hasDividerBelow);
}
}
public static class VideoCodec extends ControlOption<com.otaliastudios.cameraview.controls.VideoCodec> {
VideoCodec(boolean hasDividerBelow) {
super(com.otaliastudios.cameraview.controls.VideoCodec.class, "Video Codec", hasDividerBelow);
}
}
public static class Audio extends ControlOption<com.otaliastudios.cameraview.controls.Audio> {
Audio(boolean hasDividerBelow) {
super(com.otaliastudios.cameraview.controls.Audio.class, "Audio", hasDividerBelow);
}
}
private static abstract class GestureOption extends Option<GestureAction> {
private final Gesture gesture;
private final GestureAction[] allActions = GestureAction.values();
GestureOption(@NonNull Gesture gesture, String name, boolean hasDividerBelow) {
super(name, hasDividerBelow);
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 {
Pinch(boolean hasDividerBelow) {
super(Gesture.PINCH, "Pinch", hasDividerBelow);
}
}
public static class HorizontalScroll extends GestureOption {
HorizontalScroll(boolean hasDividerBelow) {
super(Gesture.SCROLL_HORIZONTAL, "Horizontal Scroll", hasDividerBelow);
}
}
public static class VerticalScroll extends GestureOption {
VerticalScroll(boolean hasDividerBelow) {
super(Gesture.SCROLL_VERTICAL, "Vertical Scroll", hasDividerBelow);
}
}
public static class Tap extends GestureOption {
Tap(boolean hasDividerBelow) {
super(Gesture.TAP, "Tap", hasDividerBelow);
}
}
public static class LongTap extends GestureOption {
LongTap(boolean hasDividerBelow) {
super(Gesture.LONG_TAP, "Long Tap", hasDividerBelow);
}
}
public static class Grid extends ControlOption<com.otaliastudios.cameraview.controls.Grid> {
Grid(boolean hasDividerBelow) {
super(com.otaliastudios.cameraview.controls.Grid.class, "Grid Lines", hasDividerBelow);
}
}
public static class GridColor extends Option<Pair<Integer, String>> {
GridColor(boolean hasDividerBelow) {
super("Grid Color", hasDividerBelow);
}
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> {
UseDeviceOrientation(boolean hasDividerBelow) {
super("Use Device Orientation", hasDividerBelow);
}
@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);
}
}
}

@ -3,66 +3,60 @@ package com.otaliastudios.cameraview.demo;
import android.annotation.SuppressLint; import android.annotation.SuppressLint;
import android.content.Context; import android.content.Context;
import android.text.TextUtils;
import android.util.Log; import android.util.Log;
import android.util.TypedValue;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.AdapterView; import android.widget.AdapterView;
import android.widget.ArrayAdapter; import android.widget.ArrayAdapter;
import android.widget.LinearLayout; import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import android.widget.Spinner; import android.widget.Spinner;
import android.widget.SpinnerAdapter;
import android.widget.TextView; import android.widget.TextView;
import androidx.annotation.NonNull;
import com.otaliastudios.cameraview.CameraOptions; import com.otaliastudios.cameraview.CameraOptions;
import com.otaliastudios.cameraview.CameraView; import com.otaliastudios.cameraview.CameraView;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection;
public class ControlView<Value> extends LinearLayout implements Spinner.OnItemSelectedListener { @SuppressLint("ViewConstructor")
public class OptionView<Value> extends LinearLayout implements Spinner.OnItemSelectedListener {
interface Callback { interface Callback {
boolean onValueChanged(Control control, Object value, String name); <T> boolean onValueChanged(@NonNull Option<T> option, @NonNull T value, @NonNull String name);
} }
private Value value; private Value value;
private ArrayList<Value> values; private ArrayList<Value> values;
private ArrayList<String> valuesStrings; private ArrayList<String> valuesStrings;
private Control control; private Option option;
private Callback callback; private Callback callback;
private Spinner spinner; private Spinner spinner;
public ControlView(Context context, Control control, Callback callback) { public OptionView(Context context, Option option, Callback callback) {
super(context); super(context);
this.control = control; this.option = option;
this.callback = callback; this.callback = callback;
setOrientation(VERTICAL); setOrientation(VERTICAL);
inflate(context, R.layout.control_view, this); inflate(context, R.layout.option_view, this);
TextView title = findViewById(R.id.title); TextView title = findViewById(R.id.title);
title.setText(control.getName()); title.setText(option.getName());
View divider = findViewById(R.id.divider); View divider = findViewById(R.id.divider);
divider.setVisibility(control.isSectionLast() ? View.VISIBLE : View.GONE); divider.setVisibility(option.hasDividerBelow() ? View.VISIBLE : View.GONE);
ViewGroup content = findViewById(R.id.content); ViewGroup content = findViewById(R.id.content);
spinner = new Spinner(context, Spinner.MODE_DROPDOWN); spinner = new Spinner(context, Spinner.MODE_DROPDOWN);
content.addView(spinner); content.addView(spinner);
} }
public Value getValue() {
return value;
}
@SuppressWarnings("all") @SuppressWarnings("all")
public void onCameraOpened(CameraView view, CameraOptions options) { public void onCameraOpened(CameraView view, CameraOptions options) {
values = new ArrayList(control.getValues(view, options)); values = new ArrayList(option.getAll(view, options));
value = (Value) control.getCurrentValue(view); value = (Value) option.get(view);
valuesStrings = new ArrayList<>(); valuesStrings = new ArrayList<>();
for (Value value : values) { for (Value value : values) {
valuesStrings.add(stringify(value)); valuesStrings.add(option.toString(value));
} }
if (values.isEmpty()) { if (values.isEmpty()) {
@ -86,7 +80,7 @@ public class ControlView<Value> extends LinearLayout implements Spinner.OnItemSe
public void onItemSelected(AdapterView<?> adapterView, View view, int i, long l) { public void onItemSelected(AdapterView<?> adapterView, View view, int i, long l) {
if (!values.get(i).equals(value)) { if (!values.get(i).equals(value)) {
Log.e("ControlView", "curr: " + value + " new: " + values.get(i)); Log.e("ControlView", "curr: " + value + " new: " + values.get(i));
if (!callback.onValueChanged(control, values.get(i), valuesStrings.get(i))) { if (!callback.onValueChanged(option, values.get(i), valuesStrings.get(i))) {
spinner.setSelection(values.indexOf(value)); // Go back. spinner.setSelection(values.indexOf(value)); // Go back.
} else { } else {
value = values.get(i); value = values.get(i);
@ -96,12 +90,4 @@ public class ControlView<Value> extends LinearLayout implements Spinner.OnItemSe
@Override @Override
public void onNothingSelected(AdapterView<?> adapterView) {} public void onNothingSelected(AdapterView<?> adapterView) {}
private String stringify(Value value) {
if (value instanceof Integer) {
if ((Integer) value == ViewGroup.LayoutParams.MATCH_PARENT) return "match parent";
if ((Integer) value == ViewGroup.LayoutParams.WRAP_CONTENT) return "wrap content";
}
return String.valueOf(value).replace("_", " ").toLowerCase();
}
} }
Loading…
Cancel
Save