Home | History | Annotate | Download | only in core
      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
     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
    100         protected void onCancelled(RunnerResult result) {
    101             onPostExecute(result);
    102         }
    103 
    104         @Override
    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      */
    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      */
    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
    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      */
    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
    178     public FilterGraph getGraph() {
    179         return mRunner != null ? mRunner.getGraph() : null;
    180     }
    181 
    182     /** Execute the graph in a background thread. */
    183     @Override
    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
    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
    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
    222     synchronized public boolean isRunning() {
    223         return isProcessing;
    224     }
    225 
    226     @Override
    227     synchronized public Exception getError() {
    228         return mException;
    229     }
    230 
    231     synchronized private void setRunning(boolean running) {
    232         isProcessing = running;
    233     }
    234 
    235     synchronized private void setException(Exception exception) {
    236         mException = exception;
    237     }
    238 
    239 }
    240