Improve demo app

pull/497/head
Mattia Iavarone 6 years ago
parent d45da9a579
commit 4d6c7fbf2d
  1. 3
      cameraview/src/main/java/com/otaliastudios/cameraview/CameraOptions.java
  2. 28
      cameraview/src/main/java/com/otaliastudios/cameraview/CameraView.java
  3. 17
      cameraview/src/main/java/com/otaliastudios/cameraview/preview/CameraPreview.java
  4. 18
      demo/src/main/java/com/otaliastudios/cameraview/demo/CameraActivity.java
  5. 87
      demo/src/main/java/com/otaliastudios/cameraview/demo/Control.java
  6. 1
      demo/src/main/res/layout/activity_camera.xml

@ -20,6 +20,7 @@ import com.otaliastudios.cameraview.controls.Control;
import com.otaliastudios.cameraview.controls.Engine;
import com.otaliastudios.cameraview.controls.Facing;
import com.otaliastudios.cameraview.controls.Flash;
import com.otaliastudios.cameraview.controls.Preview;
import com.otaliastudios.cameraview.engine.Mapper;
import com.otaliastudios.cameraview.gesture.GestureAction;
import com.otaliastudios.cameraview.controls.Grid;
@ -309,6 +310,8 @@ public class CameraOptions {
return (Collection<T>) getSupportedWhiteBalance();
} else if (controlClass.equals(Engine.class)) {
return (Collection<T>) Arrays.asList(Engine.values());
} else if (controlClass.equals(Preview.class)) {
return (Collection<T>) Arrays.asList(Preview.values());
}
// Unrecognized control.
return Collections.emptyList();

