Add action.abort()

pull/580/head
Mattia Iavarone 6 years ago
parent a9f6e50ac4
commit 71179b1fdc
  1. 7
      cameraview/src/main/java/com/otaliastudios/cameraview/engine/Camera2Engine.java
  2. 6
      cameraview/src/main/java/com/otaliastudios/cameraview/engine/action/Action.java
  3. 6
      cameraview/src/main/java/com/otaliastudios/cameraview/engine/action/ActionWrapper.java
  4. 143
      cameraview/src/main/java/com/otaliastudios/cameraview/engine/action/Actions.java
  5. 19
      cameraview/src/main/java/com/otaliastudios/cameraview/engine/action/BaseAction.java
  6. 94
      cameraview/src/main/java/com/otaliastudios/cameraview/engine/action/SequenceAction.java
  7. 7
      cameraview/src/main/java/com/otaliastudios/cameraview/engine/action/TimeoutAction.java
  8. 84
      cameraview/src/main/java/com/otaliastudios/cameraview/engine/action/TogetherAction.java
  9. 3
      cameraview/src/main/java/com/otaliastudios/cameraview/picture/Snapshot2PictureRecorder.java
  10. 4
      cameraview/src/main/java/com/otaliastudios/cameraview/video/Full2VideoRecorder.java

