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