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