| /* |
| * Copyright (C) 2011 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 android.filterfw.core; |
| |
| import android.os.AsyncTask; |
| |
| import android.util.Log; |
| |
| /** |
| * @hide |
| */ |
| public class AsyncRunner extends GraphRunner{ |
| |
| private Class mSchedulerClass; |
| private SyncRunner mRunner; |
| private AsyncRunnerTask mRunTask; |
| |
| private OnRunnerDoneListener mDoneListener; |
| private boolean isProcessing; |
| |
| private Exception mException; |
| |
| private class RunnerResult { |
| public int status = RESULT_UNKNOWN; |
| public Exception exception; |
| } |
| |
| private class AsyncRunnerTask extends AsyncTask<SyncRunner, Void, RunnerResult> { |
| |
| private static final String TAG = "AsyncRunnerTask"; |
| |
| @Override |
| protected RunnerResult doInBackground(SyncRunner... runner) { |
| RunnerResult result = new RunnerResult(); |
| try { |
| if (runner.length > 1) { |
| throw new RuntimeException("More than one runner received!"); |
| } |
| |
| runner[0].assertReadyToStep(); |
| |
| // Preparation |
| if (mLogVerbose) Log.v(TAG, "Starting background graph processing."); |
| activateGlContext(); |
| |
| if (mLogVerbose) Log.v(TAG, "Preparing filter graph for processing."); |
| runner[0].beginProcessing(); |
| |
| if (mLogVerbose) Log.v(TAG, "Running graph."); |
| |
| // Run loop |
| result.status = RESULT_RUNNING; |
| while (!isCancelled() && result.status == RESULT_RUNNING) { |
| if (!runner[0].performStep()) { |
| result.status = runner[0].determinePostRunState(); |
| if (result.status == GraphRunner.RESULT_SLEEPING) { |
| runner[0].waitUntilWake(); |
| result.status = RESULT_RUNNING; |
| } |
| } |
| } |
| |
| // Cleanup |
| if (isCancelled()) { |
| result.status = RESULT_STOPPED; |
| } |
| } catch (Exception exception) { |
| result.exception = exception; |
| result.status = RESULT_ERROR; |
| } |
| |
| // Deactivate context. |
| try { |
| deactivateGlContext(); |
| } catch (Exception exception) { |
| result.exception = exception; |
| result.status = RESULT_ERROR; |
| } |
| |
| if (mLogVerbose) Log.v(TAG, "Done with background graph processing."); |
| return result; |
| } |
| |
| @Override |
| protected void onCancelled(RunnerResult result) { |
| onPostExecute(result); |
| } |
| |
| @Override |
| protected void onPostExecute(RunnerResult result) { |
| if (mLogVerbose) Log.v(TAG, "Starting post-execute."); |
| setRunning(false); |
| if (result == null) { |
| // Cancelled before got to doInBackground |
| result = new RunnerResult(); |
| result.status = RESULT_STOPPED; |
| } |
| setException(result.exception); |
| if (result.status == RESULT_STOPPED || result.status == RESULT_ERROR) { |
| if (mLogVerbose) Log.v(TAG, "Closing filters."); |
| try { |
| mRunner.close(); |
| } catch (Exception exception) { |
| result.status = RESULT_ERROR; |
| setException(exception); |
| } |
| } |
| if (mDoneListener != null) { |
| if (mLogVerbose) Log.v(TAG, "Calling graph done callback."); |
| mDoneListener.onRunnerDone(result.status); |
| } |
| if (mLogVerbose) Log.v(TAG, "Completed post-execute."); |
| } |
| } |
| |
| private boolean mLogVerbose; |
| private static final String TAG = "AsyncRunner"; |
| |
| /** Create a new asynchronous graph runner with the given filter |
| * context, and the given scheduler class. |
| * |
| * Must be created on the UI thread. |
| */ |
| public AsyncRunner(FilterContext context, Class schedulerClass) { |
| super(context); |
| |
| mSchedulerClass = schedulerClass; |
| mLogVerbose = Log.isLoggable(TAG, Log.VERBOSE); |
| } |
| |
| /** Create a new asynchronous graph runner with the given filter |
| * context. Uses a default scheduler. |
| * |
| * Must be created on the UI thread. |
| */ |
| public AsyncRunner(FilterContext context) { |
| super(context); |
| |
| mSchedulerClass = SimpleScheduler.class; |
| mLogVerbose = Log.isLoggable(TAG, Log.VERBOSE); |
| } |
| |
| /** Set a callback to be called in the UI thread once the AsyncRunner |
| * completes running a graph, whether the completion is due to a stop() call |
| * or the filters running out of data to process. |
| */ |
| @Override |
| public void setDoneCallback(OnRunnerDoneListener listener) { |
| mDoneListener = listener; |
| } |
| |
| /** Sets the graph to be run. Will call prepare() on graph. Cannot be called |
| * when a graph is already running. |
| */ |
| synchronized public void setGraph(FilterGraph graph) { |
| if (isRunning()) { |
| throw new RuntimeException("Graph is already running!"); |
| } |
| mRunner = new SyncRunner(mFilterContext, graph, mSchedulerClass); |
| } |
| |
| @Override |
| public FilterGraph getGraph() { |
| return mRunner != null ? mRunner.getGraph() : null; |
| } |
| |
| /** Execute the graph in a background thread. */ |
| @Override |
| synchronized public void run() { |
| if (mLogVerbose) Log.v(TAG, "Running graph."); |
| setException(null); |
| |
| if (isRunning()) { |
| throw new RuntimeException("Graph is already running!"); |
| } |
| if (mRunner == null) { |
| throw new RuntimeException("Cannot run before a graph is set!"); |
| } |
| mRunTask = this.new AsyncRunnerTask(); |
| |
| setRunning(true); |
| mRunTask.execute(mRunner); |
| } |
| |
| /** Stop graph execution. This is an asynchronous call; register a callback |
| * with setDoneCallback to be notified of when the background processing has |
| * been completed. Calling stop will close the filter graph. */ |
| @Override |
| synchronized public void stop() { |
| if (mRunTask != null && !mRunTask.isCancelled() ) { |
| if (mLogVerbose) Log.v(TAG, "Stopping graph."); |
| mRunTask.cancel(false); |
| } |
| } |
| |
| @Override |
| synchronized public void close() { |
| if (isRunning()) { |
| throw new RuntimeException("Cannot close graph while it is running!"); |
| } |
| if (mLogVerbose) Log.v(TAG, "Closing filters."); |
| mRunner.close(); |
| } |
| |
| /** Check if background processing is happening */ |
| @Override |
| synchronized public boolean isRunning() { |
| return isProcessing; |
| } |
| |
| @Override |
| synchronized public Exception getError() { |
| return mException; |
| } |
| |
| synchronized private void setRunning(boolean running) { |
| isProcessing = running; |
| } |
| |
| synchronized private void setException(Exception exception) { |
| mException = exception; |
| } |
| |
| } |