blob: 86721acb7548cb39c4f5810351c470d70fe4f45b [file] [log] [blame]
/*
* Copyright (C) 2015 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.camera.one.v2.autofocus;
import android.hardware.camera2.CaptureResult;
import androidx.annotation.Nullable;
import com.android.camera.async.Updatable;
import java.util.Set;
import javax.annotation.ParametersAreNonnullByDefault;
import javax.annotation.concurrent.NotThreadSafe;
/**
* Tracks the finite state machines used by the camera2 api for AF and AE
* triggers. That is, the state machine waits for a TRIGGER_START followed by
* one of the done states, at which point a callback is invoked and the state
* machine resets.
* <p>
* In other words, this implements the state machine defined by the following
* regex, such that a callback is invoked each time the state machine reaches
* the end.
*
* <pre>
* (.* TRIGGER_START .* [DONE_STATES])+
* </pre>
* <p>
* See the android documentation for {@link CaptureResult#CONTROL_AF_STATE} and
* {@link CaptureResult#CONTROL_AE_STATE} for the transition tables which this
* is based on.
*/
@ParametersAreNonnullByDefault
@NotThreadSafe
final class TriggerStateMachine {
private static enum State {
WAITING_FOR_TRIGGER,
TRIGGERED
}
private final int mTriggerStart;
private final Set<Integer> mDoneStates;
private State mCurrentState;
@Nullable
private Long mLastTriggerFrameNumber;
@Nullable
private Long mLastFinishFrameNumber;
public TriggerStateMachine(int triggerStart, Set<Integer> doneStates) {
mTriggerStart = triggerStart;
mDoneStates = doneStates;
mCurrentState = State.WAITING_FOR_TRIGGER;
mLastTriggerFrameNumber = null;
mLastFinishFrameNumber = null;
}
/**
* @return True upon completion of a cycle of the state machine.
*/
public boolean update(long frameNumber, @Nullable Integer triggerState, @Nullable Integer
state) {
boolean triggeredNow = triggerState != null && triggerState == mTriggerStart;
boolean doneNow = mDoneStates.contains(state);
if (mCurrentState == State.WAITING_FOR_TRIGGER) {
if (mLastTriggerFrameNumber == null || frameNumber > mLastTriggerFrameNumber) {
if (triggeredNow) {
mCurrentState = State.TRIGGERED;
mLastTriggerFrameNumber = frameNumber;
}
}
}
if (mCurrentState == State.TRIGGERED) {
if (mLastFinishFrameNumber == null || frameNumber > mLastFinishFrameNumber) {
if (doneNow) {
mCurrentState = State.WAITING_FOR_TRIGGER;
mLastFinishFrameNumber = frameNumber;
return true;
}
}
}
return false;
}
}