165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn/*
265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn * Copyright (C) 2011 The Android Open Source Project
365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn *
465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn * Licensed under the Apache License, Version 2.0 (the "License");
565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn * you may not use this file except in compliance with the License.
665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn * You may obtain a copy of the License at
765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn *
865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn *      http://www.apache.org/licenses/LICENSE-2.0
965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn *
1065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn * Unless required by applicable law or agreed to in writing, software
1165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn * distributed under the License is distributed on an "AS IS" BASIS,
1265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn * See the License for the specific language governing permissions and
1465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn * limitations under the License.
1565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn */
1665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
1765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
1865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennpackage android.filterfw.core;
1965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
2065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennimport android.os.ConditionVariable;
2165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennimport android.util.Log;
2265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
2365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennimport java.lang.reflect.Constructor;
2465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennimport java.lang.reflect.InvocationTargetException;
2565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennimport java.util.concurrent.ScheduledThreadPoolExecutor;
2665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennimport java.util.concurrent.TimeUnit;
2765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
2865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn/**
2965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn * @hide
3065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn */
3165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennpublic class SyncRunner extends GraphRunner {
3265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
3365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    private Scheduler mScheduler = null;
3465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
3565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    private OnRunnerDoneListener mDoneListener = null;
3665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    private ScheduledThreadPoolExecutor mWakeExecutor = new ScheduledThreadPoolExecutor(1);
3765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    private ConditionVariable mWakeCondition = new ConditionVariable();
3865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
3965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    private StopWatchMap mTimer = null;
4065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
4165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    private final boolean mLogVerbose;
4265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    private final static String TAG = "SyncRunner";
4365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
4465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    // TODO: Provide factory based constructor?
4565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    public SyncRunner(FilterContext context, FilterGraph graph, Class schedulerClass) {
4665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        super(context);
4765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
4865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        mLogVerbose = Log.isLoggable(TAG, Log.VERBOSE);
4965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
5065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        if (mLogVerbose) Log.v(TAG, "Initializing SyncRunner");
5165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
5265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        // Create the scheduler
5365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        if (Scheduler.class.isAssignableFrom(schedulerClass)) {
5465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn            try {
5565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn                Constructor schedulerConstructor = schedulerClass.getConstructor(FilterGraph.class);
5665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn                mScheduler = (Scheduler)schedulerConstructor.newInstance(graph);
5765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn            } catch (NoSuchMethodException e) {
5865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn                throw new RuntimeException("Scheduler does not have constructor <init>(FilterGraph)!", e);
5965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn            } catch (InstantiationException e) {
6065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn                throw new RuntimeException("Could not instantiate the Scheduler instance!", e);
6165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn            } catch (IllegalAccessException e) {
6265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn                throw new RuntimeException("Cannot access Scheduler constructor!", e);
6365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn            } catch (InvocationTargetException e) {
6465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn                throw new RuntimeException("Scheduler constructor threw an exception", e);
6565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn            } catch (Exception e) {
6665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn                throw new RuntimeException("Could not instantiate Scheduler", e);
6765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn            }
6865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        } else {
6965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn            throw new IllegalArgumentException("Class provided is not a Scheduler subclass!");
7065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        }
7165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
7265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        // Associate this runner and the graph with the context
7365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        mFilterContext = context;
7465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        mFilterContext.addGraph(graph);
7565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
7665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        mTimer = new StopWatchMap();
7765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
7865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        if (mLogVerbose) Log.v(TAG, "Setting up filters");
7965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
8065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        // Setup graph filters
8165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        graph.setupFilters();
8265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    }
8365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
8465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    @Override
8565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    public FilterGraph getGraph() {
8665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        return mScheduler != null ? mScheduler.getGraph() : null;
8765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    }
8865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
8965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    public int step() {
9065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        assertReadyToStep();
9165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        if (!getGraph().isReady() ) {
9265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn            throw new RuntimeException("Trying to process graph that is not open!");
9365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        }
9465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        return performStep() ? RESULT_RUNNING : determinePostRunState();
9565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    }
9665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
9765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    public void beginProcessing() {
9865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        mScheduler.reset();
9965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        getGraph().beginProcessing();
10065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    }
10165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
10265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    public void close() {
10365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        // Close filters
10465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        if (mLogVerbose) Log.v(TAG, "Closing graph.");
10565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        getGraph().closeFilters(mFilterContext);
10665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        mScheduler.reset();
10765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    }
10865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
10965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    @Override
11065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    public void run() {
11165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        if (mLogVerbose) Log.v(TAG, "Beginning run.");
11265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
11365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        assertReadyToStep();
11465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
11565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        // Preparation
11665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        beginProcessing();
11765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        boolean glActivated = activateGlContext();
11865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
11965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        // Run
12065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        boolean keepRunning = true;
12165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        while (keepRunning) {
12265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn            keepRunning = performStep();
12365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        }
12465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
12565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        // Cleanup
12665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        if (glActivated) {
12765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn            deactivateGlContext();
12865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        }
12965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
13065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        // Call completion callback if set
13165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        if (mDoneListener != null) {
13265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn            if (mLogVerbose) Log.v(TAG, "Calling completion listener.");
13365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn            mDoneListener.onRunnerDone(determinePostRunState());
13465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        }
13565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        if (mLogVerbose) Log.v(TAG, "Run complete");
13665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    }
13765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
13865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    @Override
13965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    public boolean isRunning() {
14065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        return false;
14165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    }
14265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
14365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    @Override
14465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    public void setDoneCallback(OnRunnerDoneListener listener) {
14565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        mDoneListener = listener;
14665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    }
14765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
14865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    @Override
14965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    public void stop() {
15065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        throw new RuntimeException("SyncRunner does not support stopping a graph!");
15165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    }
15265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
15365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    @Override
15465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    synchronized public Exception getError() {
15565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        return null;
15665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    }
15765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
15865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    protected void waitUntilWake() {
15965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        mWakeCondition.block();
16065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    }
16165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
16265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    protected void processFilterNode(Filter filter) {
16365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        if (mLogVerbose) Log.v(TAG, "Processing filter node");
16465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        filter.performProcess(mFilterContext);
16565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        if (filter.getStatus() == Filter.STATUS_ERROR) {
16665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn            throw new RuntimeException("There was an error executing " + filter + "!");
16765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        } else if (filter.getStatus() == Filter.STATUS_SLEEPING) {
16865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn            if (mLogVerbose) Log.v(TAG, "Scheduling filter wakeup");
16965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn            scheduleFilterWake(filter, filter.getSleepDelay());
17065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        }
17165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    }
17265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
17365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    protected void scheduleFilterWake(Filter filter, int delay) {
17465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        // Close the wake condition
17565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        mWakeCondition.close();
17665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
17765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        // Schedule the wake-up
17865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        final Filter filterToSchedule = filter;
17965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        final ConditionVariable conditionToWake = mWakeCondition;
18065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
18165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        mWakeExecutor.schedule(new Runnable() {
18265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn          @Override
18365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn          public void run() {
18465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn                filterToSchedule.unsetStatus(Filter.STATUS_SLEEPING);
18565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn                conditionToWake.open();
18665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn            }
18765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        }, delay, TimeUnit.MILLISECONDS);
18865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    }
18965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
19065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    protected int determinePostRunState() {
19165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        boolean isBlocked = false;
19265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        for (Filter filter : mScheduler.getGraph().getFilters()) {
19365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn            if (filter.isOpen()) {
19465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn                if (filter.getStatus() == Filter.STATUS_SLEEPING) {
19565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn                    // If ANY node is sleeping, we return our state as sleeping
19665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn                    return RESULT_SLEEPING;
19765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn                } else {
19865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn                    // If a node is still open, it is blocked (by input or output)
19965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn                    return RESULT_BLOCKED;
20065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn                }
20165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn            }
20265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        }
20365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        return RESULT_FINISHED;
20465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    }
20565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
20665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    // Core internal methods ///////////////////////////////////////////////////////////////////////
20765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    boolean performStep() {
20865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        if (mLogVerbose) Log.v(TAG, "Performing one step.");
20965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        Filter filter = mScheduler.scheduleNextNode();
21065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        if (filter != null) {
21165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn            mTimer.start(filter.getName());
21265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn            processFilterNode(filter);
21365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn            mTimer.stop(filter.getName());
21465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn            return true;
21565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        } else {
21665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn            return false;
21765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        }
21865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    }
21965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
22065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    void assertReadyToStep() {
22165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        if (mScheduler == null) {
22265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn            throw new RuntimeException("Attempting to run schedule with no scheduler in place!");
22365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        } else if (getGraph() == null) {
22465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn            throw new RuntimeException("Calling step on scheduler with no graph in place!");
22565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        }
22665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    }
22765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn}
228