Refactor filters parameters
- introduce FilterRepresentations
- change filters lifecycle

Change-Id: I9416fca47a334d532a347cd5577795738c870933
diff --git a/src/com/android/gallery3d/filtershow/FilterShowActivity.java b/src/com/android/gallery3d/filtershow/FilterShowActivity.java
index 83ea06d..7719c04 100644
--- a/src/com/android/gallery3d/filtershow/FilterShowActivity.java
+++ b/src/com/android/gallery3d/filtershow/FilterShowActivity.java
@@ -62,13 +62,7 @@
 import com.android.gallery3d.filtershow.editors.BasicEditor;
 import com.android.gallery3d.filtershow.editors.EditorDraw;
 import com.android.gallery3d.filtershow.editors.EditorManager;
-import com.android.gallery3d.filtershow.filters.FiltersManager;
-import com.android.gallery3d.filtershow.filters.ImageFilter;
-import com.android.gallery3d.filtershow.filters.ImageFilterBorder;
-import com.android.gallery3d.filtershow.filters.ImageFilterFx;
-import com.android.gallery3d.filtershow.filters.ImageFilterParametricBorder;
-import com.android.gallery3d.filtershow.filters.ImageFilterRS;
-import com.android.gallery3d.filtershow.filters.ImageFilterRedEye;
+import com.android.gallery3d.filtershow.filters.*;
 import com.android.gallery3d.filtershow.imageshow.ImageCrop;
 import com.android.gallery3d.filtershow.imageshow.ImageDraw;
 import com.android.gallery3d.filtershow.imageshow.ImageFlip;
@@ -288,7 +282,6 @@
         FiltersManager.addFilters(filters, mImageLoader);
 
         for (ImageFilter filter : filters) {
-            filter.setParameter(filter.getDefaultParameter());
             filter.setName(getString(filter.getTextId()));
             setupFilterButton(filter, listColors, mColorsButton);
         }
@@ -714,6 +707,10 @@
             text = "";
         }
         icon.setup(text, filter, this, panel);
+        // TODO: get rid of hasDefaultRepresentation()
+        if (filter.hasDefaultRepresentation()) {
+            icon.setFilterRepresentation(filter.getDefaultRepresentation());
+        }
         icon.setId(filter.getButtonId());
         mPanelController.addComponent(button, icon);
         mPanelController.addFilter(filter);
@@ -973,20 +970,23 @@
                 r.getDisplayMetrics());
     }
 