@ -46,7 +46,6 @@ import com.otaliastudios.cameraview.engine.action.Action;
import com.otaliastudios.cameraview.engine.action.ActionHolder;
import com.otaliastudios.cameraview.engine.action.Actions;
import com.otaliastudios.cameraview.engine.action.CompletionCallback;
import com.otaliastudios.cameraview.engine.action.TimeoutAction;
import com.otaliastudios.cameraview.engine.lock.UnlockAction;
import com.otaliastudios.cameraview.engine.mappers.Camera2Mapper;
import com.otaliastudios.cameraview.engine.meter.MeterAction;
@ -637,7 +636,7 @@ public class Camera2Engine extends CameraEngine implements ImageReader.OnImageAv
protected void onTakePictureSnapshot(@NonNull final PictureResult.Stub stub, @NonNull final AspectRatio outputRatio, boolean doMetering) {
if (doMetering) {
LOG.i("onTakePictureSnapshot:", "doMetering is true. Delaying.");
Action action = new TimeoutAction(METER_TIMEOUT, createMeterAction(null));
Action action = Actions.timeout(METER_TIMEOUT, createMeterAction(null));
action.addCallback(new CompletionCallback() {
@Override
protected void onActionCompleted(@NonNull Action action) {
@ -665,7 +664,7 @@ public class Camera2Engine extends CameraEngine implements ImageReader.OnImageAv
protected void onTakePicture(@NonNull final PictureResult.Stub stub, boolean doMetering) {
if (doMetering) {
LOG.i("onTakePicture:", "doMetering is true. Delaying.");
Action action = new TimeoutAction(METER_TIMEOUT, createMeterAction(null));
Action action = Actions.timeout(METER_TIMEOUT, createMeterAction(null));
action.addCallback(new CompletionCallback() {
@Override
protected void onActionCompleted(@NonNull Action action) {
@ -1238,7 +1237,7 @@ public class Camera2Engine extends CameraEngine implements ImageReader.OnImageAv
// Create the meter and start.
mCallback.dispatchOnFocusStart(gesture, point);
final MeterAction action = createMeterAction(point);
final TimeoutAction wrapper = new TimeoutAction(METER_TIMEOUT, action);
Action wrapper = Actions.timeout(METER_TIMEOUT, action);
wrapper.start(Camera2Engine.this);
wrapper.addCallback(new CompletionCallback() {
@Override

@ -41,6 +41,12 @@ public interface Action {
*/
void start(@NonNull ActionHolder holder);
/**
* Aborts this action.
* @param holder the holder
*/
void abort(@NonNull ActionHolder holder);
/**
* Adds an {@link ActionCallback} to receive state
* change events.

@ -37,6 +37,12 @@ public abstract class ActionWrapper extends BaseAction {
getAction().onStart(holder);
}
@Override
protected void onAbort(@NonNull ActionHolder holder) {
super.onAbort(holder);
getAction().onAbort(holder);
}
@Override
public void onCaptureStarted(@NonNull ActionHolder holder, @NonNull CaptureRequest request) {
super.onCaptureStarted(holder, request);

@ -1,16 +1,11 @@
package com.otaliastudios.cameraview.engine.action;
import android.hardware.camera2.CaptureRequest;
import android.hardware.camera2.CaptureResult;
import android.hardware.camera2.TotalCaptureResult;
import android.os.Build;
import androidx.annotation.NonNull;
import androidx.annotation.RequiresApi;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
* Utilities for creating {@link Action} sequences.
@ -22,6 +17,7 @@ public class Actions {
* Creates a {@link BaseAction} that executes all the child actions
* together, at the same time, and completes once all of them are
* completed.
*
* @param actions input actions
* @return a new action
*/
@ -34,6 +30,7 @@ public class Actions {
* Creates a {@link BaseAction} that executes all the child actions
* in sequence, waiting for the first to complete, then going on with
* the second and so on, finally completing when all are completed.
*
* @param actions input actions
* @return a new action
*/
@ -42,130 +39,18 @@ public class Actions {
return new SequenceAction(Arrays.asList(actions));
}
private static class TogetherAction extends BaseAction {
// Need to be BaseAction so we can call onStart() instead of start()
private final List<BaseAction> actions;
private final List<BaseAction> runningActions;
private TogetherAction(@NonNull final List<BaseAction> actions) {
this.actions = new ArrayList<>(actions);
this.runningActions = new ArrayList<>(actions);
for (BaseAction action : actions) {
action.addCallback(new ActionCallback() {
@Override
public void onActionStateChanged(@NonNull Action action, int state) {
if (state == STATE_COMPLETED) {
//noinspection SuspiciousMethodCalls
runningActions.remove(action);
}
if (runningActions.isEmpty()) {
setState(STATE_COMPLETED);
}
}
});
}
}
@Override
protected void onStart(@NonNull ActionHolder holder) {
super.onStart(holder);
for (BaseAction action : actions) {
if (!action.isCompleted()) action.onStart(holder);
}
}
@Override
public void onCaptureStarted(@NonNull ActionHolder holder, @NonNull CaptureRequest request) {
super.onCaptureStarted(holder, request);
for (BaseAction action : actions) {
if (!action.isCompleted()) action.onCaptureStarted(holder, request);
}
}
@Override
public void onCaptureProgressed(@NonNull ActionHolder holder, @NonNull CaptureRequest request,
@NonNull CaptureResult result) {
super.onCaptureProgressed(holder, request, result);
for (BaseAction action : actions) {
if (!action.isCompleted()) action.onCaptureProgressed(holder, request, result);
}
}
@Override
public void onCaptureCompleted(@NonNull ActionHolder holder, @NonNull CaptureRequest request,
@NonNull TotalCaptureResult result) {
super.onCaptureCompleted(holder, request, result);
for (BaseAction action : actions) {
if (!action.isCompleted()) action.onCaptureCompleted(holder, request, result);
}
}
/**
* Creates a {@link BaseAction} that completes as normal, but is also
* forced to complete if the given timeout is reached, by calling
* {@link Action#abort(ActionHolder)}.
*
* @param timeoutMillis timeout in milliseconds
* @param action action
* @return a new action
*/
@NonNull
public static BaseAction timeout(long timeoutMillis, @NonNull BaseAction action) {
return new TimeoutAction(timeoutMillis, action);
}
private static class SequenceAction extends BaseAction {
// Need to be BaseAction so we can call onStart() instead of start()
private final List<BaseAction> actions;
private int runningAction = -1;
private SequenceAction(@NonNull List<BaseAction> actions) {
this.actions = actions;
increaseRunningAction();
}
private void increaseRunningAction() {
boolean first = runningAction == -1;
boolean last = runningAction == actions.size() - 1;
if (last) {
// This was the last action. We're done.
setState(STATE_COMPLETED);
} else {
runningAction++;
actions.get(runningAction).addCallback(new ActionCallback() {
@Override
public void onActionStateChanged(@NonNull Action action, int state) {
if (state == STATE_COMPLETED) {
action.removeCallback(this);
increaseRunningAction();
}
}
});
if (!first) {
actions.get(runningAction).onStart(getHolder());
}
}
}
@Override
protected void onStart(@NonNull ActionHolder holder) {
super.onStart(holder);
if (runningAction >= 0) {
actions.get(runningAction).onStart(holder);
}
}
@Override
public void onCaptureStarted(@NonNull ActionHolder holder, @NonNull CaptureRequest request) {
super.onCaptureStarted(holder, request);
if (runningAction >= 0) {
actions.get(runningAction).onCaptureStarted(holder, request);
}
}
@Override
public void onCaptureProgressed(@NonNull ActionHolder holder, @NonNull CaptureRequest request,
@NonNull CaptureResult result) {
super.onCaptureProgressed(holder, request, result);
if (runningAction >= 0) {
actions.get(runningAction).onCaptureProgressed(holder, request, result);
}
}
@Override
public void onCaptureCompleted(@NonNull ActionHolder holder, @NonNull CaptureRequest request,
@NonNull TotalCaptureResult result) {
super.onCaptureCompleted(holder, request, result);
if (runningAction >= 0) {
actions.get(runningAction).onCaptureCompleted(holder, request, result);
}
}
}
}

@ -42,6 +42,15 @@ public abstract class BaseAction implements Action {
onStart(holder);
}
@Override
public final void abort(@NonNull ActionHolder holder) {
holder.removeAction(this);
if (!isCompleted()) {
onAbort(holder);
setState(STATE_COMPLETED);
}
}
/**
* Action was started and will soon receive events from the
* holder stream.
@ -53,6 +62,16 @@ public abstract class BaseAction implements Action {
// Overrideable
}
/**
* Action was aborted and will not receive events from the
* holder stream anymore. It will soon be marked as completed.
* @param holder holder
*/
@SuppressWarnings({"WeakerAccess", "unused"})
protected void onAbort(@NonNull ActionHolder holder) {
// Overrideable
}
@Override
public void onCaptureStarted(@NonNull ActionHolder holder, @NonNull CaptureRequest request) {
// Overrideable

@ -0,0 +1,94 @@
package com.otaliastudios.cameraview.engine.action;
import android.hardware.camera2.CaptureRequest;
import android.hardware.camera2.CaptureResult;
import android.hardware.camera2.TotalCaptureResult;
import android.os.Build;
import androidx.annotation.NonNull;
import androidx.annotation.RequiresApi;
import java.util.List;
/**
* Executes a list of actions in sequence, completing once
* the last of them has been completed.
*/
@RequiresApi(Build.VERSION_CODES.LOLLIPOP)
class SequenceAction extends BaseAction {
// Need to be BaseAction so we can call onStart() instead of start()
private final List<BaseAction> actions;
private int runningAction = -1;
SequenceAction(@NonNull List<BaseAction> actions) {
this.actions = actions;
increaseRunningAction();
}
private void increaseRunningAction() {
boolean first = runningAction == -1;
boolean last = runningAction == actions.size() - 1;
if (last) {
// This was the last action. We're done.
setState(STATE_COMPLETED);
} else {
runningAction++;
actions.get(runningAction).addCallback(new ActionCallback() {
@Override
public void onActionStateChanged(@NonNull Action action, int state) {
if (state == STATE_COMPLETED) {
action.removeCallback(this);
increaseRunningAction();
}
}
});
if (!first) {
actions.get(runningAction).onStart(getHolder());
}
}
}
@Override
protected void onStart(@NonNull ActionHolder holder) {
super.onStart(holder);
if (runningAction >= 0) {
actions.get(runningAction).onStart(holder);
}
}
@Override
protected void onAbort(@NonNull ActionHolder holder) {
super.onAbort(holder);
if (runningAction >= 0) {
// Previous actions have been completed already.
// Future actions will never start. So this is OK.
actions.get(runningAction).onAbort(holder);
}
}
@Override
public void onCaptureStarted(@NonNull ActionHolder holder, @NonNull CaptureRequest request) {
super.onCaptureStarted(holder, request);
if (runningAction >= 0) {
actions.get(runningAction).onCaptureStarted(holder, request);
}
}
@Override
public void onCaptureProgressed(@NonNull ActionHolder holder, @NonNull CaptureRequest request,
@NonNull CaptureResult result) {
super.onCaptureProgressed(holder, request, result);
if (runningAction >= 0) {
actions.get(runningAction).onCaptureProgressed(holder, request, result);
}
}
@Override
public void onCaptureCompleted(@NonNull ActionHolder holder, @NonNull CaptureRequest request,
@NonNull TotalCaptureResult result) {
super.onCaptureCompleted(holder, request, result);
if (runningAction >= 0) {
actions.get(runningAction).onCaptureCompleted(holder, request, result);
}
}
}

@ -12,13 +12,13 @@ import androidx.annotation.RequiresApi;
* after the given timeout in milliseconds is reached.
*/
@RequiresApi(Build.VERSION_CODES.LOLLIPOP)
public class TimeoutAction extends ActionWrapper {
class TimeoutAction extends ActionWrapper {
private long startMillis;
private long timeoutMillis;
private BaseAction action;
public TimeoutAction(long timeoutMillis, @NonNull BaseAction action) {
TimeoutAction(long timeoutMillis, @NonNull BaseAction action) {
this.timeoutMillis = timeoutMillis;
this.action = action;
}
@ -42,7 +42,8 @@ public class TimeoutAction extends ActionWrapper {
super.onCaptureCompleted(holder, request, result);
if (!isCompleted()) {
if (System.currentTimeMillis() > startMillis + timeoutMillis) {
setState(STATE_COMPLETED);
// This will set our state to COMPLETED and stop requests.
getAction().abort(holder);
}
}
}

@ -0,0 +1,84 @@
package com.otaliastudios.cameraview.engine.action;
import android.hardware.camera2.CaptureRequest;
import android.hardware.camera2.CaptureResult;
import android.hardware.camera2.TotalCaptureResult;
import android.os.Build;
import androidx.annotation.NonNull;
import androidx.annotation.RequiresApi;
import java.util.ArrayList;
import java.util.List;
/**
* Performs a list of actions together, completing
* once all of them have completed.
*/
@RequiresApi(Build.VERSION_CODES.LOLLIPOP)
class TogetherAction extends BaseAction {
// Need to be BaseAction so we can call onStart() instead of start()
private final List<BaseAction> actions;
private final List<BaseAction> runningActions;
TogetherAction(@NonNull final List<BaseAction> actions) {
this.actions = new ArrayList<>(actions);
this.runningActions = new ArrayList<>(actions);
for (BaseAction action : actions) {
action.addCallback(new ActionCallback() {
@Override
public void onActionStateChanged(@NonNull Action action, int state) {
if (state == STATE_COMPLETED) {
//noinspection SuspiciousMethodCalls
runningActions.remove(action);
}
if (runningActions.isEmpty()) {
setState(STATE_COMPLETED);
}
}
});
}
}
@Override
protected void onStart(@NonNull ActionHolder holder) {
super.onStart(holder);
for (BaseAction action : actions) {
if (!action.isCompleted()) action.onStart(holder);
}
}
@Override
protected void onAbort(@NonNull ActionHolder holder) {
super.onAbort(holder);
for (BaseAction action : actions) {
if (!action.isCompleted()) action.onAbort(holder);
}
}
@Override
public void onCaptureStarted(@NonNull ActionHolder holder, @NonNull CaptureRequest request) {
super.onCaptureStarted(holder, request);
for (BaseAction action : actions) {
if (!action.isCompleted()) action.onCaptureStarted(holder, request);
}
}
@Override
public void onCaptureProgressed(@NonNull ActionHolder holder, @NonNull CaptureRequest request,
@NonNull CaptureResult result) {
super.onCaptureProgressed(holder, request, result);
for (BaseAction action : actions) {
if (!action.isCompleted()) action.onCaptureProgressed(holder, request, result);
}
}
@Override
public void onCaptureCompleted(@NonNull ActionHolder holder, @NonNull CaptureRequest request,
@NonNull TotalCaptureResult result) {
super.onCaptureCompleted(holder, request, result);
for (BaseAction action : actions) {
if (!action.isCompleted()) action.onCaptureCompleted(holder, request, result);
}
}
}

@ -18,7 +18,6 @@ import com.otaliastudios.cameraview.engine.action.ActionHolder;
import com.otaliastudios.cameraview.engine.action.Actions;
import com.otaliastudios.cameraview.engine.action.BaseAction;
import com.otaliastudios.cameraview.engine.action.CompletionCallback;
import com.otaliastudios.cameraview.engine.action.TimeoutAction;
import com.otaliastudios.cameraview.engine.lock.LockAction;
import com.otaliastudios.cameraview.preview.GlCameraPreview;
import com.otaliastudios.cameraview.size.AspectRatio;
@ -91,7 +90,7 @@ public class Snapshot2PictureRecorder extends SnapshotGlPictureRecorder {
mHolder = engine;
mAction = Actions.sequence(
new TimeoutAction(LOCK_TIMEOUT, new LockAction()),
Actions.timeout(LOCK_TIMEOUT, new LockAction()),
new FlashAction());
mAction.addCallback(new CompletionCallback() {
@Override

@ -34,12 +34,10 @@ public class Full2VideoRecorder extends FullVideoRecorder {
private static final CameraLogger LOG = CameraLogger.create(TAG);
private ActionHolder mHolder;
private boolean mGotFirstFrame;
private final String mCameraId;
private Surface mInputSurface;
public Full2VideoRecorder(@NonNull Camera2Engine engine,
@NonNull String cameraId) {
public Full2VideoRecorder(@NonNull Camera2Engine engine, @NonNull String cameraId) {
super(engine);
mHolder = engine;
mCameraId = cameraId;

Loading…
Cancel
Save