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;
1965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
2065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennimport android.content.Context;
2165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennimport android.filterfw.core.AsyncRunner;
2265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennimport android.filterfw.core.FilterGraph;
2365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennimport android.filterfw.core.FilterContext;
2465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennimport android.filterfw.core.FrameManager;
2565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennimport android.filterfw.core.GraphRunner;
2665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennimport android.filterfw.core.RoundRobinScheduler;
2765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennimport android.filterfw.core.SyncRunner;
2865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennimport android.filterfw.io.GraphIOException;
2965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennimport android.filterfw.io.GraphReader;
3065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennimport android.filterfw.io.TextGraphReader;
3165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
3265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennimport java.util.ArrayList;
3365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
3465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn/**
3565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn * A GraphEnvironment provides a simple front-end to filter graph setup and execution using the
3665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn * mobile filter framework. Typically, you use a GraphEnvironment in the following fashion:
3765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn *   1. Instantiate a new GraphEnvironment instance.
3865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn *   2. Perform any configuration, such as adding graph references and setting a GL environment.
3965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn *   3. Load a graph file using loadGraph() or add a graph using addGraph().
4065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn *   4. Obtain a GraphRunner instance using getRunner().
4165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn *   5. Execute the obtained runner.
4265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn * Note that it is possible to add multiple graphs and runners to a single GraphEnvironment.
4365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn *
4465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn * @hide
4565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn */
4665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennpublic class GraphEnvironment extends MffEnvironment {
4765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
4865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    public static final int MODE_ASYNCHRONOUS = 1;
4965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    public static final int MODE_SYNCHRONOUS  = 2;
5065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
5165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    private GraphReader mGraphReader;
5265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    private ArrayList<GraphHandle> mGraphs = new ArrayList<GraphHandle>();
5365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
5465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    private class GraphHandle {
5565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        private FilterGraph mGraph;
5665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        private AsyncRunner mAsyncRunner;
5765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        private SyncRunner mSyncRunner;
5865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
5965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        public GraphHandle(FilterGraph graph) {
6065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn            mGraph = graph;
6165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        }
6265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
6365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        public FilterGraph getGraph() {
6465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn            return mGraph;
6565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        }
6665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
6765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        public AsyncRunner getAsyncRunner(FilterContext environment) {
6865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn            if (mAsyncRunner == null) {
6965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn                mAsyncRunner = new AsyncRunner(environment, RoundRobinScheduler.class);
7065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn                mAsyncRunner.setGraph(mGraph);
7165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn            }
7265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn            return mAsyncRunner;
7365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        }
7465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
7565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        public GraphRunner getSyncRunner(FilterContext environment) {
7665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn            if (mSyncRunner == null) {
7765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn                mSyncRunner = new SyncRunner(environment, mGraph, RoundRobinScheduler.class);
7865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn            }
7965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn            return mSyncRunner;
8065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        }
8165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    }
8265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
8365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    /**
8465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn     * Create a new GraphEnvironment with default components.
8565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn     */
8665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    public GraphEnvironment() {
8765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        super(null);
8865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    }
8965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
9065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    /**
9165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn     * Create a new GraphEnvironment with a custom FrameManager and GraphReader. Specifying null
9265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn     * for either of these, will auto-create a default instance.
9365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn     *
9465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn     * @param frameManager The FrameManager to use, or null to auto-create one.
9565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn     * @param reader        The GraphReader to use for graph loading, or null to auto-create one.
9665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn     *                      Note, that the reader will not be created until it is required. Pass
9765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn     *                      null if you will not load any graph files.
9865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn     */
9965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    public GraphEnvironment(FrameManager frameManager, GraphReader reader) {
10065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        super(frameManager);
10165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        mGraphReader = reader;
10265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    }
10365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
10465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    /**
10565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn     * Returns the used graph reader. This will create one, if a reader has not been set already.
10665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn     */
10765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    public GraphReader getGraphReader() {
10865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        if (mGraphReader == null) {
10965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn            mGraphReader = new TextGraphReader();
11065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        }
11165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        return mGraphReader;
11265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    }
11365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
11465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    /**
11565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn     * Add graph references to resolve during graph reading. The references added here are shared
11665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn     * among all graphs.
11765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn     *
11865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn     * @param references An alternating argument list of keys (Strings) and values.
11965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn     */
12065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    public void addReferences(Object... references) {
12165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        getGraphReader().addReferencesByKeysAndValues(references);
12265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    }
12365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
12465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    /**
12565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn     * Loads a graph file from the specified resource and adds it to this environment.
12665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn     *
12765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn     * @param context       The context in which to read the resource.
12865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn     * @param resourceId    The ID of the graph resource to load.
12965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn     * @return              A unique ID for the graph.
13065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn     */
13165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    public int loadGraph(Context context, int resourceId) {
13265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        // Read the file into a graph
13365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        FilterGraph graph = null;
13465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        try {
13565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn            graph = getGraphReader().readGraphResource(context, resourceId);
13665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        } catch (GraphIOException e) {
13765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn            throw new RuntimeException("Could not read graph: " + e.getMessage());
13865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        }
13965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
14065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        // Add graph to our list of graphs
14165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        return addGraph(graph);
14265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    }
14365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
14465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    /**
14565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn     * Add a graph to the environment. Consider using loadGraph() if you are loading a graph from
14665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn     * a graph file.
14765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn     *
14865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn     * @param graph The graph to add to the environment.
14965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn     * @return      A unique ID for the added graph.
15065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn     */
15165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    public int addGraph(FilterGraph graph) {
15265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        GraphHandle graphHandle = new GraphHandle(graph);
15365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        mGraphs.add(graphHandle);
15465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        return mGraphs.size() - 1;
15565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    }
15665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
15765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    /**
15865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn     * Access a specific graph of this environment given a graph ID (previously returned from
15965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn     * loadGraph() or addGraph()). Throws an InvalidArgumentException if no graph with the
16065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn     * specified ID could be found.
16165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn     *
16265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn     * @param graphId   The ID of the graph to get.
16365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn     * @return          The graph with the specified ID.
16465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn     */
16565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    public FilterGraph getGraph(int graphId) {
16665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        if (graphId < 0 || graphId >= mGraphs.size()) {
16765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn            throw new IllegalArgumentException(
16865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn                "Invalid graph ID " + graphId + " specified in runGraph()!");
16965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        }
17065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        return mGraphs.get(graphId).getGraph();
17165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    }
17265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
17365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    /**
17465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn     * Get a GraphRunner instance for the graph with the specified ID. The GraphRunner instance can
17565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn     * be used to execute the graph. Throws an InvalidArgumentException if no graph with the
17665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn     * specified ID could be found.
17765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn     *
17865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn     * @param graphId       The ID of the graph to get.
17965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn     * @param executionMode The mode of graph execution. Currently this can be either
18065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn                            MODE_SYNCHRONOUS or MODE_ASYNCHRONOUS.
18165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn     * @return              A GraphRunner instance for this graph.
18265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn     */
18365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    public GraphRunner getRunner(int graphId, int executionMode) {
18465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        switch (executionMode) {
18565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn            case MODE_ASYNCHRONOUS:
18665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn                return mGraphs.get(graphId).getAsyncRunner(getContext());
18765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
18865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn            case MODE_SYNCHRONOUS:
18965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn                return mGraphs.get(graphId).getSyncRunner(getContext());
19065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
19165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn            default:
19265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn                throw new RuntimeException(
19365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn                    "Invalid execution mode " + executionMode + " specified in getRunner()!");
19465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        }
19565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    }
19665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
19765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn}
198