124be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu/* 224be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu * Copyright (C) 2015 The Android Open Source Project 324be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu * 424be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu * Licensed under the Apache License, Version 2.0 (the "License"); 524be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu * you may not use this file except in compliance with the License. 624be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu * You may obtain a copy of the License at 724be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu * 824be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu * http://www.apache.org/licenses/LICENSE-2.0 924be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu * 1024be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu * Unless required by applicable law or agreed to in writing, software 1124be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu * distributed under the License is distributed on an "AS IS" BASIS, 1224be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1324be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu * See the License for the specific language governing permissions and 1424be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu * limitations under the License. 1524be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu */ 1624be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu 17d2d86155337a7dd9fd285a25c93e27dc05200ed1Senpo Hupackage com.android.camera.captureintent.stateful; 1824be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu 1924be7cc6d138129b4087ef28f114701de54aba3cSenpo Huimport com.google.common.base.Optional; 2024be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu 2124be7cc6d138129b4087ef28f114701de54aba3cSenpo Huimport com.android.camera.debug.Log; 2224be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu 2324be7cc6d138129b4087ef28f114701de54aba3cSenpo Huimport java.util.concurrent.locks.Condition; 2424be7cc6d138129b4087ef28f114701de54aba3cSenpo Huimport java.util.concurrent.locks.ReentrantLock; 2524be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu 2624be7cc6d138129b4087ef28f114701de54aba3cSenpo Huimport javax.annotation.Nonnull; 2724be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu 28d2d86155337a7dd9fd285a25c93e27dc05200ed1Senpo Hupublic class StateMachineImpl implements StateMachine { 2924be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu private static final Log.Tag TAG = new Log.Tag("StateMachine"); 3024be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu 3124be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu /** The current state. */ 3224be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu private State mState; 3324be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu 3424be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu /** The lock to protect mState. */ 3524be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu private final ReentrantLock mStateLock; 3624be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu 3724be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu /** The condition to synchronize state changed event. */ 3824be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu private final Condition mStateChangedCondition; 3924be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu 40d2d86155337a7dd9fd285a25c93e27dc05200ed1Senpo Hu public StateMachineImpl() { 4124be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu mStateLock = new ReentrantLock(); 4224be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu mStateChangedCondition = mStateLock.newCondition(); 434908a11eefa7f69129891bc9859029d6b2504efaSenpo Hu mState = new StateUninitialized(this); 4424be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu } 4524be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu 4624be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu /** 4724be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu * Jumps directly to a specific state. 4824be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu * 4924be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu * @param newState The new state. 5024be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu */ 5124be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu public void jumpToState(@Nonnull State newState) { 5224be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu mStateLock.lock(); 5324be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu try { 5424be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu if (newState.equals(mState)) { 5524be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu Log.d(TAG, "No op since jump to the same state."); 5624be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu } else { 5724be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu // While changing to a particular state, execute its onEnter() hook 5824be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu // and keep forwarding to new states if necessary. 5924be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu Log.d(TAG, "Change state : " + mState + " => " + newState); 6024be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu mState.onLeave(); 6124be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu mState = newState; 6224be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu Optional<State> nextState = mState.onEnter(); 6324be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu while (nextState.isPresent()) { 6424be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu Log.d(TAG, "Forward state : " + mState + " => " + nextState.get()); 6524be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu mState.onLeave(); 6624be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu mState = nextState.get(); 6724be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu nextState = mState.onEnter(); 6824be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu } 6924be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu 7024be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu mStateChangedCondition.signalAll(); 7124be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu } 7224be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu } finally { 7324be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu mStateLock.unlock(); 7424be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu } 7524be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu } 7624be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu 77d2d86155337a7dd9fd285a25c93e27dc05200ed1Senpo Hu @Override 78d2d86155337a7dd9fd285a25c93e27dc05200ed1Senpo Hu public State getCurrentState() { 79d2d86155337a7dd9fd285a25c93e27dc05200ed1Senpo Hu mStateLock.lock(); 80d2d86155337a7dd9fd285a25c93e27dc05200ed1Senpo Hu try { 81d2d86155337a7dd9fd285a25c93e27dc05200ed1Senpo Hu return mState; 82d2d86155337a7dd9fd285a25c93e27dc05200ed1Senpo Hu } finally { 83d2d86155337a7dd9fd285a25c93e27dc05200ed1Senpo Hu mStateLock.unlock(); 84d2d86155337a7dd9fd285a25c93e27dc05200ed1Senpo Hu } 85d2d86155337a7dd9fd285a25c93e27dc05200ed1Senpo Hu } 86d2d86155337a7dd9fd285a25c93e27dc05200ed1Senpo Hu 87d2d86155337a7dd9fd285a25c93e27dc05200ed1Senpo Hu @Override 88d2d86155337a7dd9fd285a25c93e27dc05200ed1Senpo Hu public boolean setInitialState(State initialState) { 89d2d86155337a7dd9fd285a25c93e27dc05200ed1Senpo Hu mStateLock.lock(); 90d2d86155337a7dd9fd285a25c93e27dc05200ed1Senpo Hu try { 91d2d86155337a7dd9fd285a25c93e27dc05200ed1Senpo Hu if (!(mState instanceof StateUninitialized)) { 92d2d86155337a7dd9fd285a25c93e27dc05200ed1Senpo Hu return false; 93d2d86155337a7dd9fd285a25c93e27dc05200ed1Senpo Hu } 94d2d86155337a7dd9fd285a25c93e27dc05200ed1Senpo Hu jumpToState(initialState); 95d2d86155337a7dd9fd285a25c93e27dc05200ed1Senpo Hu return true; 96d2d86155337a7dd9fd285a25c93e27dc05200ed1Senpo Hu } finally { 97d2d86155337a7dd9fd285a25c93e27dc05200ed1Senpo Hu mStateLock.unlock(); 98d2d86155337a7dd9fd285a25c93e27dc05200ed1Senpo Hu } 99d2d86155337a7dd9fd285a25c93e27dc05200ed1Senpo Hu } 100d2d86155337a7dd9fd285a25c93e27dc05200ed1Senpo Hu 101d2d86155337a7dd9fd285a25c93e27dc05200ed1Senpo Hu @Override 1021b98e83085e2b0a3066a4bf3cbde2d664b8422eeSenpo Hu public void processEvent(Event event) { 10324be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu mStateLock.lock(); 10424be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu try { 105d2d86155337a7dd9fd285a25c93e27dc05200ed1Senpo Hu EventHandler eventHandler = mState.getEventHandler(event.getClass()); 106d2d86155337a7dd9fd285a25c93e27dc05200ed1Senpo Hu if (eventHandler != null) { 1078950eeb4deed45538d5e5143cd6d0282ed325746Senpo Hu Log.d(TAG, "Process event : " + event); 108d2d86155337a7dd9fd285a25c93e27dc05200ed1Senpo Hu Optional<State> newState = eventHandler.processEvent(event); 109d2d86155337a7dd9fd285a25c93e27dc05200ed1Senpo Hu if (newState.isPresent()) { 110d2d86155337a7dd9fd285a25c93e27dc05200ed1Senpo Hu jumpToState(newState.get()); 111d2d86155337a7dd9fd285a25c93e27dc05200ed1Senpo Hu } 11224be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu } 11324be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu } catch (Exception ex) { 11400562dd0a8451eda80815b3d8fdcb8075e4b9db6Senpo Hu Log.e(TAG, "Failed to process event: " + event); 11500562dd0a8451eda80815b3d8fdcb8075e4b9db6Senpo Hu throw ex; 11624be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu } finally { 11724be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu mStateLock.unlock(); 11824be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu } 11924be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu } 1204908a11eefa7f69129891bc9859029d6b2504efaSenpo Hu 1214908a11eefa7f69129891bc9859029d6b2504efaSenpo Hu /** 1224908a11eefa7f69129891bc9859029d6b2504efaSenpo Hu * The initial state of the state machine. 1234908a11eefa7f69129891bc9859029d6b2504efaSenpo Hu */ 124d2d86155337a7dd9fd285a25c93e27dc05200ed1Senpo Hu public static class StateUninitialized extends StateImpl { 1254908a11eefa7f69129891bc9859029d6b2504efaSenpo Hu public StateUninitialized(StateMachine stateMachine) { 126d2d86155337a7dd9fd285a25c93e27dc05200ed1Senpo Hu super(stateMachine); 1274908a11eefa7f69129891bc9859029d6b2504efaSenpo Hu } 1284908a11eefa7f69129891bc9859029d6b2504efaSenpo Hu } 12924be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu} 130