-    public void useFilter(ImageFilter filter) {
-        if (mMasterImage.getCurrentFilter() == filter) {
+    public void useFilterRepresentation(FilterRepresentation filterRepresentation) {
+        if (filterRepresentation == null) {
+            return;
+        }
+        if (mMasterImage.getCurrentFilterRepresentation() == filterRepresentation) {
             return;
         }
         ImagePreset oldPreset = mMasterImage.getPreset();
         ImagePreset copy = new ImagePreset(oldPreset);
-
-        ImageFilter existingFilter = copy.getFilter(filter.getName());
-        if (existingFilter == null) {
-            copy.add(filter);
+        FilterRepresentation representation = copy.getRepresentation(filterRepresentation);
+        if (representation == null) {
+            copy.addFilter(filterRepresentation);
+        } else {
+            filterRepresentation = representation;
         }
-        existingFilter = copy.getFilter(filter.getName());
         mMasterImage.setPreset(copy, true);
-        mMasterImage.setCurrentFilter(existingFilter);
+        mMasterImage.setCurrentFilterRepresentation(filterRepresentation);
         invalidateViews();
     }
 
diff --git a/src/com/android/gallery3d/filtershow/ImageStateAdapter.java b/src/com/android/gallery3d/filtershow/ImageStateAdapter.java
index 44b94e4..5de9696 100644
--- a/src/com/android/gallery3d/filtershow/ImageStateAdapter.java
+++ b/src/com/android/gallery3d/filtershow/ImageStateAdapter.java
@@ -46,7 +46,8 @@
             TextView itemLabel = (TextView) view.findViewById(R.id.imagestate_label);
             itemLabel.setText(filter.getName());
             TextView itemParameter = (TextView) view.findViewById(R.id.imagestate_parameter);
-            itemParameter.setText("" + filter.getParameter());
+            // TODO: fix the image state adapter
+            // itemParameter.setText("" + filter.getParameter());
         }
         return view;
     }
diff --git a/src/com/android/gallery3d/filtershow/PanelController.java b/src/com/android/gallery3d/filtershow/PanelController.java
index a0b13fb..ff168bc 100644
--- a/src/com/android/gallery3d/filtershow/PanelController.java
+++ b/src/com/android/gallery3d/filtershow/PanelController.java
@@ -359,6 +359,7 @@
     public void showDefaultImageView() {
         showImageView(R.id.imageShow).setShowControls(false);
         mMasterImage.setCurrentFilter(null);
+        mMasterImage.setCurrentFilterRepresentation(null);
     }
 
     public void showPanel(View view) {
@@ -415,6 +416,7 @@
 
     // TODO: remove this.
     public void ensureFilter(String name) {
+        /*
         ImagePreset preset = getImagePreset();
         ImageFilter filter = preset.getFilter(name);
         if (filter != null) {
@@ -441,6 +443,7 @@
         if (filter != null) {
             mMasterImage.setCurrentFilter(filter);
         }
+        */
     }
 
     public void showComponent(View view) {
@@ -483,8 +486,6 @@
                 mUtilityPanel.setEffectName(ename);
 
                 mUtilityPanel.setShowParameter(filter.showParameterValue());
-                ImageFilter currentFilter = mMasterImage.getPreset().getFilter(filter.getName());
-                mMasterImage.setCurrentFilter(currentFilter);
                 mCurrentImage.select();
                 if (mCurrentEditor != null) {
                     mCurrentEditor.reflectCurrentFilter();
diff --git a/src/com/android/gallery3d/filtershow/cache/FilteringPipeline.java b/src/com/android/gallery3d/filtershow/cache/FilteringPipeline.java
index d415250..69f91ac 100644
--- a/src/com/android/gallery3d/filtershow/cache/FilteringPipeline.java
+++ b/src/com/android/gallery3d/filtershow/cache/FilteringPipeline.java
@@ -22,11 +22,16 @@
 import android.support.v8.renderscript.*;
 import android.util.Log;
 
+import com.android.gallery3d.filtershow.filters.FilterRepresentation;
+import com.android.gallery3d.filtershow.filters.ImageFilter;
 import com.android.gallery3d.filtershow.filters.ImageFilterRS;
+import com.android.gallery3d.filtershow.filters.ImageFilterVignette;
 import com.android.gallery3d.filtershow.imageshow.GeometryMetadata;
 import com.android.gallery3d.filtershow.imageshow.MasterImage;
 import com.android.gallery3d.filtershow.presets.ImagePreset;
 
+import java.util.HashMap;
+
 public class FilteringPipeline implements Handler.Callback {
 
     private final static FilteringPipeline gPipeline = new FilteringPipeline();
@@ -235,17 +240,12 @@
     }
 
     private void compute(TripleBufferBitmap buffer, ImagePreset preset, int type) {
-        String thread = Thread.currentThread().getName();
-        if (type == COMPUTE_PRESET && preset.same(mPreviousPreset)) {
-            mPreviousPreset.usePreset(preset);
-            preset = mPreviousPreset;
-        } else if (type == COMPUTE_GEOMETRY_PRESET && preset.same(mPreviousGeometryPreset)) {
-            mPreviousGeometryPreset.usePreset(preset);
-            preset = mPreviousGeometryPreset;
-        } else if (type == COMPUTE_FILTERS_PRESET && preset.same(mPreviousFiltersPreset)) {
-            mPreviousFiltersPreset.usePreset(preset);
-            preset = mPreviousFiltersPreset;
+        if (DEBUG) {
+            Log.v(LOGTAG, "compute preset " + preset);
+            preset.showFilters();
         }
+
+        String thread = Thread.currentThread().getName();
         long time = System.currentTimeMillis();
         if (updateOriginalAllocation(preset)) {
             buffer.updateBitmaps(mResizedOriginalBitmap);
diff --git a/src/com/android/gallery3d/filtershow/editors/BasicEditor.java b/src/com/android/gallery3d/filtershow/editors/BasicEditor.java
index 1ea0da7..fa3bd4a 100644
--- a/src/com/android/gallery3d/filtershow/editors/BasicEditor.java
+++ b/src/com/android/gallery3d/filtershow/editors/BasicEditor.java
@@ -17,7 +17,7 @@
 package com.android.gallery3d.filtershow.editors;
 
 import com.android.gallery3d.R;
-import com.android.gallery3d.filtershow.filters.ImageFilter;
+import com.android.gallery3d.filtershow.filters.*;
 
 import android.content.Context;
 import android.util.Log;
@@ -61,35 +61,35 @@
 
     @Override
     public void reflectCurrentFilter() {
-        ImageFilter filter = mImageShow.getCurrentFilter();
-        if (filter == null) {
-            return;
+        FilterRepresentation filterRepresentation = MasterImage.getImage().getCurrentFilterRepresentation();
+        if (filterRepresentation != null && filterRepresentation instanceof FilterBasicRepresentation) {
+            FilterBasicRepresentation interval = (FilterBasicRepresentation) filterRepresentation;
+            boolean f = interval.showParameterValue();
+            mSeekBar.setVisibility((f) ? View.VISIBLE : View.INVISIBLE);
+            int value = interval.getValue();
+            int min = interval.getMinimum();
+            int max = interval.getMaximum();
+            mSeekBar.setMax(max - min);
+            mSeekBar.setProgress(value - min);
         }
-        boolean f = filter.showParameterValue();
-        mSeekBar.setVisibility((f) ? View.VISIBLE : View.INVISIBLE);
-        int parameter = filter.getParameter();
-        int maxp = filter.getMaxParameter();
-        int minp = filter.getMinParameter();
-        mSeekBar.setMax(maxp - minp);
-        mSeekBar.setProgress(parameter - minp);
     }
 
     @Override
     public void onProgressChanged(SeekBar sbar, int progress, boolean arg2) {
-        ImageFilter filter = mImageShow.getCurrentFilter();
-        if (filter == null) {
-            return;
-        }
-        int minp = filter.getMinParameter();
-        int value = progress + minp;
-        mImageShow.onNewValue(value);
-        mView.invalidate();
-        if (filter.showParameterValue()) {
-            mPanelController.onNewValue(value);
-        }
+        FilterRepresentation filterRepresentation = MasterImage.getImage().getCurrentFilterRepresentation();
+        if (filterRepresentation != null && filterRepresentation instanceof FilterBasicRepresentation) {
+            FilterBasicRepresentation interval = (FilterBasicRepresentation) filterRepresentation;
+            int value = progress + interval.getMinimum();
+            interval.setValue(value);
+            mImageShow.onNewValue(value);
+            mView.invalidate();
+            if (interval.showParameterValue()) {
+                mPanelController.onNewValue(value);
+            }
 
-        Log.v(LOGTAG, "    #### progress=" + value);
-        MasterImage.getImage().updateBuffers();
+            Log.v(LOGTAG, "    #### progress=" + value);
+            MasterImage.getImage().updateBuffers();
+        }
     }
 
     @Override
diff --git a/src/com/android/gallery3d/filtershow/editors/EditorDraw.java b/src/com/android/gallery3d/filtershow/editors/EditorDraw.java
index abd4ae4..a31c1d3 100644
--- a/src/com/android/gallery3d/filtershow/editors/EditorDraw.java
+++ b/src/com/android/gallery3d/filtershow/editors/EditorDraw.java
@@ -94,8 +94,6 @@
             @Override
             public boolean onMenuItemClick(MenuItem item) {
                 ImageFilterDraw filter = (ImageFilterDraw) mImageShow.getCurrentFilter();
-                int minp = filter.getMinParameter();
-                int parameter = filter.getParameter();
                 if (item.getItemId() == R.id.draw_menu_color) {
                     showColorGrid(item);
                 } else if (item.getItemId() == R.id.draw_menu_size) {
diff --git a/src/com/android/gallery3d/filtershow/filters/FilterBasicRepresentation.java b/src/com/android/gallery3d/filtershow/filters/FilterBasicRepresentation.java
new file mode 100644
index 0000000..9e9c57a
--- /dev/null
+++ b/src/com/android/gallery3d/filtershow/filters/FilterBasicRepresentation.java
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) 2013 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 com.android.gallery3d.filtershow.filters;
+
+import com.android.gallery3d.app.Log;
+
+public class FilterBasicRepresentation extends FilterRepresentation {
+    private static final String LOGTAG = "FilterBasicRepresentation";
+    private int mMinimum;
+    private int mValue;
+    private int mMaximum;
+    private int mDefaultValue;
+    private int mPreviewValue;
+
+    public FilterBasicRepresentation(String name, int minimum, int value, int maximum) {
+        super(name);
+        mMinimum = minimum;
+        mMaximum = maximum;
+        setValue(value);
+    }
+
+    public String toString() {
+        return getName() + " : " + mMinimum + " < " + mValue + " < " + mMaximum;
+    }
+
+    @Override
+    public FilterRepresentation clone() throws CloneNotSupportedException {
+        FilterBasicRepresentation representation = (FilterBasicRepresentation) super.clone();
+        representation.setMinimum(getMinimum());
+        representation.setMaximum(getMaximum());
+        representation.setValue(getValue());
+        Log.v(LOGTAG, "cloning from <" + this + "> to <" + representation + ">");
+        return representation;
+    }
+
+    public void useParametersFrom(FilterRepresentation a) {
+        if (a instanceof FilterBasicRepresentation) {
+            FilterBasicRepresentation representation = (FilterBasicRepresentation) a;
+            setMinimum(representation.getMinimum());
+            setMaximum(representation.getMaximum());
+            setValue(representation.getValue());
+            setDefaultValue(representation.getDefaultValue());
+            setPreviewValue(representation.getPreviewValue());
+        }
+    }
+
+    @Override
+    public boolean equals(FilterRepresentation representation) {
+        if (super.equals(representation)) {
+            return false;
+        }
+        if (representation instanceof FilterBasicRepresentation) {
+            FilterBasicRepresentation basic = (FilterBasicRepresentation) representation;
+            if (basic.mMinimum == mMinimum
+                    && basic.mMaximum == mMaximum
+                    && basic.mValue == mValue
+                    && basic.mDefaultValue == mDefaultValue
+                    && basic.mPreviewValue == mPreviewValue) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    public int getMinimum() {
+        return mMinimum;
+    }
+
+    public void setMinimum(int minimum) {
+        mMinimum = minimum;
+    }
+
+    public int getValue() {
+        return mValue;
+    }
+
+    public void setValue(int value) {
+        mValue = value;
+        if (mValue < mMinimum) {
+            mValue = mMinimum;
+        }
+        if (mValue > mMaximum) {
+            mValue = mMaximum;
+        }
+    }
+
+    public int getMaximum() {
+        return mMaximum;
+    }
+
+    public void setMaximum(int maximum) {
+        mMaximum = maximum;
+    }
+
+    public void setDefaultValue(int defaultValue) {
+        mDefaultValue = defaultValue;
+    }
+
+    public int getDefaultValue() {
+        return mDefaultValue;
+    }
+
+    public int getPreviewValue() {
+        return mPreviewValue;
+    }
+
+    public void setPreviewValue(int previewValue) {
+        mPreviewValue = previewValue;
+    }
+}
diff --git a/src/com/android/gallery3d/filtershow/filters/FilterDirectRepresentation.java b/src/com/android/gallery3d/filtershow/filters/FilterDirectRepresentation.java
new file mode 100644
index 0000000..3807ee1
--- /dev/null
+++ b/src/com/android/gallery3d/filtershow/filters/FilterDirectRepresentation.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2013 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 com.android.gallery3d.filtershow.filters;
+
+public class FilterDirectRepresentation extends FilterRepresentation {
+
+    public FilterDirectRepresentation(String name) {
+        super(name);
+    }
+
+    public boolean isNil() {
+        return true;
+    }
+
+}
diff --git a/src/com/android/gallery3d/filtershow/filters/FilterRepresentation.java b/src/com/android/gallery3d/filtershow/filters/FilterRepresentation.java
new file mode 100644
index 0000000..afa6ad1
--- /dev/null
+++ b/src/com/android/gallery3d/filtershow/filters/FilterRepresentation.java
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2013 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 com.android.gallery3d.filtershow.filters;
+
+import com.android.gallery3d.app.Log;
+import com.android.gallery3d.filtershow.presets.ImagePreset;
+
+import java.util.HashMap;
+
+public class FilterRepresentation implements Cloneable {
+    private static final String LOGTAG = "FilterRepresentation";
+    private String mName;
+    private int mPriority;
+    private ImagePreset mPreset;
+    private boolean mShowParameterValue;
+    private Class mFilterClass;
+
+    public static String DEFAULT = "Default";
+
+    public FilterRepresentation(String name) {
+        mName = name;
+    }
+
+    @Override
+    public FilterRepresentation clone() throws CloneNotSupportedException {
+        FilterRepresentation representation = (FilterRepresentation) super.clone();
+        representation.setName(getName());
+        representation.setPriority(getPriority());
+        Log.v(LOGTAG, "cloning from <" + this + "> to <" + representation + ">");
+        return representation;
+    }
+
+    public boolean equals(FilterRepresentation representation) {
+        if (representation.mFilterClass == representation.mFilterClass
+                && representation.mName.equalsIgnoreCase(mName)
+                && representation.mPriority == mPriority
+                && representation.mShowParameterValue == mShowParameterValue) {
+            return true;
+        }
+        return false;
+    }
+
+    public String toString() {
+        return mName;
+    }
+
+    public void setName(String name) {
+        mName = name;
+    }
+
+    public String getName() {
+        return mName;
+    }
+
+    public void setPriority(int priority) {
+        mPriority = priority;
+    }
+
+    public int getPriority() {
+        return mPriority;
+    }
+
+    public void setImagePreset(ImagePreset preset) {
+        mPreset = preset;
+    }
+
+    public boolean isNil() {
+        return false;
+    }
+
+    public void useParametersFrom(FilterRepresentation a) {
+    }
+
+    public void setShowParameterValue(boolean showParameterValue) {
+        mShowParameterValue = showParameterValue;
+    }
+
+    public boolean showParameterValue() {
+        return mShowParameterValue;
+    }
+
+    public Class getFilterClass() {
+        return mFilterClass;
+    }
+
+    public void setFilterClass(Class filterClass) {
+        mFilterClass = filterClass;
+    }
+
+    public boolean same(FilterRepresentation b) {
+        if (b == null) {
+            return false;
+        }
+        return getFilterClass() == b.getFilterClass();
+    }
+}
diff --git a/src/com/android/gallery3d/filtershow/filters/ImageFilter.java b/src/com/android/gallery3d/filtershow/filters/ImageFilter.java
index a261031..abf65c4 100644
--- a/src/com/android/gallery3d/filtershow/filters/ImageFilter.java
+++ b/src/com/android/gallery3d/filtershow/filters/ImageFilter.java
@@ -24,15 +24,6 @@
 
 public class ImageFilter implements Cloneable {
 
-    public static int DEFAULT_MAX_PARAMETER = 100;
-    public static int DEFAULT_MIN_PARAMETER = -100;
-    public static int DEFAULT_INITIAL_PARAMETER = 0;
-
-    protected int mMaxParameter = DEFAULT_MAX_PARAMETER;
-    protected int mMinParameter = DEFAULT_MIN_PARAMETER;
-    protected int mPreviewParameter = mMaxParameter;
-    protected int mDefaultParameter = DEFAULT_INITIAL_PARAMETER;
-    protected int mParameter = DEFAULT_INITIAL_PARAMETER;
     private ImagePreset mImagePreset;
 
     protected String mName = "Original";
@@ -81,31 +72,6 @@
         return true;
     }
 
-    @Override
-    public ImageFilter clone() throws CloneNotSupportedException {
-        ImageFilter filter = (ImageFilter) super.clone();
-        filter.setName(getName());
-        filter.setParameter(getParameter());
-        filter.setFilterType(filterType);
-        filter.mMaxParameter = mMaxParameter;
-        filter.mMinParameter = mMinParameter;
-        filter.mImagePreset = mImagePreset;
-        filter.mDefaultParameter = mDefaultParameter;
-        filter.mPreviewParameter = mPreviewParameter;
-        return filter;
-    }
-
-    public void reset() {
-        setParameter(mDefaultParameter);
-    }
-
-    public boolean isNil() {
-        if (mParameter == mDefaultParameter) {
-            return true;
-        }
-        return false;
-    }
-
     public void setName(String name) {
         mName = name;
     }
@@ -124,68 +90,17 @@
      * Override this to provide filter-specific button icons.
      */
     public Bitmap iconApply(Bitmap bitmap, float scaleFactor, boolean highQuality) {
-        int param = getParameter();
-        setParameter(getPreviewParameter());
-        bitmap = apply(bitmap, scaleFactor, highQuality);
-        setParameter(param);
-        return bitmap;
-    }
-
-    public int getParameter() {
-        return mParameter;
-    }
-
-    public void setParameter(int value) {
-        mParameter = value;
-    }
-
-    /**
-     * The maximum allowed value (inclusive)
-     * @return maximum value allowed as input to this filter
-     */
-    public int getMaxParameter() {
-        return mMaxParameter;
-    }
-
-    /**
-     * The parameter value to be used in previews.
-     * @return parameter value to be used to preview the filter
-     */
-    public int getPreviewParameter() {
-        return mPreviewParameter;
-    }
-
-    /**
-     * The minimum allowed value (inclusive)
-     * @return minimum value allowed as input to this filter
-     */
-    public int getMinParameter() {
-        return mMinParameter;
-    }
-
-    /**
-     * Returns the default value returned by this filter.
-     * @return default value
-     */
-    public int getDefaultParameter() {
-        return mDefaultParameter;
+        return apply(bitmap, scaleFactor, highQuality);
     }
 
     public ImagePreset getImagePreset() {
         return mImagePreset;
     }
 
-    public void setImagePreset(ImagePreset mPreset) {
-        this.mImagePreset = mPreset;
-    }
-
     public boolean equals(ImageFilter filter) {
         if (!same(filter)) {
             return false;
         }
-        if (mParameter != filter.mParameter) {
-            return false;
-        }
         return true;
     }
 
@@ -199,10 +114,17 @@
         return true;
     }
 
+    public void useRepresentation(FilterRepresentation representation) {
+    }
+
     native protected void nativeApplyGradientFilter(Bitmap bitmap, int w, int h,
             int[] redGradient, int[] greenGradient, int[] blueGradient);
 
-    public void useFilter(ImageFilter a) {
-        setParameter(a.getParameter());
+    public FilterRepresentation getDefaultRepresentation() {
+        return null;
+    }
+
+    public boolean hasDefaultRepresentation() {
+        return false;
     }
 }
diff --git a/src/com/android/gallery3d/filtershow/filters/ImageFilterBorder.java b/src/com/android/gallery3d/filtershow/filters/ImageFilterBorder.java
index 4fe3082..7d8152b 100644
--- a/src/com/android/gallery3d/filtershow/filters/ImageFilterBorder.java
+++ b/src/com/android/gallery3d/filtershow/filters/ImageFilterBorder.java
@@ -41,7 +41,6 @@
         mNinePatch = ninePatch;
     }
 
-    @Override
     public boolean isNil() {
         if (mNinePatch == null) {
             return true;
diff --git a/src/com/android/gallery3d/filtershow/filters/ImageFilterBwFilter.java b/src/com/android/gallery3d/filtershow/filters/ImageFilterBwFilter.java
index 1bb5c76..1c06323 100644
--- a/src/com/android/gallery3d/filtershow/filters/ImageFilterBwFilter.java
+++ b/src/com/android/gallery3d/filtershow/filters/ImageFilterBwFilter.java
@@ -22,12 +22,19 @@
 import android.graphics.Color;
 
 
-public class ImageFilterBwFilter extends ImageFilter {
+public class ImageFilterBwFilter extends SimpleImageFilter {
 
     public ImageFilterBwFilter() {
         mName = "BW Filter";
-        mMaxParameter = 180;
-        mMinParameter = -180;
+    }
+
+    public FilterRepresentation getDefaultRepresentation() {
+        FilterBasicRepresentation representation = (FilterBasicRepresentation) super.getDefaultRepresentation();
+        representation.setName("BW Filter");
+        representation.setFilterClass(ImageFilterBwFilter.class);
+        representation.setMaximum(180);
+        representation.setMinimum(-180);
+        return representation;
     }
 
     @Override
@@ -50,10 +57,13 @@
 
     @Override
     public Bitmap apply(Bitmap bitmap, float scaleFactor, boolean highQuality) {
+        if (getParameters() == null) {
+            return bitmap;
+        }
         int w = bitmap.getWidth();
         int h = bitmap.getHeight();
         float[] hsv = new float[] {
-                180 + mParameter, 1, 1
+                180 + getParameters().getValue(), 1, 1
         };
         int rgb = Color.HSVToColor(hsv);
         int r = 0xFF & (rgb >> 16);
diff --git a/src/com/android/gallery3d/filtershow/filters/ImageFilterContrast.java b/src/com/android/gallery3d/filtershow/filters/ImageFilterContrast.java
index 70e3d85..7e78589 100644
--- a/src/com/android/gallery3d/filtershow/filters/ImageFilterContrast.java
+++ b/src/com/android/gallery3d/filtershow/filters/ImageFilterContrast.java
@@ -20,12 +20,19 @@
 
 import android.graphics.Bitmap;
 
-public class ImageFilterContrast extends ImageFilter {
+public class ImageFilterContrast extends SimpleImageFilter {
 
     public ImageFilterContrast() {
         mName = "Contrast";
     }
 
+    public FilterRepresentation getDefaultRepresentation() {
+        FilterRepresentation representation = super.getDefaultRepresentation();
+        representation.setName("Contrast");
+        representation.setFilterClass(ImageFilterContrast.class);
+        return representation;
+    }
+
     @Override
     public int getButtonId() {
         return R.id.contrastButton;
@@ -40,10 +47,12 @@
 
     @Override
     public Bitmap apply(Bitmap bitmap, float scaleFactor, boolean highQuality) {
+        if (getParameters() == null) {
+            return bitmap;
+        }
         int w = bitmap.getWidth();
         int h = bitmap.getHeight();
-        float p = mParameter;
-        float value = p;
+        float value = getParameters().getValue();
         nativeApplyFilter(bitmap, w, h, value);
         return bitmap;
     }
diff --git a/src/com/android/gallery3d/filtershow/filters/ImageFilterCurves.java b/src/com/android/gallery3d/filtershow/filters/ImageFilterCurves.java
index b7e5c2a..15cf046 100644
--- a/src/com/android/gallery3d/filtershow/filters/ImageFilterCurves.java
+++ b/src/com/android/gallery3d/filtershow/filters/ImageFilterCurves.java
@@ -74,7 +74,6 @@
         return filter;
     }
 
-    @Override
     public boolean isNil() {
         for (int i = 0; i < 4; i++) {
             if (mSplines[i] != null && !mSplines[i].isOriginal()) {
@@ -148,7 +147,6 @@
         return mSplines[splineIndex];
     }
 
-    @Override
     public void reset() {
         Spline spline = new Spline();
 
@@ -160,7 +158,7 @@
         }
     }
 
-    @Override
+    // TODO: fix useFilter
     public void useFilter(ImageFilter a) {
         ImageFilterCurves c = (ImageFilterCurves) a;
         for (int i = 0; i < 4; i++) {
diff --git a/src/com/android/gallery3d/filtershow/filters/ImageFilterDownsample.java b/src/com/android/gallery3d/filtershow/filters/ImageFilterDownsample.java
index 784028a..c2b6481 100644
--- a/src/com/android/gallery3d/filtershow/filters/ImageFilterDownsample.java
+++ b/src/com/android/gallery3d/filtershow/filters/ImageFilterDownsample.java
@@ -23,20 +23,27 @@
 import com.android.gallery3d.R;
 import com.android.gallery3d.filtershow.cache.ImageLoader;
 
-public class ImageFilterDownsample extends ImageFilter {
+public class ImageFilterDownsample extends SimpleImageFilter {
     private static final int ICON_DOWNSAMPLE_FRACTION = 8;
     private ImageLoader mImageLoader;
 
     public ImageFilterDownsample(ImageLoader loader) {
         mName = "Downsample";
-        mMaxParameter = 100;
-        mMinParameter = 1;
-        mPreviewParameter = 3;
-        mDefaultParameter = 50;
-        mParameter = 50;
         mImageLoader = loader;
     }
 
+    public FilterRepresentation getDefaultRepresentation() {
+        FilterBasicRepresentation representation = (FilterBasicRepresentation) super.getDefaultRepresentation();
+        representation.setName("Downsample");
+        representation.setFilterClass(ImageFilterDownsample.class);
+        representation.setMaximum(100);
+        representation.setMinimum(1);
+        representation.setValue(50);
+        representation.setDefaultValue(50);
+        representation.setPreviewValue(3);
+        return representation;
+    }
+
     @Override
     public int getButtonId() {
         return R.id.downsampleButton;
@@ -48,15 +55,13 @@
     }
 
     @Override
-    public boolean isNil() {
-        return false;
-    }
-
-    @Override
     public Bitmap apply(Bitmap bitmap, float scaleFactor, boolean highQuality) {
+        if (getParameters() == null) {
+            return bitmap;
+        }
         int w = bitmap.getWidth();
         int h = bitmap.getHeight();
-        int p = mParameter;
+        int p = getParameters().getValue();
 
         // size of original precached image
         Rect size = mImageLoader.getOriginalBounds();
diff --git a/src/com/android/gallery3d/filtershow/filters/ImageFilterDraw.java b/src/com/android/gallery3d/filtershow/filters/ImageFilterDraw.java
index 3177d24..d83a521 100644
--- a/src/com/android/gallery3d/filtershow/filters/ImageFilterDraw.java
+++ b/src/com/android/gallery3d/filtershow/filters/ImageFilterDraw.java
@@ -435,7 +435,6 @@
         return filter;
     }
 
-    @Override
     public boolean isNil() {
         for (int i = 0; i < mDrawings.length; i++) {
             if (mDrawings[i].getNumberOfStrokes() != 0) {
diff --git a/src/com/android/gallery3d/filtershow/filters/ImageFilterEdge.java b/src/com/android/gallery3d/filtershow/filters/ImageFilterEdge.java
index 9eda648..f5a0a69 100644
--- a/src/com/android/gallery3d/filtershow/filters/ImageFilterEdge.java
+++ b/src/com/android/gallery3d/filtershow/filters/ImageFilterEdge.java
@@ -20,11 +20,17 @@
 
 import com.android.gallery3d.R;
 
-public class ImageFilterEdge extends ImageFilter {
+public class ImageFilterEdge extends SimpleImageFilter {
 
     public ImageFilterEdge() {
         mName = "Edge";
-        mPreviewParameter = 0;
+    }
+
+    public FilterRepresentation getDefaultRepresentation() {
+        FilterRepresentation representation = super.getDefaultRepresentation();
+        representation.setName("Edge");
+        representation.setFilterClass(ImageFilterEdge.class);
+        return representation;
     }
 
     native protected void nativeApplyFilter(Bitmap bitmap, int w, int h, float p);
@@ -40,15 +46,13 @@
     }
 
     @Override
-    public boolean isNil() {
-        return false;
-    }
-
-    @Override
     public Bitmap apply(Bitmap bitmap, float scaleFactor, boolean highQuality) {
+        if (getParameters() == null) {
+            return bitmap;
+        }
         int w = bitmap.getWidth();
         int h = bitmap.getHeight();
-        float p = mParameter + 101;
+        float p = getParameters().getValue() + 101;
         p = (float) p / 100;
         nativeApplyFilter(bitmap, w, h, p);
         return bitmap;
diff --git a/src/com/android/gallery3d/filtershow/filters/ImageFilterExposure.java b/src/com/android/gallery3d/filtershow/filters/ImageFilterExposure.java
index 63f8601..569a6f2 100644
--- a/src/com/android/gallery3d/filtershow/filters/ImageFilterExposure.java
+++ b/src/com/android/gallery3d/filtershow/filters/ImageFilterExposure.java
@@ -20,12 +20,19 @@
 
 import android.graphics.Bitmap;
 
-public class ImageFilterExposure extends ImageFilter {
+public class ImageFilterExposure extends SimpleImageFilter {
 
     public ImageFilterExposure() {
         mName = "Exposure";
     }
 
+    public FilterRepresentation getDefaultRepresentation() {
+        FilterRepresentation representation = super.getDefaultRepresentation();
+        representation.setName("Exposure");
+        representation.setFilterClass(ImageFilterExposure.class);
+        return representation;
+    }
+
     @Override
     public int getButtonId() {
         return R.id.exposureButton;
@@ -40,10 +47,12 @@
 
     @Override
     public Bitmap apply(Bitmap bitmap, float scaleFactor, boolean highQuality) {
+        if (getParameters() == null) {
+            return bitmap;
+        }
         int w = bitmap.getWidth();
         int h = bitmap.getHeight();
-        int p = mParameter;
-        float value = p;
+        float value = getParameters().getValue();
         nativeApplyFilter(bitmap, w, h, value);
         return bitmap;
     }
diff --git a/src/com/android/gallery3d/filtershow/filters/ImageFilterFx.java b/src/com/android/gallery3d/filtershow/filters/ImageFilterFx.java
index 345202f..f5dff5e 100644
--- a/src/com/android/gallery3d/filtershow/filters/ImageFilterFx.java
+++ b/src/com/android/gallery3d/filtershow/filters/ImageFilterFx.java
@@ -42,7 +42,6 @@
         return filter;
     }
 
-    @Override
     public boolean isNil() {
         if (fxBitmap != null) {
             return false;
diff --git a/src/com/android/gallery3d/filtershow/filters/ImageFilterHue.java b/src/com/android/gallery3d/filtershow/filters/ImageFilterHue.java
index 6b9869b..51c476d 100644
--- a/src/com/android/gallery3d/filtershow/filters/ImageFilterHue.java
+++ b/src/com/android/gallery3d/filtershow/filters/ImageFilterHue.java
@@ -21,14 +21,21 @@
 
 import android.graphics.Bitmap;
 
-public class ImageFilterHue extends ImageFilter {
+public class ImageFilterHue extends SimpleImageFilter {
     private ColorSpaceMatrix cmatrix = null;
 
     public ImageFilterHue() {
         mName = "Hue";
         cmatrix = new ColorSpaceMatrix();
-        mMaxParameter = 180;
-        mMinParameter = -180;
+    }
+
+    public FilterRepresentation getDefaultRepresentation() {
+        FilterBasicRepresentation representation = (FilterBasicRepresentation) super.getDefaultRepresentation();
+        representation.setName("Hue");
+        representation.setFilterClass(ImageFilterHue.class);
+        representation.setMinimum(-180);
+        representation.setMaximum(180);
+        return representation;
     }
 
     @Override
@@ -57,10 +64,12 @@
 
     @Override
     public Bitmap apply(Bitmap bitmap, float scaleFactor, boolean highQuality) {
+        if (getParameters() == null) {
+            return bitmap;
+        }
         int w = bitmap.getWidth();
         int h = bitmap.getHeight();
-        float p = mParameter;
-        float value = p;
+        float value = getParameters().getValue();
         cmatrix.identity();
         cmatrix.setHue(value);
 
diff --git a/src/com/android/gallery3d/filtershow/filters/ImageFilterKMeans.java b/src/com/android/gallery3d/filtershow/filters/ImageFilterKMeans.java
index f03baca..fd098e6 100644
--- a/src/com/android/gallery3d/filtershow/filters/ImageFilterKMeans.java
+++ b/src/com/android/gallery3d/filtershow/filters/ImageFilterKMeans.java
@@ -20,17 +20,13 @@
 import android.text.format.Time;
 
 import com.android.gallery3d.R;
+import com.android.gallery3d.ingest.ui.MtpThumbnailTileView;
 
-public class ImageFilterKMeans extends ImageFilter {
+public class ImageFilterKMeans extends SimpleImageFilter {
     private int mSeed = 0;
 
     public ImageFilterKMeans() {
         mName = "KMeans";
-        mMaxParameter = 20;
-        mMinParameter = 2;
-        mPreviewParameter = 4;
-        mDefaultParameter = 4;
-        mParameter = 4;
 
         // set random seed for session
         Time t = new Time();
@@ -38,6 +34,18 @@
         mSeed = (int) t.toMillis(false);
     }
 
+    public FilterRepresentation getDefaultRepresentation() {
+        FilterBasicRepresentation representation = (FilterBasicRepresentation) super.getDefaultRepresentation();
+        representation.setName("KMeans");
+        representation.setFilterClass(ImageFilterKMeans.class);
+        representation.setMaximum(20);
+        representation.setMinimum(2);
+        representation.setValue(4);
+        representation.setDefaultValue(4);
+        representation.setPreviewValue(4);
+        return representation;
+    }
+
     native protected void nativeApplyFilter(Bitmap bitmap, int width, int height,
             Bitmap large_ds_bm, int lwidth, int lheight, Bitmap small_ds_bm,
             int swidth, int sheight, int p, int seed);
@@ -53,12 +61,10 @@
     }
 
     @Override
-    public boolean isNil() {
-        return false;
-    }
-
-    @Override
     public Bitmap apply(Bitmap bitmap, float scaleFactor, boolean highQuality) {
+        if (getParameters() == null) {
+            return bitmap;
+        }
         int w = bitmap.getWidth();
         int h = bitmap.getHeight();
 
@@ -87,8 +93,10 @@
             small_bm_ds = Bitmap.createScaledBitmap(large_bm_ds, sw, sh, true);
         }
 
-        int p = Math.max(mParameter, mMinParameter) % (mMaxParameter + 1);
-        nativeApplyFilter(bitmap, w, h, large_bm_ds, lw, lh, small_bm_ds, sw, sh, p, mSeed);
+        if (getParameters() != null) {
+            int p = Math.max(getParameters().getValue(), getParameters().getMinimum()) % (getParameters().getMaximum() + 1);
+            nativeApplyFilter(bitmap, w, h, large_bm_ds, lw, lh, small_bm_ds, sw, sh, p, mSeed);
+        }
         return bitmap;
     }
 }
diff --git a/src/com/android/gallery3d/filtershow/filters/ImageFilterNegative.java b/src/com/android/gallery3d/filtershow/filters/ImageFilterNegative.java
index 04fd1e4..e69fe35 100644
--- a/src/com/android/gallery3d/filtershow/filters/ImageFilterNegative.java
+++ b/src/com/android/gallery3d/filtershow/filters/ImageFilterNegative.java
@@ -10,6 +10,16 @@
         mName = "Negative";
     }
 
+    public FilterRepresentation getDefaultRepresentation() {
+        FilterRepresentation representation = new FilterDirectRepresentation("Negative");
+        representation.setFilterClass(ImageFilterNegative.class);
+        return representation;
+    }
+
+    public boolean hasDefaultRepresentation() {
+        return true;
+    }
+
     @Override
     public int getButtonId() {
         return R.id.negativeButton;
@@ -21,11 +31,6 @@
     }
 
     @Override
-    public boolean isNil() {
-        return false;
-    }
-
-    @Override
     public boolean showEditingControls() {
         return false;
     }
diff --git a/src/com/android/gallery3d/filtershow/filters/ImageFilterParametricBorder.java b/src/com/android/gallery3d/filtershow/filters/ImageFilterParametricBorder.java
index 681eb12..1e75eb2 100644
--- a/src/com/android/gallery3d/filtershow/filters/ImageFilterParametricBorder.java
+++ b/src/com/android/gallery3d/filtershow/filters/ImageFilterParametricBorder.java
@@ -67,7 +67,6 @@
         return filter;
     }
 
-    @Override
     public boolean isNil() {
         return false;
     }
diff --git a/src/com/android/gallery3d/filtershow/filters/ImageFilterRedEye.java b/src/com/android/gallery3d/filtershow/filters/ImageFilterRedEye.java
index 9ae6f51..0378090 100644
--- a/src/com/android/gallery3d/filtershow/filters/ImageFilterRedEye.java
+++ b/src/com/android/gallery3d/filtershow/filters/ImageFilterRedEye.java
@@ -45,7 +45,7 @@
 
     @Override
     public int getEditingViewId() {
-        return R.id.imageRedEyes;
+            return R.id.imageRedEyes;
     }
 
     @Override
@@ -61,7 +61,6 @@
         return filter;
     }
 
-    @Override
     public boolean isNil() {
         if (mCandidates != null && mCandidates.size() > 0) {
             return false;
diff --git a/src/com/android/gallery3d/filtershow/filters/ImageFilterSaturated.java b/src/com/android/gallery3d/filtershow/filters/ImageFilterSaturated.java
index 129165b..7d848f5 100644
--- a/src/com/android/gallery3d/filtershow/filters/ImageFilterSaturated.java
+++ b/src/com/android/gallery3d/filtershow/filters/ImageFilterSaturated.java
@@ -20,12 +20,19 @@
 
 import android.graphics.Bitmap;
 
-public class ImageFilterSaturated extends ImageFilter {
+public class ImageFilterSaturated extends SimpleImageFilter {
 
     public ImageFilterSaturated() {
         mName = "Saturated";
     }
 
+    public FilterRepresentation getDefaultRepresentation() {
+        FilterRepresentation representation = super.getDefaultRepresentation();
+        representation.setName("Saturated");
+        representation.setFilterClass(ImageFilterSaturated.class);
+        return representation;
+    }
+
     @Override
     public int getButtonId() {
         return R.id.saturationButton;
@@ -40,9 +47,12 @@
 
     @Override
     public Bitmap apply(Bitmap bitmap, float scaleFactor, boolean highQuality) {
+        if (getParameters() == null) {
+            return bitmap;
+        }
         int w = bitmap.getWidth();
         int h = bitmap.getHeight();
-        int p = mParameter;
+        int p = getParameters().getValue();
         float value = 1 +  p / 100.0f;
         nativeApplyFilter(bitmap, w, h, value);
         return bitmap;
diff --git a/src/com/android/gallery3d/filtershow/filters/ImageFilterShadows.java b/src/com/android/gallery3d/filtershow/filters/ImageFilterShadows.java
index de8fcd5..27e5342 100644
--- a/src/com/android/gallery3d/filtershow/filters/ImageFilterShadows.java
+++ b/src/com/android/gallery3d/filtershow/filters/ImageFilterShadows.java
@@ -20,13 +20,20 @@
 
 import android.graphics.Bitmap;
 
-public class ImageFilterShadows extends ImageFilter {
+public class ImageFilterShadows extends SimpleImageFilter {
 
     public ImageFilterShadows() {
         mName = "Shadows";
 
     }
 
+    public FilterRepresentation getDefaultRepresentation() {
+        FilterRepresentation representation = super.getDefaultRepresentation();
+        representation.setName("Shadows");
+        representation.setFilterClass(ImageFilterShadows.class);
+        return representation;
+    }
+
     @Override
     public int getButtonId() {
         return R.id.shadowRecoveryButton;
@@ -47,9 +54,12 @@
 
     @Override
     public Bitmap apply(Bitmap bitmap, float scaleFactor, boolean highQuality) {
+        if (getParameters() == null) {
+            return bitmap;
+        }
         int w = bitmap.getWidth();
         int h = bitmap.getHeight();
-        float p = mParameter;
+        float p = getParameters().getValue();
 
         nativeApplyFilter(bitmap, w, h, p);
         return bitmap;
diff --git a/src/com/android/gallery3d/filtershow/filters/ImageFilterSharpen.java b/src/com/android/gallery3d/filtershow/filters/ImageFilterSharpen.java
index 1f9bf22..58c2ac6 100644
--- a/src/com/android/gallery3d/filtershow/filters/ImageFilterSharpen.java
+++ b/src/com/android/gallery3d/filtershow/filters/ImageFilterSharpen.java
@@ -24,10 +24,28 @@
     private ScriptC_convolve3x3 mScript;
     float mScaleFactor;
 
+    private FilterBasicRepresentation mParameters;
+
     public ImageFilterSharpen() {
         mName = "Sharpen";
     }
 
+    public FilterRepresentation getDefaultRepresentation() {
+        FilterRepresentation representation = new FilterBasicRepresentation("Sharpen", 0, 0, 100);
+        representation.setShowParameterValue(true);
+        representation.setFilterClass(ImageFilterSharpen.class);
+        return representation;
+    }
+
+    public void useRepresentation(FilterRepresentation representation) {
+        FilterBasicRepresentation parameters = (FilterBasicRepresentation) representation;
+        mParameters = parameters;
+    }
+
+    public boolean hasDefaultRepresentation() {
+        return true;
+    }
+
     @Override
     public int getButtonId() {
         return R.id.sharpenButton;
@@ -63,7 +81,7 @@
     }
 
     private void computeKernel(){
-        float p1 = mParameter * mScaleFactor;
+        float p1 = mParameters.getValue() * mScaleFactor;
         float value = p1 / 100.0f;
         float f[] = new float[9];
         float p = value;
@@ -81,6 +99,9 @@
 
     @Override
     public void runFilter() {
+        if (mParameters == null) {
+            return;
+        }
         computeKernel();
         mScript.set_gIn(mInPixelsAllocation);
         mScript.bind_gPixels(mInPixelsAllocation);
diff --git a/src/com/android/gallery3d/filtershow/filters/ImageFilterTinyPlanet.java b/src/com/android/gallery3d/filtershow/filters/ImageFilterTinyPlanet.java
index 36bd626..a6075da 100644
--- a/src/com/android/gallery3d/filtershow/filters/ImageFilterTinyPlanet.java
+++ b/src/com/android/gallery3d/filtershow/filters/ImageFilterTinyPlanet.java
@@ -29,7 +29,7 @@
 /**
  * An image filter which creates a tiny planet projection.
  */
-public class ImageFilterTinyPlanet extends ImageFilter {
+public class ImageFilterTinyPlanet extends SimpleImageFilter {
     private float mAngle = 0;
 
     private static final String TAG = ImageFilterTinyPlanet.class.getSimpleName();
@@ -51,12 +51,6 @@
     public ImageFilterTinyPlanet() {
         setFilterType(TYPE_TINYPLANET);
         mName = "TinyPlanet";
-
-        mMinParameter = 10;
-        mMaxParameter = 60;
-        mDefaultParameter = 20;
-        mPreviewParameter = 20;
-        mParameter = 20;
         mAngle = 0;
     }
 
@@ -114,7 +108,7 @@
             }
         }
         nativeApplyFilter(bitmapIn, bitmapIn.getWidth(), bitmapIn.getHeight(), mBitmapOut,
-                outputSize, mParameter / 100f, mAngle);
+                outputSize, getParameters().getValue() / 100f, mAngle);
         return mBitmapOut;
     }
 
diff --git a/src/com/android/gallery3d/filtershow/filters/ImageFilterVibrance.java b/src/com/android/gallery3d/filtershow/filters/ImageFilterVibrance.java
index 7720d04..905850a 100644
--- a/src/com/android/gallery3d/filtershow/filters/ImageFilterVibrance.java
+++ b/src/com/android/gallery3d/filtershow/filters/ImageFilterVibrance.java
@@ -20,12 +20,19 @@
 
 import android.graphics.Bitmap;
 
-public class ImageFilterVibrance extends ImageFilter {
+public class ImageFilterVibrance extends SimpleImageFilter {
 
     public ImageFilterVibrance() {
         mName = "Vibrance";
     }
 
+    public FilterRepresentation getDefaultRepresentation() {
+        FilterRepresentation representation = super.getDefaultRepresentation();
+        representation.setName("Vibrance");
+        representation.setFilterClass(ImageFilterVibrance.class);
+        return representation;
+    }
+
     @Override
     public int getButtonId() {
         return R.id.vibranceButton;
@@ -40,10 +47,12 @@
 
     @Override
     public Bitmap apply(Bitmap bitmap, float scaleFactor, boolean highQuality) {
+        if (getParameters() == null) {
+            return bitmap;
+        }
         int w = bitmap.getWidth();
         int h = bitmap.getHeight();
-        int p = mParameter;
-        float value = p;
+        float value = getParameters().getValue();
         nativeApplyFilter(bitmap, w, h, value);
 
         return bitmap;
diff --git a/src/com/android/gallery3d/filtershow/filters/ImageFilterVignette.java b/src/com/android/gallery3d/filtershow/filters/ImageFilterVignette.java
index 3c904fa..1cc9359 100644
--- a/src/com/android/gallery3d/filtershow/filters/ImageFilterVignette.java
+++ b/src/com/android/gallery3d/filtershow/filters/ImageFilterVignette.java
@@ -19,14 +19,25 @@
 import com.android.gallery3d.R;
 
 import android.graphics.Bitmap;
+import com.android.gallery3d.app.Log;
 
-public class ImageFilterVignette extends ImageFilter {
+public class ImageFilterVignette extends SimpleImageFilter {
+
+    private static final String LOGTAG = "ImageFilterVignette";
 
     public ImageFilterVignette() {
         setFilterType(TYPE_VIGNETTE);
         mName = "Vignette";
     }
 
+    public FilterRepresentation getDefaultRepresentation() {
+        FilterBasicRepresentation representation = (FilterBasicRepresentation) super.getDefaultRepresentation();
+        representation.setName("Vignette");
+        representation.setFilterClass(ImageFilterVignette.class);
+        representation.setPriority(TYPE_VIGNETTE);
+        return representation;
+    }
+
     @Override
     public int getButtonId() {
         return R.id.vignetteButton;
@@ -41,10 +52,12 @@
 
     @Override
     public Bitmap apply(Bitmap bitmap, float scaleFactor, boolean highQuality) {
+        if (getParameters() == null) {
+            return bitmap;
+        }
         int w = bitmap.getWidth();
         int h = bitmap.getHeight();
-        float p = mParameter;
-        float value = p / 100.0f;
+        float value = getParameters().getValue() / 100.0f;
         nativeApplyFilter(bitmap, w, h, value);
 
         return bitmap;
diff --git a/src/com/android/gallery3d/filtershow/filters/ImageFilterWBalance.java b/src/com/android/gallery3d/filtershow/filters/ImageFilterWBalance.java
index 8665dc5..05f5124 100644
--- a/src/com/android/gallery3d/filtershow/filters/ImageFilterWBalance.java
+++ b/src/com/android/gallery3d/filtershow/filters/ImageFilterWBalance.java
@@ -28,6 +28,16 @@
         mName = "WBalance";
     }
 
+    public FilterRepresentation getDefaultRepresentation() {
+        FilterRepresentation representation = new FilterDirectRepresentation("WBalance");
+        representation.setFilterClass(ImageFilterWBalance.class);
+        return representation;
+    }
+
+    public boolean hasDefaultRepresentation() {
+        return true;
+    }
+
     @Override
     public int getButtonId() {
         return R.id.wbalanceButton;
@@ -52,8 +62,4 @@
         return bitmap;
     }
 
-    @Override
-    public boolean isNil() {
-        return false;
-    }
 }
diff --git a/src/com/android/gallery3d/filtershow/filters/SimpleImageFilter.java b/src/com/android/gallery3d/filtershow/filters/SimpleImageFilter.java
new file mode 100644
index 0000000..8b6f3da
--- /dev/null
+++ b/src/com/android/gallery3d/filtershow/filters/SimpleImageFilter.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2013 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 com.android.gallery3d.filtershow.filters;
+
+import android.graphics.Bitmap;
+
+public class SimpleImageFilter extends ImageFilter {
+
+    private FilterBasicRepresentation mParameters;
+
+    public FilterRepresentation getDefaultRepresentation() {
+        FilterRepresentation representation = new FilterBasicRepresentation("Default", 0, 50, 100);
+        representation.setShowParameterValue(true);
+        return representation;
+    }
+
+    public void useRepresentation(FilterRepresentation representation) {
+        FilterBasicRepresentation parameters = (FilterBasicRepresentation) representation;
+        mParameters = parameters;
+    }
+
+    public boolean hasDefaultRepresentation() {
+        return true;
+    }
+
+    public FilterBasicRepresentation getParameters() {
+        return mParameters;
+    }
+
+    @Override
+    public Bitmap iconApply(Bitmap bitmap, float scaleFactor, boolean highQuality) {
+        FilterRepresentation representation = getDefaultRepresentation();
+        this.useRepresentation(representation);
+        return apply(bitmap, scaleFactor, highQuality);
+    }
+}
diff --git a/src/com/android/gallery3d/filtershow/imageshow/ImageShow.java b/src/com/android/gallery3d/filtershow/imageshow/ImageShow.java
index 93c4622..8b58240 100644
--- a/src/com/android/gallery3d/filtershow/imageshow/ImageShow.java
+++ b/src/com/android/gallery3d/filtershow/imageshow/ImageShow.java
@@ -141,12 +141,6 @@
         if (mSeekBar != null) {
             mSeekBar.setOnSeekBarChangeListener(this);
         }
-        if (getCurrentFilter() != null) {
-            int parameter = getCurrentFilter().getParameter();
-            int maxp = getCurrentFilter().getMaxParameter();
-            int minp = getCurrentFilter().getMinParameter();
-            updateSeekBar(parameter, minp, maxp);
-        }
     }
 
     private int parameterToUI(int parameter, int minp, int maxp, int uimax) {
@@ -178,11 +172,7 @@
     }
 
     public void resetParameter() {
-        ImageFilter currentFilter = getCurrentFilter();
-        if (currentFilter != null) {
-            updateSeekBar(currentFilter.getDefaultParameter(),
-                    getCurrentFilter().getMinParameter(), getCurrentFilter().getMaxParameter());
-        }
+        // TODO: implement reset
     }
 
     public void setPanelController(PanelController controller) {
@@ -195,16 +185,6 @@
 
     @Override
     public void onNewValue(int parameter) {
-        int maxp = ImageFilter.DEFAULT_MAX_PARAMETER;
-        int minp = ImageFilter.DEFAULT_MIN_PARAMETER;
-        if (getCurrentFilter() != null) {
-            if (getCurrentFilter().getParameter() == parameter) {
-                return;
-            }
-            getCurrentFilter().setParameter(parameter);
-            maxp = getCurrentFilter().getMaxParameter();
-            minp = getCurrentFilter().getMinParameter();
-        }
         if (getImagePreset() != null) {
             getImagePreset().fillImageStateAdapter(mMasterImage.getState());
         }
@@ -616,12 +596,6 @@
     @Override
     public void onProgressChanged(SeekBar arg0, int progress, boolean arg2) {
         int parameter = progress;
-        if (getCurrentFilter() != null) {
-            int maxp = getCurrentFilter().getMaxParameter();
-            int minp = getCurrentFilter().getMinParameter();
-            parameter = uiToParameter(progress, minp, maxp, arg0.getMax());
-        }
-
         onNewValue(parameter);
     }
 
diff --git a/src/com/android/gallery3d/filtershow/imageshow/MasterImage.java b/src/com/android/gallery3d/filtershow/imageshow/MasterImage.java
index 5e9ec7a..9eae1177 100644
--- a/src/com/android/gallery3d/filtershow/imageshow/MasterImage.java
+++ b/src/com/android/gallery3d/filtershow/imageshow/MasterImage.java
@@ -26,6 +26,7 @@
 import com.android.gallery3d.filtershow.cache.TripleBufferBitmap;
 import com.android.gallery3d.filtershow.cache.FilteringPipeline;
 import com.android.gallery3d.filtershow.cache.ImageLoader;
+import com.android.gallery3d.filtershow.filters.FilterRepresentation;
 import com.android.gallery3d.filtershow.filters.ImageFilter;
 import com.android.gallery3d.filtershow.presets.ImagePreset;
 
@@ -53,6 +54,7 @@
     private FilterShowActivity mActivity = null;
 
     private Vector<ImageShow> mObservers = new Vector<ImageShow>();
+    private FilterRepresentation mCurrentFilterRepresentation;
 
     private MasterImage() { }
 
@@ -205,4 +207,11 @@
         FilteringPipeline.getPipeline().updateFiltersOnlyPreviewBuffer();
     }
 
+    public FilterRepresentation getCurrentFilterRepresentation() {
+        return mCurrentFilterRepresentation;
+    }
+
+    public void setCurrentFilterRepresentation(FilterRepresentation currentFilterRepresentation) {
+        mCurrentFilterRepresentation = currentFilterRepresentation;
+    }
 }
diff --git a/src/com/android/gallery3d/filtershow/presets/ImagePreset.java b/src/com/android/gallery3d/filtershow/presets/ImagePreset.java
index d6a69af..6e9ab9f 100644
--- a/src/com/android/gallery3d/filtershow/presets/ImagePreset.java
+++ b/src/com/android/gallery3d/filtershow/presets/ImagePreset.java
@@ -21,8 +21,10 @@
 
 import com.android.gallery3d.filtershow.ImageStateAdapter;
 import com.android.gallery3d.filtershow.cache.ImageLoader;
+import com.android.gallery3d.filtershow.filters.FilterRepresentation;
+import com.android.gallery3d.filtershow.filters.FiltersManager;
 import com.android.gallery3d.filtershow.filters.ImageFilter;
-import com.android.gallery3d.filtershow.filters.ImageFilterRS;
+import com.android.gallery3d.filtershow.filters.ImageFilterCurves;
 import com.android.gallery3d.filtershow.imageshow.GeometryMetadata;
 import com.android.gallery3d.filtershow.imageshow.ImageShow;
 
@@ -33,12 +35,13 @@
     private static final String LOGTAG = "ImagePreset";
 
     private ImageShow mEndPoint = null;
-    private ImageFilter mImageBorder = null;
+    private FilterRepresentation mImageBorder = null;
     private float mScaleFactor = 1.0f;
     private boolean mIsHighQuality = false;
     private ImageLoader mImageLoader = null;
 
-    protected Vector<ImageFilter> mFilters = new Vector<ImageFilter>();
+    private Vector<FilterRepresentation> mFilters = new Vector<FilterRepresentation>();
+
     protected String mName = "Original";
     private String mHistoryName = "Original";
     protected boolean mIsFxPreset = false;
@@ -74,9 +77,9 @@
                 mImageBorder = source.mImageBorder.clone();
             }
             for (int i = 0; i < source.mFilters.size(); i++) {
-                ImageFilter filter = source.mFilters.elementAt(i).clone();
-                filter.setImagePreset(this);
-                add(filter);
+                FilterRepresentation representation = source.mFilters.elementAt(i).clone();
+                representation.setImagePreset(this);
+                addFilter(representation);
             }
         } catch (java.lang.CloneNotSupportedException e) {
             Log.v(LOGTAG, "Exception trying to clone: " + e);
@@ -113,7 +116,7 @@
             return true;
         }
         for (int i = 0; i < mFilters.size(); i++) {
-            ImageFilter filter = mFilters.elementAt(i);
+            FilterRepresentation filter = mFilters.elementAt(i);
             if (!filter.isNil()) {
                 return true;
             }
@@ -128,13 +131,13 @@
         if (mGeoData.hasModifications()) {
             return false;
         }
-        for (ImageFilter filter : mFilters) {
-            if (filter.getFilterType() == ImageFilter.TYPE_VIGNETTE
-                    && !filter.isNil()) {
+        for (FilterRepresentation representation : mFilters) {
+            if (representation.getPriority() == ImageFilter.TYPE_VIGNETTE
+                && !representation.isNil()) {
                 return false;
             }
-            if (filter.getFilterType() == ImageFilter.TYPE_TINYPLANET
-                    && !filter.isNil()) {
+            if (representation.getPriority() == ImageFilter.TYPE_TINYPLANET
+                && !representation.isNil()) {
                 return false;
             }
         }
@@ -145,7 +148,7 @@
         mGeoData.set(m);
     }
 
-    private void setBorder(ImageFilter filter) {
+    private void setBorder(FilterRepresentation filter) {
         mImageBorder = filter;
     }
 
@@ -180,8 +183,8 @@
         }
         if (mDoApplyFilters && preset.mDoApplyFilters) {
             for (int i = 0; i < preset.mFilters.size(); i++) {
-                ImageFilter a = preset.mFilters.elementAt(i);
-                ImageFilter b = mFilters.elementAt(i);
+                FilterRepresentation a = preset.mFilters.elementAt(i);
+                FilterRepresentation b = mFilters.elementAt(i);
                 if (!a.equals(b)) {
                     return false;
                 }
@@ -190,14 +193,6 @@
         return true;
     }
 
-    public void usePreset(ImagePreset preset) {
-        for (int i = 0; i < preset.mFilters.size(); i++) {
-            ImageFilter a = preset.mFilters.elementAt(i);
-            ImageFilter b = mFilters.elementAt(i);
-            b.useFilter(a);
-        }
-    }
-
     public boolean same(ImagePreset preset) {
         if (preset == null) {
             return false;
@@ -223,7 +218,7 @@
             return false;
         }
 
-        if (mImageBorder != null && !mImageBorder.same(preset.mImageBorder)) {
+        if (mImageBorder != null && !mImageBorder.equals(preset.mImageBorder)) {
             return false;
         }
 
@@ -235,18 +230,15 @@
 
         if (mDoApplyFilters && preset.mDoApplyFilters) {
             for (int i = 0; i < preset.mFilters.size(); i++) {
-                ImageFilter a = preset.mFilters.elementAt(i);
-                ImageFilter b = mFilters.elementAt(i);
+                FilterRepresentation a = preset.mFilters.elementAt(i);
+                FilterRepresentation b = mFilters.elementAt(i);
                 if (!a.same(b)) {
                     return false;
                 }
             }
         }
-        return true;
-    }
 
-    public int nbFilters() {
-        return mFilters.size();
+        return true;
     }
 
     public int similarUpTo(ImagePreset preset) {
@@ -255,13 +247,13 @@
         }
 
         for (int i = 0; i < preset.mFilters.size(); i++) {
-            ImageFilter a = preset.mFilters.elementAt(i);
+            FilterRepresentation a = preset.mFilters.elementAt(i);
             if (i < mFilters.size()) {
-                ImageFilter b = mFilters.elementAt(i);
+                FilterRepresentation b = mFilters.elementAt(i);
                 if (!a.same(b)) {
                     return i;
                 }
-                if (a.getParameter() != b.getParameter()) {
+                if (!a.equals(b)) {
                     return i;
                 }
             } else {
@@ -279,15 +271,25 @@
         return mHistoryName;
     }
 
-    public void add(ImageFilter filter) {
+    public void showFilters() {
+        Log.v(LOGTAG, "\\\\\\ showFilters -- " + mFilters.size() + " filters");
+        int n = 0;
+        for (FilterRepresentation representation : mFilters) {
+            Log.v(LOGTAG, " filter " + n + " : " + representation.toString());
+            n++;
+        }
+        Log.v(LOGTAG, "/// showFilters -- " + mFilters.size() + " filters");
+    }
 
-        if (filter.getFilterType() == ImageFilter.TYPE_BORDER) {
-            setHistoryName(filter.getName());
-            setBorder(filter);
-        } else if (filter.getFilterType() == ImageFilter.TYPE_FX) {
+    public void addFilter(FilterRepresentation representation) {
+        Log.v(LOGTAG, "*** Add Filter *** " + representation);
+        if (representation.getPriority() == ImageFilter.TYPE_BORDER) {
+            setHistoryName(representation.getName());
+            setBorder(representation);
+        } else if (representation.getPriority() == ImageFilter.TYPE_FX) {
             boolean found = false;
             for (int i = 0; i < mFilters.size(); i++) {
-                byte type = mFilters.get(i).getFilterType();
+                int type = mFilters.elementAt(i).getPriority();
                 if (found) {
                     if (type != ImageFilter.TYPE_VIGNETTE) {
                         mFilters.remove(i);
@@ -296,38 +298,30 @@
                 }
                 if (type == ImageFilter.TYPE_FX) {
                     mFilters.remove(i);
-                    mFilters.add(i, filter);
-                    setHistoryName(filter.getName());
+                    mFilters.add(i, representation);
+                    setHistoryName(representation.getName());
                     found = true;
                 }
             }
             if (!found) {
-                mFilters.add(filter);
-                setHistoryName(filter.getName());
+                mFilters.add(representation);
+                setHistoryName(representation.getName());
             }
         } else {
-            mFilters.add(filter);
-            setHistoryName(filter.getName());
+            mFilters.add(representation);
+            setHistoryName(representation.getName());
         }
-        filter.setImagePreset(this);
+        representation.setImagePreset(this);
     }
 
-    public void remove(String filterName) {
-        ImageFilter filter = getFilter(filterName);
-        if (filter != null) {
-            mFilters.remove(filter);
-        }
+    public void add(ImageFilter filter) {
     }
 
-    public int getCount() {
-        return mFilters.size();
-    }
-
-    public ImageFilter getFilter(String name) {
+    public FilterRepresentation getRepresentation(FilterRepresentation filterRepresentation) {
         for (int i = 0; i < mFilters.size(); i++) {
-            ImageFilter filter = mFilters.elementAt(i);
-            if (filter.getName().equalsIgnoreCase(name)) {
-                return filter;
+            FilterRepresentation representation = mFilters.elementAt(i);
+            if (representation.getFilterClass() == filterRepresentation.getFilterClass()) {
+                return representation;
             }
         }
         return null;
@@ -337,10 +331,6 @@
         // do nothing here
     }
 
-    public void setEndpoint(ImageShow image) {
-        mEndPoint = image;
-    }
-
     public Bitmap apply(Bitmap original) {
         Bitmap bitmap = original;
         bitmap = applyFilters(bitmap, -1, -1);
@@ -355,7 +345,8 @@
 
     public Bitmap applyBorder(Bitmap bitmap) {
         if (mImageBorder != null && mDoApplyGeometry) {
-            bitmap = mImageBorder.apply(bitmap, mScaleFactor, mIsHighQuality);
+            ImageFilter filter = FiltersManager.getManager().getFilterForRepresentation(mImageBorder);
+            bitmap = filter.apply(bitmap, mScaleFactor, mIsHighQuality);
         }
         return bitmap;
     }
@@ -370,7 +361,9 @@
                 to = mFilters.size();
             }
             for (int i = from; i < to; i++) {
-                ImageFilter filter = mFilters.elementAt(i);
+                FilterRepresentation representation = mFilters.elementAt(i);
+                ImageFilter filter = FiltersManager.getManager().getFilterForRepresentation(representation);
+                filter.useRepresentation(representation);
                 bitmap = filter.apply(bitmap, mScaleFactor, mIsHighQuality);
             }
         }
@@ -383,7 +376,8 @@
             return;
         }
         imageStateAdapter.clear();
-        imageStateAdapter.addAll(mFilters);
+        // TODO: re-enable the state panel
+        // imageStateAdapter.addAll(mFilters);
         imageStateAdapter.notifyDataSetChanged();
     }
 
diff --git a/src/com/android/gallery3d/filtershow/ui/FilterIconButton.java b/src/com/android/gallery3d/filtershow/ui/FilterIconButton.java
index 089b241..8dc5153 100644
--- a/src/com/android/gallery3d/filtershow/ui/FilterIconButton.java
+++ b/src/com/android/gallery3d/filtershow/ui/FilterIconButton.java
@@ -25,12 +25,14 @@
 import android.widget.LinearLayout;
 
 import com.android.gallery3d.filtershow.FilterShowActivity;
+import com.android.gallery3d.filtershow.filters.FilterRepresentation;
 import com.android.gallery3d.filtershow.filters.ImageFilter;
 
 public class FilterIconButton extends IconButton implements View.OnClickListener {
     private Bitmap mOverlayBitmap = null;
     private FilterShowActivity mController = null;
     private ImageFilter mImageFilter = null;
+    private FilterRepresentation mFilterRepresentation = null;
     private LinearLayout mParentContainer = null;
     private View.OnClickListener mListener = null;
 
@@ -80,7 +82,7 @@
     @Override
     public void onClick(View v) {
         if (mController != null && mImageFilter != null) {
-            mController.useFilter(mImageFilter);
+            mController.useFilterRepresentation(mFilterRepresentation);
             mParentContainer.dispatchSetSelected(false);
             setSelected(true);
         }
@@ -92,4 +94,8 @@
     public ImageFilter getImageFilter() {
         return mImageFilter;
     }
+
+    public void setFilterRepresentation(FilterRepresentation filterRepresentation) {
+        mFilterRepresentation = filterRepresentation;
+    }
 }
diff --git a/src/com/android/gallery3d/filtershow/ui/ImageCurves.java b/src/com/android/gallery3d/filtershow/ui/ImageCurves.java
index 80c8935..88e756a 100644
--- a/src/com/android/gallery3d/filtershow/ui/ImageCurves.java
+++ b/src/com/android/gallery3d/filtershow/ui/ImageCurves.java
@@ -35,6 +35,7 @@
 import android.widget.PopupMenu;
 
 import com.android.gallery3d.R;
+import com.android.gallery3d.filtershow.filters.FiltersManager;
 import com.android.gallery3d.filtershow.filters.ImageFilterCurves;
 import com.android.gallery3d.filtershow.imageshow.ImageShow;
 import com.android.gallery3d.filtershow.presets.ImagePreset;
@@ -127,7 +128,7 @@
         String filterName = getFilterName();
         ImagePreset p = getImagePreset();
         if (p != null) {
-            return (ImageFilterCurves) p.getFilter(filterName);
+            return (ImageFilterCurves) FiltersManager.getManager().getFilter(ImageFilterCurves.class);
         }
         return null;
     }
diff --git a/src_pd/com/android/gallery3d/filtershow/filters/FiltersManager.java b/src_pd/com/android/gallery3d/filtershow/filters/FiltersManager.java
index 915041b..3b3326c 100644
--- a/src_pd/com/android/gallery3d/filtershow/filters/FiltersManager.java
+++ b/src_pd/com/android/gallery3d/filtershow/filters/FiltersManager.java
@@ -16,17 +16,45 @@
 
 package com.android.gallery3d.filtershow.filters;
 
-import android.util.Log;
-
 import com.android.gallery3d.filtershow.cache.ImageLoader;
 
+import java.util.HashMap;
 import java.util.Vector;
 
 public class FiltersManager {
 
     private static final String LOGTAG = "FiltersManager";
+    private static FiltersManager gInstance = null;
+    private static HashMap<Class, ImageFilter> mFilters = new HashMap<Class, ImageFilter>();
 
-    public static void addFilters(Vector<ImageFilter> filters, ImageLoader imageLoader) {
+    private FiltersManager() {
+        Vector<ImageFilter> filters = new Vector<ImageFilter>();
+        FiltersManager.addFilters(filters);
+        for (ImageFilter filter : filters) {
+            mFilters.put(filter.getClass(), filter);
+        }
+    }
+
+    public ImageFilter getFilter(Class c) {
+        return mFilters.get(c);
+    }
+
+    public ImageFilter getFilterForRepresentation(FilterRepresentation representation) {
+        return mFilters.get(representation.getFilterClass());
+    }
+
+    public void addFilter(Class filterClass, ImageFilter filter) {
+        mFilters.put(filterClass, filter);
+    }
+
+    public static FiltersManager getManager() {
+        if (gInstance == null) {
+            gInstance = new FiltersManager();
+        }
+        return gInstance;
+    }
+
+    public static void addFilters(Vector<ImageFilter> filters) {
         filters.add(new ImageFilterTinyPlanet());
         filters.add(new ImageFilterWBalance());
         filters.add(new ImageFilterExposure());
@@ -43,6 +71,13 @@
         filters.add(new ImageFilterNegative());
         filters.add(new ImageFilterEdge());
         filters.add(new ImageFilterKMeans());
-        filters.add(new ImageFilterDownsample(imageLoader));
     }
+
+    public static void addFilters(Vector<ImageFilter> filters, ImageLoader imageLoader) {
+        FiltersManager.addFilters(filters);
+        filters.add(new ImageFilterDownsample(imageLoader));
+        FiltersManager.getManager().addFilter(ImageFilterDownsample.class,
+                new ImageFilterDownsample(imageLoader));
+    }
+
 }