pull/696/head
Mattia Iavarone 6 years ago
parent 22931a4c55
commit e789f9c62d
  1. 4
      cameraview/src/androidTest/java/com/otaliastudios/cameraview/engine/CameraIntegrationTest.java
  2. 39
      cameraview/src/main/java/com/otaliastudios/cameraview/engine/CameraEngine.java
  3. 35
      cameraview/src/main/java/com/otaliastudios/cameraview/engine/orchestrator/CameraOrchestrator.java
  4. 20
      cameraview/src/main/java/com/otaliastudios/cameraview/engine/orchestrator/CameraStateOrchestrator.java

@ -314,11 +314,11 @@ public abstract class CameraIntegrationTest<E extends CameraEngine> extends Base
@Test
public void testOpenClose() {
assertEquals(controller.getState(), CameraState.OFF);
assertEquals(CameraState.OFF, controller.getState());
openSync(true);
assertTrue(controller.getState().isAtLeast(CameraState.ENGINE));
closeSync(true);
assertEquals(controller.getState(), CameraState.OFF);
assertEquals(CameraState.OFF, controller.getState());
}
@Test

@ -408,23 +408,24 @@ public abstract class CameraEngine implements
private Task<Void> startEngine() {
return mOrchestrator.scheduleStateChange(CameraState.OFF, CameraState.ENGINE,
true,
new Callable<Task<Void>>() {
new Callable<Task<CameraOptions>>() {
@Override
public Task<Void> call() {
public Task<CameraOptions> call() {
if (!collectCameraInfo(mFacing)) {
LOG.e("onStartEngine:", "No camera available for facing", mFacing);
throw new CameraException(CameraException.REASON_NO_CAMERA);
}
return onStartEngine().onSuccessTask(
new SuccessContinuation<CameraOptions, Void>() {
@NonNull
@Override
public Task<Void> then(@Nullable CameraOptions cameraOptions) {
if (cameraOptions == null) throw new RuntimeException("Null options!");
mCallback.dispatchOnCameraOpened(cameraOptions);
return Tasks.forResult(null);
}
});
return onStartEngine();
}
}).onSuccessTask(new SuccessContinuation<CameraOptions, Void>() {
@NonNull
@Override
public Task<Void> then(@Nullable CameraOptions cameraOptions) {
// Put this on the outer task so we're sure it's called after getState() is changed.
// This was breaking some tests on rare occasions.
if (cameraOptions == null) throw new RuntimeException("Null options!");
mCallback.dispatchOnCameraOpened(cameraOptions);
return Tasks.forResult(null);
}
});
}
@ -437,12 +438,14 @@ public abstract class CameraEngine implements
new Callable<Task<Void>>() {
@Override
public Task<Void> call() {
return onStopEngine().addOnSuccessListener(new OnSuccessListener<Void>() {
@Override
public void onSuccess(Void aVoid) {
mCallback.dispatchOnCameraClosed();
}
});
return onStopEngine();
}
}).addOnSuccessListener(new OnSuccessListener<Void>() {
@Override
public void onSuccess(Void aVoid) {
// Put this on the outer task so we're sure it's called after getState() is OFF.
// This was breaking some tests on rare occasions.
mCallback.dispatchOnCameraClosed();
}
});
}

