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.filterfw.core.FilterContext;
     21 import android.filterfw.core.FilterPort;
     22 import android.filterfw.core.KeyValueMap;
     23 import android.filterfw.io.TextGraphReader;
     24 import android.filterfw.io.GraphIOException;
     25 import android.filterfw.format.ObjectFormat;
     26 import android.util.Log;
     27 
     28 import java.io.Serializable;
     29 import java.lang.annotation.Annotation;
     30 import java.lang.reflect.Field;
     31 import java.lang.Thread;
     32 import java.util.Collection;
     33 import java.util.HashMap;
     34 import java.util.HashSet;
     35 import java.util.Map.Entry;
     36 import java.util.Set;
     37 
     38 /**
     39  * @hide
     40  */
     41 public abstract class Filter {
     42 
     43     static final int STATUS_PREINIT               = 0;
     44     static final int STATUS_UNPREPARED            = 1;
     45     static final int STATUS_PREPARED              = 2;
     46     static final int STATUS_PROCESSING            = 3;
     47     static final int STATUS_SLEEPING              = 4;
     48     static final int STATUS_FINISHED              = 5;
     49     static final int STATUS_ERROR                 = 6;
     50     static final int STATUS_RELEASED              = 7;
     51 
     52     private String mName;
     53 
     54     private int mInputCount = -1;
     55     private int mOutputCount = -1;
     56 
     57     private HashMap<String, InputPort> mInputPorts;
     58     private HashMap<String, OutputPort> mOutputPorts;
     59 
     60     private HashSet<Frame> mFramesToRelease;
     61     private HashMap<String, Frame> mFramesToSet;
     62 
     63     private int mStatus = 0;
     64     private boolean mIsOpen = false;
     65     private int mSleepDelay;
     66 
     67     private long mCurrentTimestamp;
     68 
     69     private boolean mLogVerbose;
     70     private static final String TAG = "Filter";
     71 
     72     public Filter(String name) {
     73         mName = name;
     74         mFramesToRelease = new HashSet<Frame>();
     75         mFramesToSet = new HashMap<String, Frame>();
     76         mStatus = STATUS_PREINIT;
     77 
     78         mLogVerbose = Log.isLoggable(TAG, Log.VERBOSE);
     79     }
     80 
     81     /** Tests to see if a given filter is installed on the system. Requires
     82      * full filter package name, including filterpack.
     83      */
     84     public static final boolean isAvailable(String filterName) {
     85         ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
     86         Class filterClass;
     87         // First see if a class of that name exists
     88         try {
     89             filterClass = contextClassLoader.loadClass(filterName);
     90         } catch (ClassNotFoundException e) {
     91             return false;
     92         }
     93         // Then make sure it's a subclass of Filter.
     94         try {
     95             filterClass.asSubclass(Filter.class);
     96         } catch (ClassCastException e) {
     97             return false;
     98         }
     99         return true;
    100     }
    101 
    102     public final void initWithValueMap(KeyValueMap valueMap) {
    103         // Initialization
    104         initFinalPorts(valueMap);
    105 
    106         // Setup remaining ports
    107         initRemainingPorts(valueMap);
    108 
    109         // This indicates that final ports can no longer be set
    110         mStatus = STATUS_UNPREPARED;
    111     }
    112 
    113     public final void initWithAssignmentString(String assignments) {
    114         try {
    115             KeyValueMap valueMap = new TextGraphReader().readKeyValueAssignments(assignments);
    116             initWithValueMap(valueMap);
    117         } catch (GraphIOException e) {
    118             throw new IllegalArgumentException(e.getMessage());
    119         }
    120     }
    121 
    122     public final void initWithAssignmentList(Object... keyValues) {
    123         KeyValueMap valueMap = new KeyValueMap();
    124         valueMap.setKeyValues(keyValues);
    125         initWithValueMap(valueMap);
    126     }
    127 
    128     public final void init() throws ProtocolException {
    129         KeyValueMap valueMap = new KeyValueMap();
    130         initWithValueMap(valueMap);
    131     }
    132 
    133     public String getFilterClassName() {
    134         return getClass().getSimpleName();
    135     }
    136 
    137     public final String getName() {
    138         return mName;
    139     }
    140 
    141     public boolean isOpen() {
    142         return mIsOpen;
    143     }
    144 
    145     public void setInputFrame(String inputName, Frame frame) {
    146         FilterPort port = getInputPort(inputName);
    147         if (!port.isOpen()) {
    148             port.open();
    149         }
    150         port.setFrame(frame);
    151     }
    152 
    153     public final void setInputValue(String inputName, Object value) {
    154         setInputFrame(inputName, wrapInputValue(inputName, value));
    155     }
    156 
    157     protected void prepare(FilterContext context) {
    158     }
    159 
    160     protected void parametersUpdated(Set<String> updated) {
    161     }
    162 
    163     protected void delayNextProcess(int millisecs) {
    164         mSleepDelay = millisecs;
    165         mStatus = STATUS_SLEEPING;
    166     }
    167 
    168     public abstract void setupPorts();
    169 
    170     public FrameFormat getOutputFormat(String portName, FrameFormat inputFormat) {
    171         return null;
    172     }
    173 
    174     public final FrameFormat getInputFormat(String portName) {
    175         InputPort inputPort = getInputPort(portName);
    176         return inputPort.getSourceFormat();
    177     }
    178 
    179     public void open(FilterContext context) {
    180     }
    181 
    182     public abstract void process(FilterContext context);
    183 
    184     public final int getSleepDelay() {
    185         return 250;
    186     }
    187 
    188     public void close(FilterContext context) {
    189     }
    190 
    191     public void tearDown(FilterContext context) {
    192     }
    193 
    194     public final int getNumberOfConnectedInputs() {
    195         int c = 0;
    196         for (InputPort inputPort : mInputPorts.values()) {
    197             if (inputPort.isConnected()) {
    198                 ++c;
    199             }
    200         }
    201         return c;
    202     }
    203 
    204     public final int getNumberOfConnectedOutputs() {
    205         int c = 0;
    206         for (OutputPort outputPort : mOutputPorts.values()) {
    207             if (outputPort.isConnected()) {
    208                 ++c;
    209             }
    210         }
    211         return c;
    212     }
    213 
    214     public final int getNumberOfInputs() {
    215         return mOutputPorts == null ? 0 : mInputPorts.size();
    216     }
    217 
    218     public final int getNumberOfOutputs() {
    219         return mInputPorts == null ? 0 : mOutputPorts.size();
    220     }
    221 
    222     public final InputPort getInputPort(String portName) {
    223         if (mInputPorts == null) {
    224             throw new NullPointerException("Attempting to access input port '" + portName
    225                 + "' of " + this + " before Filter has been initialized!");
    226         }
    227         InputPort result = mInputPorts.get(portName);
    228         if (result == null) {
    229             throw new IllegalArgumentException("Unknown input port '" + portName + "' on filter "
    230                 + this + "!");
    231         }
    232         return result;
    233     }
    234 
    235     public final OutputPort getOutputPort(String portName) {
    236         if (mInputPorts == null) {
    237             throw new NullPointerException("Attempting to access output port '" + portName
    238                 + "' of " + this + " before Filter has been initialized!");
    239         }
    240         OutputPort result = mOutputPorts.get(portName);
    241         if (result == null) {
    242             throw new IllegalArgumentException("Unknown output port '" + portName + "' on filter "
    243                 + this + "!");
    244         }
    245         return result;
    246     }
    247 
    248     protected final void pushOutput(String name, Frame frame) {
    249         if (frame.getTimestamp() == Frame.TIMESTAMP_NOT_SET) {
    250             if (mLogVerbose) Log.v(TAG, "Default-setting output Frame timestamp on port " + name + " to " + mCurrentTimestamp);
    251             frame.setTimestamp(mCurrentTimestamp);
    252         }
    253         getOutputPort(name).pushFrame(frame);
    254     }
    255 
    256     protected final Frame pullInput(String name) {
    257         Frame result = getInputPort(name).pullFrame();
    258         if (mCurrentTimestamp == Frame.TIMESTAMP_UNKNOWN) {
    259             mCurrentTimestamp = result.getTimestamp();
    260             if (mLogVerbose) Log.v(TAG, "Default-setting current timestamp from input port " + name + " to " + mCurrentTimestamp);
    261         }
    262         // As result is retained, we add it to the release pool here
    263         mFramesToRelease.add(result);
    264 
    265         return result;
    266     }
    267 
    268     public void fieldPortValueUpdated(String name, FilterContext context) {
    269     }
    270 
    271     /**
    272      * Transfers any frame from an input port to its destination. This is useful to force a
    273      * transfer from a FieldPort or ProgramPort to its connected target (field or program variable).
    274      */
    275     protected void transferInputPortFrame(String name, FilterContext context) {
    276         getInputPort(name).transfer(context);
    277     }
    278 
    279     /**
    280      * Assigns all program variables to the ports they are connected to. Call this after
    281      * constructing a Program instance with attached ProgramPorts.
    282      */
    283     protected void initProgramInputs(Program program, FilterContext context) {
    284         if (program != null) {
    285             for (InputPort inputPort : mInputPorts.values()) {
    286                 if (inputPort.getTarget() == program) {
    287                     inputPort.transfer(context);
    288                 }
    289             }
    290         }
    291     }
    292 
    293     /**
    294      * Adds an input port to the filter. You should call this from within setupPorts, if your
    295      * filter has input ports. No type-checking is performed on the input. If you would like to
    296      * check against a type mask, use
    297      * {@link #addMaskedInputPort(String, FrameFormat) addMaskedInputPort} instead.
    298      *
    299      * @param name the name of the input port
    300      */
    301     protected void addInputPort(String name) {
    302         addMaskedInputPort(name, null);
    303     }
    304 
    305     /**
    306      * Adds an input port to the filter. You should call this from within setupPorts, if your
    307      * filter has input ports. When type-checking is performed, the input format is
    308      * checked against the provided format mask. An exception is thrown in case of a conflict.
    309      *
    310      * @param name the name of the input port
    311      * @param formatMask a format mask, which filters the allowable input types
    312      */
    313     protected void addMaskedInputPort(String name, FrameFormat formatMask) {
    314         InputPort port = new StreamPort(this, name);
    315         if (mLogVerbose) Log.v(TAG, "Filter " + this + " adding " + port);
    316         mInputPorts.put(name, port);
    317         port.setPortFormat(formatMask);
    318     }
    319 
    320     /**
    321      * Adds an output port to the filter with a fixed output format. You should call this from
    322      * within setupPorts, if your filter has output ports. You cannot use this method, if your
    323      * output format depends on the input format (e.g. in a pass-through filter). In this case, use
    324      * {@link #addOutputBasedOnInput(String, String) addOutputBasedOnInput} instead.
    325      *
    326      * @param name the name of the output port
    327      * @param format the fixed output format of this port
    328      */
    329     protected void addOutputPort(String name, FrameFormat format) {
    330         OutputPort port = new OutputPort(this, name);
    331         if (mLogVerbose) Log.v(TAG, "Filter " + this + " adding " + port);
    332         port.setPortFormat(format);
    333         mOutputPorts.put(name, port);
    334     }
    335 
    336     /**
    337      * Adds an output port to the filter. You should call this from within setupPorts, if your
    338      * filter has output ports. Using this method indicates that the output format for this
    339      * particular port, depends on the format of an input port. You MUST also override
    340      * {@link #getOutputFormat(String, FrameFormat) getOutputFormat} to specify what format your
    341      * filter will output for a given input. If the output format of your filter port does not
    342      * depend on the input, use {@link #addOutputPort(String, FrameFormat) addOutputPort} instead.
    343      *
    344      * @param outputName the name of the output port
    345      * @param inputName the name of the input port, that this output depends on
    346      */
    347     protected void addOutputBasedOnInput(String outputName, String inputName) {
    348         OutputPort port = new OutputPort(this, outputName);
    349         if (mLogVerbose) Log.v(TAG, "Filter " + this + " adding " + port);
    350         port.setBasePort(getInputPort(inputName));
    351         mOutputPorts.put(outputName, port);
    352     }
    353 
    354     protected void addFieldPort(String name,
    355                                 Field field,
    356                                 boolean hasDefault,
    357                                 boolean isFinal) {
    358         // Make sure field is accessible
    359         field.setAccessible(true);
    360 
    361         // Create port for this input
    362         InputPort fieldPort = isFinal
    363             ? new FinalPort(this, name, field, hasDefault)
    364             : new FieldPort(this, name, field, hasDefault);
    365 
    366         // Create format for this input
    367         if (mLogVerbose) Log.v(TAG, "Filter " + this + " adding " + fieldPort);
    368         MutableFrameFormat format = ObjectFormat.fromClass(field.getType(),
    369                                                            FrameFormat.TARGET_SIMPLE);
    370         fieldPort.setPortFormat(format);
    371 
    372         // Add port
    373         mInputPorts.put(name, fieldPort);
    374     }
    375 
    376     protected void addProgramPort(String name,
    377                                   String varName,
    378                                   Field field,
    379                                   Class varType,
    380                                   boolean hasDefault) {
    381         // Make sure field is accessible
    382         field.setAccessible(true);
    383 
    384         // Create port for this input
    385         InputPort programPort = new ProgramPort(this, name, varName, field, hasDefault);
    386 
    387         // Create format for this input
    388         if (mLogVerbose) Log.v(TAG, "Filter " + this + " adding " + programPort);
    389         MutableFrameFormat format = ObjectFormat.fromClass(varType,
    390                                                            FrameFormat.TARGET_SIMPLE);
    391         programPort.setPortFormat(format);
    392 
    393         // Add port
    394         mInputPorts.put(name, programPort);
    395     }
    396 
    397     protected void closeOutputPort(String name) {
    398         getOutputPort(name).close();
    399     }
    400 
    401     /**
    402      * Specifies whether the filter should not be scheduled until a frame is available on that
    403      * input port. Note, that setting this to false, does not block a new frame from coming in
    404      * (though there is no necessity to pull that frame for processing).
    405      * @param portName the name of the input port.
    406      * @param waits true, if the filter should wait for a frame on this port.
    407      */
    408     protected void setWaitsOnInputPort(String portName, boolean waits) {
    409         getInputPort(portName).setBlocking(waits);
    410     }
    411 
    412     /**
    413      * Specifies whether the filter should not be scheduled until the output port is free, i.e.
    414      * there is no frame waiting on that output.
    415      * @param portName the name of the output port.
    416      * @param waits true, if the filter should wait for the port to become free.
    417      */
    418     protected void setWaitsOnOutputPort(String portName, boolean waits) {
    419         getOutputPort(portName).setBlocking(waits);
    420     }
    421 
    422     public String toString() {
    423         return "'" + getName() + "' (" + getFilterClassName() + ")";
    424     }
    425 
    426     // Core internal methods ///////////////////////////////////////////////////////////////////////
    427     final Collection<InputPort> getInputPorts() {
    428         return mInputPorts.values();
    429     }
    430 
    431     final Collection<OutputPort> getOutputPorts() {
    432         return mOutputPorts.values();
    433     }
    434 
    435     final synchronized int getStatus() {
    436         return mStatus;
    437     }
    438 
    439     final synchronized void unsetStatus(int flag) {
    440         mStatus &= ~flag;
    441     }
    442 
    443     final synchronized void performOpen(FilterContext context) {
    444         if (!mIsOpen) {
    445             if (mStatus == STATUS_UNPREPARED) {
    446                 if (mLogVerbose) Log.v(TAG, "Preparing " + this);
    447                 prepare(context);
    448                 mStatus = STATUS_PREPARED;
    449             }
    450             if (mStatus == STATUS_PREPARED) {
    451                 if (mLogVerbose) Log.v(TAG, "Opening " + this);
    452                 open(context);
    453                 mStatus = STATUS_PROCESSING;
    454             }
    455             if (mStatus != STATUS_PROCESSING) {
    456                 throw new RuntimeException("Filter " + this + " was brought into invalid state during "
    457                     + "opening (state: " + mStatus + ")!");
    458             }
    459             mIsOpen = true;
    460         }
    461     }
    462 
    463     final synchronized void performProcess(FilterContext context) {
    464         if (mStatus == STATUS_RELEASED) {
    465             throw new RuntimeException("Filter " + this + " is already torn down!");
    466         }
    467         transferInputFrames(context);
    468         if (mStatus < STATUS_PROCESSING) {
    469             performOpen(context);
    470         }
    471         if (mLogVerbose) Log.v(TAG, "Processing " + this);
    472         mCurrentTimestamp = Frame.TIMESTAMP_UNKNOWN;
    473         process(context);
    474         releasePulledFrames(context);
    475         if (filterMustClose()) {
    476             performClose(context);
    477         }
    478     }
    479 
    480     final synchronized void performClose(FilterContext context) {
    481         if (mIsOpen) {
    482             if (mLogVerbose) Log.v(TAG, "Closing " + this);
    483             mIsOpen = false;
    484             mStatus = STATUS_PREPARED;
    485             close(context);
    486             closePorts();
    487         }
    488     }
    489 
    490     final synchronized void performTearDown(FilterContext context) {
    491         performClose(context);
    492         if (mStatus != STATUS_RELEASED) {
    493             tearDown(context);
    494             mStatus = STATUS_RELEASED;
    495         }
    496     }
    497 
    498     synchronized final boolean canProcess() {
    499         if (mLogVerbose) Log.v(TAG, "Checking if can process: " + this + " (" + mStatus + ").");
    500         if (mStatus <= STATUS_PROCESSING) {
    501             return inputConditionsMet() && outputConditionsMet();
    502         } else {
    503             return false;
    504         }
    505     }
    506 
    507     final void openOutputs() {
    508         if (mLogVerbose) Log.v(TAG, "Opening all output ports on " + this + "!");
    509         for (OutputPort outputPort : mOutputPorts.values()) {
    510             if (!outputPort.isOpen()) {
    511                 outputPort.open();
    512             }
    513         }
    514     }
    515 
    516     final void clearInputs() {
    517         for (InputPort inputPort : mInputPorts.values()) {
    518             inputPort.clear();
    519         }
    520     }
    521 
    522     final void clearOutputs() {
    523         for (OutputPort outputPort : mOutputPorts.values()) {
    524             outputPort.clear();
    525         }
    526     }
    527 
    528     final void notifyFieldPortValueUpdated(String name, FilterContext context) {
    529         if (mStatus == STATUS_PROCESSING || mStatus == STATUS_PREPARED) {
    530             fieldPortValueUpdated(name, context);
    531         }
    532     }
    533 
    534     final synchronized void pushInputFrame(String inputName, Frame frame) {
    535         FilterPort port = getInputPort(inputName);
    536         if (!port.isOpen()) {
    537             port.open();
    538         }
    539         port.pushFrame(frame);
    540     }
    541 
    542     final synchronized void pushInputValue(String inputName, Object value) {
    543         pushInputFrame(inputName, wrapInputValue(inputName, value));
    544     }
    545 
    546     // Filter internal methods /////////////////////////////////////////////////////////////////////
    547     private final void initFinalPorts(KeyValueMap values) {
    548         mInputPorts = new HashMap<String, InputPort>();
    549         mOutputPorts = new HashMap<String, OutputPort>();
    550         addAndSetFinalPorts(values);
    551     }
    552 
    553     private final void initRemainingPorts(KeyValueMap values) {
    554         addAnnotatedPorts();
    555         setupPorts();   // TODO: rename to addFilterPorts() ?
    556         setInitialInputValues(values);
    557     }
    558 
    559     private final void addAndSetFinalPorts(KeyValueMap values) {
    560         Class filterClass = getClass();
    561         Annotation annotation;
    562         for (Field field : filterClass.getDeclaredFields()) {
    563             if ((annotation = field.getAnnotation(GenerateFinalPort.class)) != null) {
    564                 GenerateFinalPort generator = (GenerateFinalPort)annotation;
    565                 String name = generator.name().isEmpty() ? field.getName() : generator.name();
    566                 boolean hasDefault = generator.hasDefault();
    567                 addFieldPort(name, field, hasDefault, true);
    568                 if (values.containsKey(name)) {
    569                     setImmediateInputValue(name, values.get(name));
    570                     values.remove(name);
    571                 } else if (!generator.hasDefault()) {
    572                     throw new RuntimeException("No value specified for final input port '"
    573                         + name + "' of filter " + this + "!");
    574                 }
    575             }
    576         }
    577     }
    578 
    579     private final void addAnnotatedPorts() {
    580         Class filterClass = getClass();
    581         Annotation annotation;
    582         for (Field field : filterClass.getDeclaredFields()) {
    583             if ((annotation = field.getAnnotation(GenerateFieldPort.class)) != null) {
    584                 GenerateFieldPort generator = (GenerateFieldPort)annotation;
    585                 addFieldGenerator(generator, field);
    586             } else if ((annotation = field.getAnnotation(GenerateProgramPort.class)) != null) {
    587                 GenerateProgramPort generator = (GenerateProgramPort)annotation;
    588                 addProgramGenerator(generator, field);
    589             } else if ((annotation = field.getAnnotation(GenerateProgramPorts.class)) != null) {
    590                 GenerateProgramPorts generators = (GenerateProgramPorts)annotation;
    591                 for (GenerateProgramPort generator : generators.value()) {
    592                     addProgramGenerator(generator, field);
    593                 }
    594             }
    595         }
    596     }
    597 
    598     private final void addFieldGenerator(GenerateFieldPort generator, Field field) {
    599         String name = generator.name().isEmpty() ? field.getName() : generator.name();
    600         boolean hasDefault = generator.hasDefault();
    601         addFieldPort(name, field, hasDefault, false);
    602     }
    603 
    604     private final void addProgramGenerator(GenerateProgramPort generator, Field field) {
    605         String name = generator.name();
    606         String varName = generator.variableName().isEmpty() ? name
    607                                                             : generator.variableName();
    608         Class varType = generator.type();
    609         boolean hasDefault = generator.hasDefault();
    610         addProgramPort(name, varName, field, varType, hasDefault);
    611     }
    612 
    613     private final void setInitialInputValues(KeyValueMap values) {
    614         for (Entry<String, Object> entry : values.entrySet()) {
    615             setInputValue(entry.getKey(), entry.getValue());
    616         }
    617     }
    618 
    619     private final void setImmediateInputValue(String name, Object value) {
    620         if (mLogVerbose) Log.v(TAG, "Setting immediate value " + value + " for port " + name + "!");
    621         FilterPort port = getInputPort(name);
    622         port.open();
    623         port.setFrame(SimpleFrame.wrapObject(value, null));
    624     }
    625 
    626     private final void transferInputFrames(FilterContext context) {
    627         for (InputPort inputPort : mInputPorts.values()) {
    628             inputPort.transfer(context);
    629         }
    630     }
    631 
    632     private final Frame wrapInputValue(String inputName, Object value) {
    633         MutableFrameFormat inputFormat = ObjectFormat.fromObject(value, FrameFormat.TARGET_SIMPLE);
    634         if (value == null) {
    635             // If the value is null, the format cannot guess the class, so we adjust it to the
    636             // class of the input port here
    637             FrameFormat portFormat = getInputPort(inputName).getPortFormat();
    638             Class portClass = (portFormat == null) ? null : portFormat.getObjectClass();
    639             inputFormat.setObjectClass(portClass);
    640         }
    641 
    642         // Serialize if serializable, and type is not an immutable primitive.
    643         boolean shouldSerialize = !(value instanceof Number)
    644             && !(value instanceof Boolean)
    645             && !(value instanceof String)
    646             && value instanceof Serializable;
    647 
    648         // Create frame wrapper
    649         Frame frame = shouldSerialize
    650             ? new SerializedFrame(inputFormat, null)
    651             : new SimpleFrame(inputFormat, null);
    652         frame.setObjectValue(value);
    653         return frame;
    654     }
    655 
    656     private final void releasePulledFrames(FilterContext context) {
    657         for (Frame frame : mFramesToRelease) {
    658             context.getFrameManager().releaseFrame(frame);
    659         }
    660         mFramesToRelease.clear();
    661     }
    662 
    663     private final boolean inputConditionsMet() {
    664         for (FilterPort port : mInputPorts.values()) {
    665             if (!port.isReady()) {
    666                 if (mLogVerbose) Log.v(TAG, "Input condition not met: " + port + "!");
    667                 return false;
    668             }
    669         }
    670         return true;
    671     }
    672 
    673     private final boolean outputConditionsMet() {
    674         for (FilterPort port : mOutputPorts.values()) {
    675             if (!port.isReady()) {
    676                 if (mLogVerbose) Log.v(TAG, "Output condition not met: " + port + "!");
    677                 return false;
    678             }
    679         }
    680         return true;
    681     }
    682 
    683     private final void closePorts() {
    684         if (mLogVerbose) Log.v(TAG, "Closing all ports on " + this + "!");
    685         for (InputPort inputPort : mInputPorts.values()) {
    686             inputPort.close();
    687         }
    688         for (OutputPort outputPort : mOutputPorts.values()) {
    689             outputPort.close();
    690         }
    691     }
    692 
    693     private final boolean filterMustClose() {
    694         for (InputPort inputPort : mInputPorts.values()) {
    695             if (inputPort.filterMustClose()) {
    696                 if (mLogVerbose) Log.v(TAG, "Filter " + this + " must close due to port " + inputPort);
    697                 return true;
    698             }
    699         }
    700         for (OutputPort outputPort : mOutputPorts.values()) {
    701             if (outputPort.filterMustClose()) {
    702                 if (mLogVerbose) Log.v(TAG, "Filter " + this + " must close due to port " + outputPort);
    703                 return true;
    704             }
    705         }
    706         return false;
    707     }
    708 }
    709