@ -6,6 +6,7 @@ import android.annotation.TargetApi;
import android.app.Activity;
import androidx.annotation.VisibleForTesting;
import androidx.core.view.ViewCompat;
import androidx.lifecycle.Lifecycle;
import androidx.lifecycle.LifecycleObserver;
import androidx.lifecycle.LifecycleOwner;
@ -782,9 +783,26 @@ public class CameraView extends FrameLayout implements LifecycleObserver {
* @param preview desired preview engine
*/
public void setPreview(@NonNull Preview preview) {
boolean isNew = preview != mPreview;
if (!isNew) return;
mPreview = preview;
if (!ViewCompat.isAttachedToWindow(this) && mCameraPreview != null) {
// Null the preview: will create another when re-attaching.
mCameraPreview.onDestroy();
mCameraPreview = null;
}
}
/**
* Returns the current preview control.
*
* @see #setPreview(Preview)
* @return the current preview control
*/
@NonNull
public Preview getPreview() {
return mPreview;
}
/**
* Controls the core engine. Should only be called
@ -820,6 +838,16 @@ public class CameraView extends FrameLayout implements LifecycleObserver {
setAutoFocusResetDelay(oldEngine.getAutoFocusResetDelay());
}
/**
* Returns the current engine control.
*
* @see #setEngine(Engine)
* @return the current engine control
*/
@NonNull
public Engine getEngine() {
return mEngine;
}
/**
* Returns a {@link CameraOptions} instance holding supported options for this camera

@ -186,7 +186,9 @@ public abstract class CameraPreview<T extends View, Output> {
if (mOutputSurfaceWidth > 0 && mOutputSurfaceHeight > 0) {
crop(mCropOp);
}
mSurfaceCallback.onSurfaceAvailable();
if (mSurfaceCallback != null) {
mSurfaceCallback.onSurfaceAvailable();
}
}
/**
@ -203,7 +205,9 @@ public abstract class CameraPreview<T extends View, Output> {
if (width > 0 && height > 0) {
crop(mCropOp);
}
mSurfaceCallback.onSurfaceChanged();
if (mSurfaceCallback != null) {
mSurfaceCallback.onSurfaceChanged();
}
}
}
@ -214,7 +218,9 @@ public abstract class CameraPreview<T extends View, Output> {
protected final void dispatchOnSurfaceDestroyed() {
mOutputSurfaceWidth = 0;
mOutputSurfaceHeight = 0;
mSurfaceCallback.onSurfaceDestroyed();
if (mSurfaceCallback != null) {
mSurfaceCallback.onSurfaceDestroyed();
}
}
/**
@ -233,7 +239,10 @@ public abstract class CameraPreview<T extends View, Output> {
* Called by the hosting {@link com.otaliastudios.cameraview.CameraView},
* this is a lifecycle event.
*/
public void onDestroy() {}
public void onDestroy() {
ViewGroup parent = (ViewGroup) getRootView().getParent();
parent.removeView(getRootView());
}
/**
* Here we must crop the visible part by applying a scale greater than 1 to one of our

@ -21,6 +21,7 @@ import com.otaliastudios.cameraview.CameraView;
import com.otaliastudios.cameraview.PictureResult;
import com.otaliastudios.cameraview.controls.Mode;
import com.otaliastudios.cameraview.VideoResult;
import com.otaliastudios.cameraview.controls.Preview;
import com.otaliastudios.cameraview.frame.Frame;
import com.otaliastudios.cameraview.frame.FrameProcessor;
import com.otaliastudios.cameraview.size.SizeSelectors;
@ -173,6 +174,10 @@ public class CameraActivity extends AppCompatActivity implements View.OnClickLis
private void capturePictureSnapshot() {
if (camera.isTakingPicture()) return;
if (camera.getPreview() != Preview.GL_SURFACE) {
message("Picture snapshots are only allowed with the GL_SURFACE preview.", true);
return;
}
mCaptureTime = System.currentTimeMillis();
message("Capturing picture snapshot...", false);
camera.takePictureSnapshot();
@ -193,6 +198,10 @@ public class CameraActivity extends AppCompatActivity implements View.OnClickLis
message("Already taking video.", false);
return;
}
if (camera.getPreview() != Preview.GL_SURFACE) {
message("Video snapshots are only allowed with the GL_SURFACE preview.", true);
return;
}
message("Recording snapshot for 5 seconds...", true);
camera.takeVideoSnapshot(new File(getFilesDir(), "video.mp4"), 5000);
}
@ -212,10 +221,11 @@ public class CameraActivity extends AppCompatActivity implements View.OnClickLis
@Override
public boolean onValueChanged(Control control, Object value, String name) {
if (!camera.isHardwareAccelerated() && (control == Control.WIDTH || control == Control.HEIGHT)) {
if ((Integer) value > 0) {
message("This device does not support hardware acceleration. " +
"In this case you can not change width or height. " +
if ((control == Control.WIDTH || control == Control.HEIGHT)) {
Preview preview = camera.getPreview();
boolean wrapContent = (Integer) value == ViewGroup.LayoutParams.WRAP_CONTENT;
if (preview == Preview.SURFACE && !wrapContent) {
message("The SurfaceView preview does not support width or height changes. " +
"The view will act as WRAP_CONTENT by default.", true);
return false;
}

@ -5,10 +5,13 @@ 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;
@ -18,6 +21,7 @@ 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;
@ -26,28 +30,38 @@ import java.util.List;
*/
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),
GRID("Grid lines", false),
GRID_COLOR("Grid color", true),
// Engine and preview
ENGINE("Engine", false),
PREVIEW("Preview Surface", true),
// TODO audio bitRate
// TODO video bitRate
// THey are a bit annoying because it's not clear what the default should be.
// 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);
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;
@ -88,6 +102,8 @@ public enum Control {
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:
@ -110,6 +126,8 @@ public enum Control {
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;
}
@ -135,11 +153,14 @@ public enum Control {
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(CameraView camera, Object value) {
public void applyValue(final CameraView camera, final Object value) {
switch (this) {
case WIDTH:
camera.getLayoutParams().width = (int) value;
@ -175,9 +196,61 @@ public enum Control {
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;

@ -17,7 +17,6 @@
android:layout_marginBottom="88dp"
android:keepScreenOn="true"
app:cameraExperimental="true"
app:cameraUseDeviceOrientation="false"
app:cameraEngine="camera2"
app:cameraPreview="glSurface"
app:cameraPlaySounds="true"

Loading…
Cancel
Save