@ -40,9 +40,9 @@ public class CameraOrchestrator {
protected static class Token {
public final String name;
public final Task<Void> task;
public final Task<?> task;
private Token(@NonNull String name, @NonNull Task<Void> task) {
private Token(@NonNull String name, @NonNull Task<?> task) {
this.name = name;
this.task = task;
}
@ -76,28 +76,29 @@ public class CameraOrchestrator {
});
}
@SuppressWarnings("unchecked")
@NonNull
public Task<Void> schedule(@NonNull final String name,
final boolean dispatchExceptions,
@NonNull final Callable<Task<Void>> job) {
public <T> Task<T> schedule(@NonNull final String name,
final boolean dispatchExceptions,
@NonNull final Callable<Task<T>> job) {
LOG.i(name.toUpperCase(), "- Scheduling.");
final TaskCompletionSource<Void> source = new TaskCompletionSource<>();
final TaskCompletionSource<T> source = new TaskCompletionSource<>();
final WorkerHandler handler = mCallback.getJobWorker(name);
synchronized (mLock) {
applyCompletionListener(mJobs.getLast().task, handler,
new OnCompleteListener<Void>() {
new OnCompleteListener() {
@Override
public void onComplete(@NonNull Task<Void> task) {
public void onComplete(@NonNull Task task) {
synchronized (mLock) {
mJobs.removeFirst();
ensureToken();
}
try {
LOG.i(name.toUpperCase(), "- Executing.");
Task<Void> inner = job.call();
applyCompletionListener(inner, handler, new OnCompleteListener<Void>() {
Task<T> inner = job.call();
applyCompletionListener(inner, handler, new OnCompleteListener<T>() {
@Override
public void onComplete(@NonNull Task<Void> task) {
public void onComplete(@NonNull Task<T> task) {
Exception e = task.getException();
if (e != null) {
LOG.w(name.toUpperCase(), "- Finished with ERROR.", e);
@ -110,7 +111,7 @@ public class CameraOrchestrator {
source.trySetException(new CancellationException());
} else {
LOG.i(name.toUpperCase(), "- Finished.");
source.trySetResult(null);
source.trySetResult(task.getResult());
}
}
});
@ -153,7 +154,7 @@ public class CameraOrchestrator {
mCallback.getJobWorker(name).remove(mDelayedJobs.get(name));
mDelayedJobs.remove(name);
}
Token token = new Token(name, Tasks.<Void>forResult(null));
Token token = new Token(name, Tasks.forResult(null));
//noinspection StatementWithEmptyBody
while (mJobs.remove(token)) { /* do nothing */ }
ensureToken();
@ -163,14 +164,14 @@ public class CameraOrchestrator {
private void ensureToken() {
synchronized (mLock) {
if (mJobs.isEmpty()) {
mJobs.add(new Token("BASE", Tasks.<Void>forResult(null)));
mJobs.add(new Token("BASE", Tasks.forResult(null)));
}
}
}
private static void applyCompletionListener(@NonNull final Task<Void> task,
@NonNull WorkerHandler handler,
@NonNull final OnCompleteListener<Void> listener) {
private static <T> void applyCompletionListener(@NonNull final Task<T> task,
@NonNull WorkerHandler handler,
@NonNull final OnCompleteListener<T> listener) {
if (task.isComplete()) {
handler.run(new Runnable() {
@Override

@ -47,19 +47,19 @@ public class CameraStateOrchestrator extends CameraOrchestrator {
}
@NonNull
public Task<Void> scheduleStateChange(@NonNull final CameraState fromState,
@NonNull final CameraState toState,
boolean dispatchExceptions,
@NonNull final Callable<Task<Void>> stateChange) {
public <T> Task<T> scheduleStateChange(@NonNull final CameraState fromState,
@NonNull final CameraState toState,
boolean dispatchExceptions,
@NonNull final Callable<Task<T>> stateChange) {
final int changeCount = ++mStateChangeCount;
mTargetState = toState;
final boolean isTearDown = !toState.isAtLeast(fromState);
final String name = isTearDown ? fromState.name() + " << " + toState.name()
: fromState.name() + " >> " + toState.name();
return schedule(name, dispatchExceptions, new Callable<Task<Void>>() {
return schedule(name, dispatchExceptions, new Callable<Task<T>>() {
@Override
public Task<Void> call() throws Exception {
public Task<T> call() throws Exception {
if (getCurrentState() != fromState) {
LOG.w(name.toUpperCase(), "- State mismatch, aborting. current:",
getCurrentState(), "from:", fromState, "to:", toState);
@ -67,9 +67,9 @@ public class CameraStateOrchestrator extends CameraOrchestrator {
} else {
Executor executor = mCallback.getJobWorker(name).getExecutor();
return stateChange.call().continueWithTask(executor,
new Continuation<Void, Task<Void>>() {
new Continuation<T, Task<T>>() {
@Override
public Task<Void> then(@NonNull Task<Void> task) {
public Task<T> then(@NonNull Task<T> task) {
if (task.isSuccessful() || isTearDown) {
mCurrentState = toState;
}
@ -78,9 +78,9 @@ public class CameraStateOrchestrator extends CameraOrchestrator {
});
}
}
}).addOnCompleteListener(new OnCompleteListener<Void>() {
}).addOnCompleteListener(new OnCompleteListener<T>() {
@Override
public void onComplete(@NonNull Task<Void> task) {
public void onComplete(@NonNull Task<T> task) {
if (changeCount == mStateChangeCount) {
mTargetState = mCurrentState;
}

Loading…
Cancel
Save