• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2011 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 
18 package android.filterfw.core;
19 
20 import android.os.AsyncTask;
21 
22 import android.util.Log;
23 
24 /**
25  * @hide
26  */
27 public class AsyncRunner extends GraphRunner{
28 
29     private Class mSchedulerClass;
30     private SyncRunner mRunner;
31     private AsyncRunnerTask mRunTask;
32 
33     private OnRunnerDoneListener mDoneListener;
34     private boolean isProcessing;
35 
36     private Exception mException;
37 
38     private class RunnerResult {
39         public int status = RESULT_UNKNOWN;
40         public Exception exception;
41     }
42 
43     private class AsyncRunnerTask extends AsyncTask<SyncRunner, Void, RunnerResult> {
44 
45         private static final String TAG = "AsyncRunnerTask";
46 
47         @Override
doInBackground(SyncRunner... runner)48         protected RunnerResult doInBackground(SyncRunner... runner) {
49             RunnerResult result = new RunnerResult();
50             try {
51                 if (runner.length > 1) {
52                     throw new RuntimeException("More than one runner received!");
53                 }
54 
55                 runner[0].assertReadyToStep();
56 
57                 // Preparation
58                 if (mLogVerbose) Log.v(TAG, "Starting background graph processing.");
59                 activateGlContext();
60 
61                 if (mLogVerbose) Log.v(TAG, "Preparing filter graph for processing.");
62                 runner[0].beginProcessing();
63 
64                 if (mLogVerbose) Log.v(TAG, "Running graph.");
65 
66                 // Run loop
67                 result.status = RESULT_RUNNING;
68                 while (!isCancelled() && result.status == RESULT_RUNNING) {
69                     if (!runner[0].performStep()) {
70                         result.status = runner[0].determinePostRunState();
71                         if (result.status == GraphRunner.RESULT_SLEEPING) {
72                             runner[0].waitUntilWake();
73                             result.status = RESULT_RUNNING;
74                         }
75                     }
76                 }
77 
78                 // Cleanup
79                 if (isCancelled()) {
80                     result.status = RESULT_STOPPED;
81                 }
82             } catch (Exception exception) {
83                 result.exception = exception;
84                 result.status = RESULT_ERROR;
85             }
86 
87             // Deactivate context.
88             try {
89                 deactivateGlContext();
90             } catch (Exception exception) {
91                 result.exception = exception;
92                 result.status = RESULT_ERROR;
93             }
94 
95             if (mLogVerbose) Log.v(TAG, "Done with background graph processing.");
96             return result;
97         }
98 
99         @Override
onCancelled(RunnerResult result)100         protected void onCancelled(RunnerResult result) {
101             onPostExecute(result);
102         }
103 
104         @Override
onPostExecute(RunnerResult result)105         protected void onPostExecute(RunnerResult result) {
106             if (mLogVerbose) Log.v(TAG, "Starting post-execute.");
107             setRunning(false);
108             if (result == null) {
109                 // Cancelled before got to doInBackground
110                 result = new RunnerResult();
111                 result.status = RESULT_STOPPED;
112             }
113             setException(result.exception);
114             if (result.status == RESULT_STOPPED || result.status == RESULT_ERROR) {
115                 if (mLogVerbose) Log.v(TAG, "Closing filters.");
116                 try {
117                     mRunner.close();
118                 } catch (Exception exception) {
119                     result.status = RESULT_ERROR;
120                     setException(exception);
121                 }
122             }
123             if (mDoneListener != null) {
124                 if (mLogVerbose) Log.v(TAG, "Calling graph done callback.");
125                 mDoneListener.onRunnerDone(result.status);
126             }
127             if (mLogVerbose) Log.v(TAG, "Completed post-execute.");
128         }
129     }
130 
131     private boolean mLogVerbose;
132     private static final String TAG = "AsyncRunner";
133 
134     /** Create a new asynchronous graph runner with the given filter
135      * context, and the given scheduler class.
136      *
137      * Must be created on the UI thread.
138      */
AsyncRunner(FilterContext context, Class schedulerClass)139     public AsyncRunner(FilterContext context, Class schedulerClass) {
140         super(context);
141 
142         mSchedulerClass = schedulerClass;
143         mLogVerbose = Log.isLoggable(TAG, Log.VERBOSE);
144     }
145 
146     /** Create a new asynchronous graph runner with the given filter
147      * context. Uses a default scheduler.
148      *
149      * Must be created on the UI thread.
150      */
AsyncRunner(FilterContext context)151     public AsyncRunner(FilterContext context) {
152         super(context);
153 
154         mSchedulerClass = SimpleScheduler.class;
155         mLogVerbose = Log.isLoggable(TAG, Log.VERBOSE);
156     }
157 
158     /** Set a callback to be called in the UI thread once the AsyncRunner
159      * completes running a graph, whether the completion is due to a stop() call
160      * or the filters running out of data to process.
161      */
162     @Override
setDoneCallback(OnRunnerDoneListener listener)163     public void setDoneCallback(OnRunnerDoneListener listener) {
164         mDoneListener = listener;
165     }
166 
167     /** Sets the graph to be run. Will call prepare() on graph. Cannot be called
168      * when a graph is already running.
169      */
setGraph(FilterGraph graph)170     synchronized public void setGraph(FilterGraph graph) {
171         if (isRunning()) {
172             throw new RuntimeException("Graph is already running!");
173         }
174         mRunner = new SyncRunner(mFilterContext, graph, mSchedulerClass);
175     }
176 
177     @Override
getGraph()178     public FilterGraph getGraph() {
179         return mRunner != null ? mRunner.getGraph() : null;
180     }
181 
182     /** Execute the graph in a background thread. */
183     @Override
run()184     synchronized public void run() {
185         if (mLogVerbose) Log.v(TAG, "Running graph.");
186         setException(null);
187 
188         if (isRunning()) {
189             throw new RuntimeException("Graph is already running!");
190         }
191         if (mRunner == null) {
192             throw new RuntimeException("Cannot run before a graph is set!");
193         }
194         mRunTask = this.new AsyncRunnerTask();
195 
196         setRunning(true);
197         mRunTask.execute(mRunner);
198     }
199 
200     /** Stop graph execution. This is an asynchronous call; register a callback
201      * with setDoneCallback to be notified of when the background processing has
202      * been completed. Calling stop will close the filter graph. */
203     @Override
stop()204     synchronized public void stop() {
205         if (mRunTask != null && !mRunTask.isCancelled() ) {
206             if (mLogVerbose) Log.v(TAG, "Stopping graph.");
207             mRunTask.cancel(false);
208         }
209     }
210 
211     @Override
close()212     synchronized public void close() {
213         if (isRunning()) {
214             throw new RuntimeException("Cannot close graph while it is running!");
215         }
216         if (mLogVerbose) Log.v(TAG, "Closing filters.");
217         mRunner.close();
218     }
219 
220     /** Check if background processing is happening */
221     @Override
isRunning()222     synchronized public boolean isRunning() {
223         return isProcessing;
224     }
225 
226     @Override
getError()227     synchronized public Exception getError() {
228         return mException;
229     }
230 
setRunning(boolean running)231     synchronized private void setRunning(boolean running) {
232         isProcessing = running;
233     }
234 
setException(Exception exception)235     synchronized private void setException(Exception exception) {
236         mException = exception;
237     }
238 
239 }
240