Merge "Fix a bug with closing action bar context modes"
diff --git a/core/java/android/database/sqlite/SQLiteDatabase.java b/core/java/android/database/sqlite/SQLiteDatabase.java
index c0226f8..d058858 100644
--- a/core/java/android/database/sqlite/SQLiteDatabase.java
+++ b/core/java/android/database/sqlite/SQLiteDatabase.java
@@ -400,6 +400,7 @@
      * @see #unlock()
      */
     /* package */ void lock() {
+        verifyDbIsOpen();
         if (!mLockingEnabled) return;
         mLock.lock();
         if (SQLiteDebug.DEBUG_LOCK_TIME_TRACKING) {
@@ -420,6 +421,7 @@
      * @see #unlockForced()
      */
     private void lockForced() {
+        verifyDbIsOpen();
         mLock.lock();
         if (SQLiteDebug.DEBUG_LOCK_TIME_TRACKING) {
             if (mLock.getHoldCount() == 1) {
@@ -952,7 +954,10 @@
         //STOPSHIP - uncomment the following line
         //sqliteDatabase.setJournalMode(path, "TRUNCATE");
         // STOPSHIP remove the following lines
-        sqliteDatabase.enableWriteAheadLogging();
+        if (!path.equalsIgnoreCase(MEMORY_DB_PATH)) {
+            sqliteDatabase.enableWriteAheadLogging();
+        }
+        // END STOPSHIP
 
         // add this database to the list of databases opened in this process
         ActiveDatabases.addActiveDatabase(sqliteDatabase);
@@ -2406,14 +2411,18 @@
     }
 
     /**
-     * package visibility only for testing purposes
+     * This method disables the features enabled by {@link #enableWriteAheadLogging()}.
+     * @hide
      */
-    /* package */ synchronized void disableWriteAheadLogging() {
-        if (mConnectionPool == null) {
-            return;
+    public void disableWriteAheadLogging() {
+        synchronized (this) {
+            if (mConnectionPool == null) {
+                return;
+            }
+            mConnectionPool.close();
+            mConnectionPool = null;
+            setJournalMode(mPath, "TRUNCATE");
         }
-        mConnectionPool.close();
-        mConnectionPool = null;
     }
 
     /**
diff --git a/core/java/android/view/GLES20Canvas.java b/core/java/android/view/GLES20Canvas.java
index b811b7b..1424638 100644
--- a/core/java/android/view/GLES20Canvas.java
+++ b/core/java/android/view/GLES20Canvas.java
@@ -32,6 +32,11 @@
 import android.graphics.Region;
 import android.graphics.Shader;
 import android.graphics.SweepGradient;
+import android.graphics.TemporaryBuffer;
+import android.text.GraphicsOperations;
+import android.text.SpannableString;
+import android.text.SpannedString;
+import android.text.TextUtils;
 
 import javax.microedition.khronos.opengles.GL;
 
@@ -574,22 +579,46 @@
 
     @Override
     public void drawText(char[] text, int index, int count, float x, float y, Paint paint) {
-        // TODO: Implement
+        if ((index | count | (index + count) | (text.length - index - count)) < 0) {
+            throw new IndexOutOfBoundsException();
+        }
+        nDrawText(mRenderer, text, index, count, x, y, paint.mBidiFlags, paint.mNativePaint);
     }
+    
+    private native void nDrawText(int renderer, char[] text, int index, int count, float x, float y,
+            int bidiFlags, int paint);
 
     @Override
     public void drawText(CharSequence text, int start, int end, float x, float y, Paint paint) {
-        // TODO: Implement
+        if (text instanceof String || text instanceof SpannedString ||
+                text instanceof SpannableString) {
+            nDrawText(mRenderer, text.toString(), start, end, x, y, paint.mBidiFlags,
+                    paint.mNativePaint);
+        } else if (text instanceof GraphicsOperations) {
+            ((GraphicsOperations) text).drawText(this, start, end, x, y,
+                                                     paint);
+        } else {
+            char[] buf = TemporaryBuffer.obtain(end - start);
+            TextUtils.getChars(text, start, end, buf, 0);
+            nDrawText(mRenderer, buf, 0, end - start, x, y, paint.mBidiFlags, paint.mNativePaint);
+            TemporaryBuffer.recycle(buf);
+        }
     }
 
     @Override
     public void drawText(String text, int start, int end, float x, float y, Paint paint) {
-        // TODO: Implement
+        if ((start | end | (end - start) | (text.length() - end)) < 0) {
+            throw new IndexOutOfBoundsException();
+        }
+        nDrawText(mRenderer, text, start, end, x, y, paint.mBidiFlags, paint.mNativePaint);
     }
 
+    private native void nDrawText(int renderer, String text, int start, int end, float x, float y,
+            int bidiFlags, int paint);
+
     @Override
     public void drawText(String text, float x, float y, Paint paint) {
-        drawText(text, 0, text.length(), x, y, paint);
+        nDrawText(mRenderer, text, 0, text.length(), x, y, paint.mBidiFlags, paint.mNativePaint);
     }
 
     @Override
diff --git a/core/jni/android/graphics/Typeface.cpp b/core/jni/android/graphics/Typeface.cpp
index 7c7bfeb..1fe72e6 100644
--- a/core/jni/android/graphics/Typeface.cpp
+++ b/core/jni/android/graphics/Typeface.cpp
@@ -130,7 +130,13 @@
         return NULL;
     }
     
-    return SkTypeface::CreateFromStream(new AssetStream(asset, true));
+    SkStream* stream = new AssetStream(asset, true);
+    SkTypeface* face = SkTypeface::CreateFromStream(stream);
+    // SkTypeFace::CreateFromStream calls ref() on the stream, so we
+    // need to unref it here or it won't be freed later on
+    stream->unref();
+
+    return face;
 }
 
 static SkTypeface* Typeface_createFromFile(JNIEnv* env, jobject, jstring jpath) {
diff --git a/core/jni/android_view_GLES20Canvas.cpp b/core/jni/android_view_GLES20Canvas.cpp
index d177e1a..fa4d23c 100644
--- a/core/jni/android_view_GLES20Canvas.cpp
+++ b/core/jni/android_view_GLES20Canvas.cpp
@@ -14,6 +14,8 @@
  * limitations under the License.
  */
 
+#define LOG_TAG "OpenGLRenderer"
+
 #include "jni.h"
 #include <nativehelper/JNIHelp.h>
 #include <android_runtime/AndroidRuntime.h>
@@ -24,6 +26,7 @@
 #include <SkMatrix.h>
 #include <SkPaint.h>
 #include <SkRegion.h>
+#include <SkScalerContext.h>
 #include <SkXfermode.h>
 
 #include <OpenGLRenderer.h>
@@ -207,7 +210,6 @@
 
     renderer->drawPatch(bitmap, patch, left, top, right, bottom, paint);
 
-    // TODO: make sure that 0 is correct for the flags
     env->ReleaseByteArrayElements(chunks, storage, 0);
 }
 
@@ -246,6 +248,26 @@
 }
 
 // ----------------------------------------------------------------------------
+// Text
+// ----------------------------------------------------------------------------
+
+static void android_view_GLES20Canvas_drawTextArray(JNIEnv* env, jobject canvas,
+        OpenGLRenderer* renderer, jcharArray text, int index, int count,
+        jfloat x, jfloat y, int flags, SkPaint* paint) {
+    jchar* textArray = env->GetCharArrayElements(text, NULL);
+    // TODO: draw from textArray + index
+    env->ReleaseCharArrayElements(text, textArray, JNI_ABORT);
+}
+
+static void android_view_GLES20Canvas_drawText(JNIEnv* env, jobject canvas,
+        OpenGLRenderer* renderer, jstring text, int start, int end,
+        jfloat x, jfloat y, int flags, SkPaint* paint) {
+    const jchar* textArray = env->GetStringChars(text, NULL);
+    // TODO: draw from textArray + start
+    env->ReleaseStringChars(text, textArray);
+}
+
+// ----------------------------------------------------------------------------
 // JNI Glue
 // ----------------------------------------------------------------------------
 
@@ -288,6 +310,10 @@
     {   "nSetupBitmapShader", "(IIIIII)V",       (void*) android_view_GLES20Canvas_setupBitmapShader },
     {   "nSetupLinearShader", "(IIIIIIII)V",     (void*) android_view_GLES20Canvas_setupLinearShader },
 
+    {   "nDrawText",          "(I[CIIFFII)V",    (void*) android_view_GLES20Canvas_drawTextArray },
+    {   "nDrawText",          "(ILjava/lang/String;IIFFII)V",
+            (void*) android_view_GLES20Canvas_drawText },
+
     {   "nGetClipBounds",     "(ILandroid/graphics/Rect;)Z",
             (void*) android_view_GLES20Canvas_getClipBounds },
 };
diff --git a/core/jni/android_view_HardwareRenderer.cpp b/core/jni/android_view_HardwareRenderer.cpp
index abd788b..6d20c9d 100644
--- a/core/jni/android_view_HardwareRenderer.cpp
+++ b/core/jni/android_view_HardwareRenderer.cpp
@@ -34,13 +34,11 @@
 const char* const kClassPathName = "android/view/HardwareRenderer";
 
 static JNINativeMethod gMethods[] = {
-    {   "nativeAbandonGlCaches", "()V", 
-                                (void*)android_view_HardwareRenderer_abandonGlCaches },
+    {   "nativeAbandonGlCaches", "()V", (void*)android_view_HardwareRenderer_abandonGlCaches },
 };
 
 int register_android_view_HardwareRenderer(JNIEnv* env) {
-    return AndroidRuntime::registerNativeMethods(env,
-            kClassPathName, gMethods, NELEM(gMethods));
+    return AndroidRuntime::registerNativeMethods(env, kClassPathName, gMethods, NELEM(gMethods));
 }
 
 };
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 98b0a28..b37d887 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -201,6 +201,9 @@
     <!-- Indicate whether the SD card is accessible without removing the battery. -->
     <bool name="config_batterySdCardAccessibility">false</bool>
 
+    <!-- Indicate whether the device has USB host support. -->
+    <bool name="config_hasUsbHostSupport">false</bool>
+
     <!-- Vibrator pattern for feedback about a long screen/key press -->
     <integer-array name="config_longPressVibePattern">
         <item>0</item>
diff --git a/graphics/java/android/graphics/Paint.java b/graphics/java/android/graphics/Paint.java
index 9b4d3a8..3d63aa6 100644
--- a/graphics/java/android/graphics/Paint.java
+++ b/graphics/java/android/graphics/Paint.java
@@ -43,7 +43,10 @@
     private boolean     mHasCompatScaling;
     private float       mCompatScaling;
     private float       mInvCompatScaling;
-    /* package */ int   mBidiFlags = BIDI_DEFAULT_LTR;
+    /**
+     * @hide
+     */
+    public  int         mBidiFlags = BIDI_DEFAULT_LTR;
     
     private static final Style[] sStyleArray = {
         Style.FILL, Style.STROKE, Style.FILL_AND_STROKE
diff --git a/graphics/java/android/graphics/TemporaryBuffer.java b/graphics/java/android/graphics/TemporaryBuffer.java
index 1d7fe01..c5b8143 100644
--- a/graphics/java/android/graphics/TemporaryBuffer.java
+++ b/graphics/java/android/graphics/TemporaryBuffer.java
@@ -18,9 +18,11 @@
 
 import com.android.internal.util.ArrayUtils;
 
-/* package */ class TemporaryBuffer
-{
-    /* package */ static char[] obtain(int len) {
+/**
+ * @hide
+ */
+public class TemporaryBuffer {
+    public static char[] obtain(int len) {
         char[] buf;
 
         synchronized (TemporaryBuffer.class) {
@@ -28,15 +30,15 @@
             sTemp = null;
         }
 
-        if (buf == null || buf.length < len)
+        if (buf == null || buf.length < len) {
             buf = new char[ArrayUtils.idealCharArraySize(len)];
+        }
 
         return buf;
     }
 
-    /* package */ static void recycle(char[] temp) {
-        if (temp.length > 1000)
-            return;
+    public static void recycle(char[] temp) {
+        if (temp.length > 1000) return;
 
         synchronized (TemporaryBuffer.class) {
             sTemp = temp;
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index e39385a..1fa76d2 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -138,8 +138,8 @@
     mCurrentProgram = mDrawTextureProgram;
 
     mShader = kShaderNone;
-    mShaderTileX = SkShader::kClamp_TileMode;
-    mShaderTileY = SkShader::kClamp_TileMode;
+    mShaderTileX = GL_CLAMP_TO_EDGE;
+    mShaderTileY = GL_CLAMP_TO_EDGE;
     mShaderMatrix = NULL;
     mShaderBitmap = NULL;
 
@@ -535,8 +535,8 @@
     mShader = OpenGLRenderer::kShaderNone;
     mShaderKey = NULL;
     mShaderBlend = false;
-    mShaderTileX = SkShader::kClamp_TileMode;
-    mShaderTileY = SkShader::kClamp_TileMode;
+    mShaderTileX = GL_CLAMP_TO_EDGE;
+    mShaderTileY = GL_CLAMP_TO_EDGE;
 }
 
 void OpenGLRenderer::setupBitmapShader(SkBitmap* bitmap, SkShader::TileMode tileX,
@@ -544,8 +544,8 @@
     mShader = OpenGLRenderer::kShaderBitmap;
     mShaderBlend = hasAlpha;
     mShaderBitmap = bitmap;
-    mShaderTileX = tileX;
-    mShaderTileY = tileY;
+    mShaderTileX = gTileModes[tileX];
+    mShaderTileY = gTileModes[tileY];
     mShaderMatrix = matrix;
 }
 
@@ -556,8 +556,8 @@
     mShader = OpenGLRenderer::kShaderLinearGradient;
     mShaderKey = shader;
     mShaderBlend = hasAlpha;
-    mShaderTileX = tileMode;
-    mShaderTileY = tileMode;
+    mShaderTileX = gTileModes[tileMode];
+    mShaderTileY = gTileModes[tileMode];
     mShaderMatrix = matrix;
     mShaderBounds = bounds;
     mShaderColors = colors;
@@ -623,8 +623,18 @@
         float alpha, SkXfermode::Mode mode) {
     Texture* texture = mGradientCache.get(mShaderKey);
     if (!texture) {
+        SkShader::TileMode tileMode = SkShader::kClamp_TileMode;
+        switch (mShaderTileX) {
+            case GL_REPEAT:
+                tileMode = SkShader::kRepeat_TileMode;
+                break;
+            case GL_MIRRORED_REPEAT:
+                tileMode = SkShader::kMirror_TileMode;
+                break;
+        }
+
         texture = mGradientCache.addLinearGradient(mShaderKey, mShaderBounds, mShaderColors,
-                mShaderPositions, mShaderCount, mShaderTileX);
+                mShaderPositions, mShaderCount, tileMode);
     }
 
     mModelView.loadTranslate(left, top, 0.0f);
@@ -634,14 +644,7 @@
     mDrawLinearGradientProgram->set(mOrthoMatrix, mModelView, mSnapshot->transform);
 
     chooseBlending(mShaderBlend || alpha < 1.0f, mode);
-
-    if (texture->id != mLastTexture) {
-        glBindTexture(GL_TEXTURE_2D, texture->id);
-        mLastTexture = texture->id;
-    }
-    // TODO: Don't set the texture parameters every time
-    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, gTileModes[mShaderTileX]);
-    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, gTileModes[mShaderTileX]);
+    bindTexture(texture->id, mShaderTileX, mShaderTileY);
 
     Rect start(mShaderBounds[0], mShaderBounds[1], mShaderBounds[2], mShaderBounds[3]);
     if (mShaderMatrix) {
@@ -736,14 +739,7 @@
     mDrawTextureProgram->set(mOrthoMatrix, mModelView, mSnapshot->transform);
 
     chooseBlending(blend || alpha < 1.0f, mode);
-
-    if (texture != mLastTexture) {
-        glBindTexture(GL_TEXTURE_2D, texture);
-        mLastTexture = texture;
-    }
-    // TODO: Don't set the texture parameters every time
-    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, gTileModes[mShaderTileX]);
-    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, gTileModes[mShaderTileY]);
+    bindTexture(texture, mShaderTileX, mShaderTileY);
 
     // Always premultiplied
     //glUniform4f(mDrawTextureProgram->color, alpha, alpha, alpha, alpha);
@@ -826,5 +822,15 @@
     }
 }
 
+void OpenGLRenderer::bindTexture(GLuint texture, GLenum wrapS, GLenum wrapT) {
+    if (texture != mLastTexture) {
+        glBindTexture(GL_TEXTURE_2D, texture);
+        mLastTexture = texture;
+    }
+    // TODO: Don't set the texture parameters every time
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wrapS);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrapT);
+}
+
 }; // namespace uirenderer
 }; // namespace android
diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h
index dd7999d..9dc2a43 100644
--- a/libs/hwui/OpenGLRenderer.h
+++ b/libs/hwui/OpenGLRenderer.h
@@ -287,6 +287,11 @@
     inline void getAlphaAndMode(const SkPaint* paint, int* alpha, SkXfermode::Mode* mode);
 
     /**
+     * Binds the specified texture with the specified wrap modes.
+     */
+    inline void bindTexture(GLuint texture, GLenum wrapS, GLenum wrapT);
+
+    /**
      * Enable or disable blending as necessary. This function sets the appropriate
      * blend function based on the specified xfermode.
      */
@@ -341,8 +346,8 @@
     ShaderType mShader;
     SkShader* mShaderKey;
     bool mShaderBlend;
-    SkShader::TileMode mShaderTileX;
-    SkShader::TileMode mShaderTileY;
+    GLenum mShaderTileX;
+    GLenum mShaderTileY;
     SkMatrix* mShaderMatrix;
     // Bitmaps
     SkBitmap* mShaderBitmap;
diff --git a/libs/rs/java/ImageProcessing/Android.mk b/libs/rs/java/ImageProcessing/Android.mk
index f7ff378..7fa30d0 100644
--- a/libs/rs/java/ImageProcessing/Android.mk
+++ b/libs/rs/java/ImageProcessing/Android.mk
@@ -21,7 +21,8 @@
 
 LOCAL_MODULE_TAGS := optional
 
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
+LOCAL_SRC_FILES := $(call all-java-files-under, src) \
+                   $(call all-renderscript-files-under, src)
 #LOCAL_STATIC_JAVA_LIBRARIES := android.renderscript
 
 LOCAL_PACKAGE_NAME := ImageProcessing
diff --git a/libs/rs/java/ImageProcessing/res/raw/horizontal_blur_bc.bc b/libs/rs/java/ImageProcessing/res/raw/horizontal_blur_bc.bc
deleted file mode 100644
index 5920f3a..0000000
--- a/libs/rs/java/ImageProcessing/res/raw/horizontal_blur_bc.bc
+++ /dev/null
Binary files differ
diff --git a/libs/rs/java/ImageProcessing/res/raw/threshold.rs b/libs/rs/java/ImageProcessing/res/raw/threshold.rs
deleted file mode 100644
index aa6b6fa..0000000
--- a/libs/rs/java/ImageProcessing/res/raw/threshold.rs
+++ /dev/null
@@ -1,176 +0,0 @@
-#pragma version(1)
-
-#include "../../../../scriptc/rs_types.rsh"
-#include "../../../../scriptc/rs_math.rsh"
-
-#include "ip.rsh"
-
-int height;
-int width;
-int radius;
-
-uchar4 * InPixel;
-uchar4 * OutPixel;
-uchar4 * ScratchPixel;
-
-float inBlack;
-float outBlack;
-float inWhite;
-float outWhite;
-float gamma;
-
-float saturation;
-
-static float inWMinInB;
-static float outWMinOutB;
-static float overInWMinInB;
-
-#pragma rs export_var(height, width, radius, InPixel, OutPixel, ScratchPixel, inBlack, outBlack, inWhite, outWhite, gamma, saturation, InPixel, OutPixel, ScratchPixel, vBlurScript, hBlurScript)
-#pragma rs export_func(filter, filterBenchmark);
-
-rs_script vBlurScript;
-rs_script hBlurScript;
-
-
-// Store our coefficients here
-static float gaussian[MAX_RADIUS * 2 + 1];
-static rs_matrix3x3 colorMat;
-
-static void computeColorMatrix() {
-    // Saturation
-    // Linear weights
-    //float rWeight = 0.3086f;
-    //float gWeight = 0.6094f;
-    //float bWeight = 0.0820f;
-
-    // Gamma 2.2 weights (we haven't converted our image to linear space yet for perf reasons)
-    float rWeight = 0.299f;
-    float gWeight = 0.587f;
-    float bWeight = 0.114f;
-
-    float oneMinusS = 1.0f - saturation;
-
-    rsMatrixSet(&colorMat, 0, 0, oneMinusS * rWeight + saturation);
-    rsMatrixSet(&colorMat, 0, 1, oneMinusS * rWeight);
-    rsMatrixSet(&colorMat, 0, 2, oneMinusS * rWeight);
-    rsMatrixSet(&colorMat, 1, 0, oneMinusS * gWeight);
-    rsMatrixSet(&colorMat, 1, 1, oneMinusS * gWeight + saturation);
-    rsMatrixSet(&colorMat, 1, 2, oneMinusS * gWeight);
-    rsMatrixSet(&colorMat, 2, 0, oneMinusS * bWeight);
-    rsMatrixSet(&colorMat, 2, 1, oneMinusS * bWeight);
-    rsMatrixSet(&colorMat, 2, 2, oneMinusS * bWeight + saturation);
-
-    inWMinInB = inWhite - inBlack;
-    outWMinOutB = outWhite - outBlack;
-    overInWMinInB = 1.f / inWMinInB;
-}
-
-static void computeGaussianWeights() {
-    // Compute gaussian weights for the blur
-    // e is the euler's number
-    float e = 2.718281828459045f;
-    float pi = 3.1415926535897932f;
-    // g(x) = ( 1 / sqrt( 2 * pi ) * sigma) * e ^ ( -x^2 / 2 * sigma^2 )
-    // x is of the form [-radius .. 0 .. radius]
-    // and sigma varies with radius.
-    // Based on some experimental radius values and sigma's
-    // we approximately fit sigma = f(radius) as
-    // sigma = radius * 0.4  + 0.6
-    // The larger the radius gets, the more our gaussian blur
-    // will resemble a box blur since with large sigma
-    // the gaussian curve begins to lose its shape
-    float sigma = 0.4f * (float)radius + 0.6f;
-
-    // Now compute the coefficints
-    // We will store some redundant values to save some math during
-    // the blur calculations
-    // precompute some values
-    float coeff1 = 1.0f / (sqrt( 2.0f * pi ) * sigma);
-    float coeff2 = - 1.0f / (2.0f * sigma * sigma);
-
-    float normalizeFactor = 0.0f;
-    float floatR = 0.0f;
-    int r;
-    for(r = -radius; r <= radius; r ++) {
-        floatR = (float)r;
-        gaussian[r + radius] = coeff1 * pow(e, floatR * floatR * coeff2);
-        normalizeFactor += gaussian[r + radius];
-    }
-
-    //Now we need to normalize the weights because all our coefficients need to add up to one
-    normalizeFactor = 1.0f / normalizeFactor;
-    for(r = -radius; r <= radius; r ++) {
-        floatR = (float)r;
-        gaussian[r + radius] *= normalizeFactor;
-    }
-}
-
-static void processNoBlur() {
-    float inWMinInB = inWhite - inBlack;
-    float outWMinOutB = outWhite - outBlack;
-    float4 currentPixel = 0;
-
-    for(int h = 0; h < height; h ++) {
-        uchar4 *input = InPixel + h*width;
-        uchar4 *output = OutPixel + h*width;
-
-        for(int w = 0; w < width; w ++) {
-            //currentPixel.xyz = convert_float3(input.xyz);
-            currentPixel.x = (float)(input->x);
-            currentPixel.y = (float)(input->y);
-            currentPixel.z = (float)(input->z);
-
-            float3 temp = rsMatrixMultiply(&colorMat, currentPixel.xyz);
-            temp = (clamp(temp, 0.f, 255.f) - inBlack) * overInWMinInB;
-            temp = pow(temp, (float3)gamma);
-            currentPixel.xyz = clamp(temp * outWMinOutB + outBlack, 0.f, 255.f);
-
-            //output.xyz = convert_uchar3(currentPixel.xyz);
-            output->x = (uint8_t)currentPixel.x;
-            output->y = (uint8_t)currentPixel.y;
-            output->z = (uint8_t)currentPixel.z;
-            output->w = input->w;
-
-            input++;
-            output++;
-        }
-    }
-}
-
-static void blur() {
-    computeGaussianWeights();
-
-    FilterStruct fs;
-    fs.gaussian = gaussian;
-    fs.width = width;
-    fs.height = height;
-    fs.radius = radius;
-
-    fs.ain = rsGetAllocation(InPixel);
-    rsForEach(hBlurScript, fs.ain, rsGetAllocation(ScratchPixel), &fs);
-
-    fs.ain = rsGetAllocation(ScratchPixel);
-    rsForEach(vBlurScript, fs.ain, rsGetAllocation(OutPixel), &fs);
-}
-
-void filter() {
-    RS_DEBUG(radius);
-
-    computeColorMatrix();
-
-    if(radius > 0) {
-        blur();
-    }
-    processNoBlur();
-
-    int count = 0;
-    rsSendToClient(&count, 1, 4, 0);
-}
-
-void filterBenchmark() {
-    blur();
-
-    int count = 0;
-    rsSendToClient(&count, 1, 4, 0);
-}
-
diff --git a/libs/rs/java/ImageProcessing/res/raw/threshold_bc.bc b/libs/rs/java/ImageProcessing/res/raw/threshold_bc.bc
deleted file mode 100644
index 2b5d254..0000000
--- a/libs/rs/java/ImageProcessing/res/raw/threshold_bc.bc
+++ /dev/null
Binary files differ
diff --git a/libs/rs/java/ImageProcessing/res/raw/vertical_blur_bc.bc b/libs/rs/java/ImageProcessing/res/raw/vertical_blur_bc.bc
deleted file mode 100644
index be5d0e4..0000000
--- a/libs/rs/java/ImageProcessing/res/raw/vertical_blur_bc.bc
+++ /dev/null
Binary files differ
diff --git a/libs/rs/java/ImageProcessing/src/com/android/rs/image/ImageProcessingActivity.java b/libs/rs/java/ImageProcessing/src/com/android/rs/image/ImageProcessingActivity.java
index 0ed1185..606bfa8 100644
--- a/libs/rs/java/ImageProcessing/src/com/android/rs/image/ImageProcessingActivity.java
+++ b/libs/rs/java/ImageProcessing/src/com/android/rs/image/ImageProcessingActivity.java
@@ -44,6 +44,7 @@
     private ScriptC_Threshold mScript;
     private ScriptC_Vertical_blur mScriptVBlur;
     private ScriptC_Horizontal_blur mScriptHBlur;
+    private ScriptC_Levels mScriptLevels;
     private int mRadius = 0;
     private SeekBar mRadiusSeekBar;
 
@@ -260,29 +261,29 @@
             }
             else if(seekBar == mInBlackSeekBar) {
                 mInBlack = (float)progress;
-                mScript.set_inBlack(mInBlack);
+                mScriptLevels.invoke_setLevels(mInBlack, mOutBlack, mInWhite, mOutWhite);
             }
             else if(seekBar == mOutBlackSeekBar) {
                 mOutBlack = (float)progress;
-                mScript.set_outBlack(mOutBlack);
+                mScriptLevels.invoke_setLevels(mInBlack, mOutBlack, mInWhite, mOutWhite);
             }
             else if(seekBar == mInWhiteSeekBar) {
                 mInWhite = (float)progress + 127.0f;
-                mScript.set_inWhite(mInWhite);
+                mScriptLevels.invoke_setLevels(mInBlack, mOutBlack, mInWhite, mOutWhite);
             }
             else if(seekBar == mOutWhiteSeekBar) {
                 mOutWhite = (float)progress + 127.0f;
-                mScript.set_outWhite(mOutWhite);
+                mScriptLevels.invoke_setLevels(mInBlack, mOutBlack, mInWhite, mOutWhite);
             }
             else if(seekBar == mGammaSeekBar) {
                 mGamma = (float)progress/100.0f;
                 mGamma = Math.max(mGamma, 0.1f);
                 mGamma = 1.0f / mGamma;
-                mScript.set_gamma(mGamma);
+                mScriptLevels.invoke_setGamma(mGamma);
             }
             else if(seekBar == mSaturationSeekBar) {
                 mSaturation = (float)progress / 50.0f;
-                mScript.set_saturation(mSaturation);
+                mScriptLevels.invoke_setSaturation(mSaturation);
             }
 
             long t = java.lang.System.currentTimeMillis();
@@ -375,20 +376,18 @@
         mOutPixelsAllocation = Allocation.createBitmapRef(mRS, mBitmapOut);
         mScratchPixelsAllocation = Allocation.createBitmapRef(mRS, mBitmapScratch);
 
-        mScriptVBlur = new ScriptC_Vertical_blur(mRS, getResources(), R.raw.vertical_blur_bc, false);
-        mScriptHBlur = new ScriptC_Horizontal_blur(mRS, getResources(), R.raw.horizontal_blur_bc, false);
+        mScriptVBlur = new ScriptC_Vertical_blur(mRS, getResources(), R.raw.vertical_blur, false);
+        mScriptHBlur = new ScriptC_Horizontal_blur(mRS, getResources(), R.raw.horizontal_blur, false);
+        mScriptLevels = new ScriptC_Levels(mRS, getResources(), R.raw.levels, false);
 
-        mScript = new ScriptC_Threshold(mRS, getResources(), R.raw.threshold_bc, false);
+        mScript = new ScriptC_Threshold(mRS, getResources(), R.raw.threshold, false);
         mScript.set_width(mBitmapIn.getWidth());
         mScript.set_height(mBitmapIn.getHeight());
         mScript.set_radius(mRadius);
 
-        mScript.set_inBlack(mInBlack);
-        mScript.set_outBlack(mOutBlack);
-        mScript.set_inWhite(mInWhite);
-        mScript.set_outWhite(mOutWhite);
-        mScript.set_gamma(mGamma);
-        mScript.set_saturation(mSaturation);
+        mScriptLevels.invoke_setLevels(mInBlack, mOutBlack, mInWhite, mOutWhite);
+        mScriptLevels.invoke_setGamma(mGamma);
+        mScriptLevels.invoke_setSaturation(mSaturation);
 
         mScript.bind_InPixel(mInPixelsAllocation);
         mScript.bind_OutPixel(mOutPixelsAllocation);
@@ -396,6 +395,7 @@
 
         mScript.set_vBlurScript(mScriptVBlur);
         mScript.set_hBlurScript(mScriptHBlur);
+        mScript.set_levelsScript(mScriptLevels);
     }
 
     private Bitmap loadBitmap(int resource) {
diff --git a/libs/rs/java/ImageProcessing/src/com/android/rs/image/ScriptC_Horizontal_blur.java b/libs/rs/java/ImageProcessing/src/com/android/rs/image/ScriptC_Horizontal_blur.java
deleted file mode 100644
index c447b9b..0000000
--- a/libs/rs/java/ImageProcessing/src/com/android/rs/image/ScriptC_Horizontal_blur.java
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * Copyright (C) 2010 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.rs.image;
-
-import android.renderscript.*;
-import android.content.res.Resources;
-import android.util.Log;
-
-public class ScriptC_Horizontal_blur extends ScriptC {
-    // Constructor
-    public  ScriptC_Horizontal_blur(RenderScript rs, Resources resources, int id, boolean isRoot) {
-        super(rs, resources, id, isRoot);
-    }
-
-}
-
diff --git a/libs/rs/java/ImageProcessing/src/com/android/rs/image/ScriptC_Threshold.java b/libs/rs/java/ImageProcessing/src/com/android/rs/image/ScriptC_Threshold.java
deleted file mode 100644
index c23dca1..0000000
--- a/libs/rs/java/ImageProcessing/src/com/android/rs/image/ScriptC_Threshold.java
+++ /dev/null
@@ -1,197 +0,0 @@
-/*
- * Copyright (C) 2010 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.rs.image;
-
-import android.renderscript.*;
-import android.content.res.Resources;
-import android.util.Log;
-
-public class ScriptC_Threshold extends ScriptC {
-    // Constructor
-    public  ScriptC_Threshold(RenderScript rs, Resources resources, int id, boolean isRoot) {
-        super(rs, resources, id, isRoot);
-    }
-
-    private final static int mExportVarIdx_height = 0;
-    private int mExportVar_height;
-    public void set_height(int v) {
-        mExportVar_height = v;
-        setVar(mExportVarIdx_height, v);
-    }
-
-    public int get_height() {
-        return mExportVar_height;
-    }
-
-    private final static int mExportVarIdx_width = 1;
-    private int mExportVar_width;
-    public void set_width(int v) {
-        mExportVar_width = v;
-        setVar(mExportVarIdx_width, v);
-    }
-
-    public int get_width() {
-        return mExportVar_width;
-    }
-
-    private final static int mExportVarIdx_radius = 2;
-    private int mExportVar_radius;
-    public void set_radius(int v) {
-        mExportVar_radius = v;
-        setVar(mExportVarIdx_radius, v);
-    }
-
-    public int get_radius() {
-        return mExportVar_radius;
-    }
-
-    private final static int mExportVarIdx_InPixel = 3;
-    private Allocation mExportVar_InPixel;
-    public void bind_InPixel(Allocation v) {
-        mExportVar_InPixel = v;
-        if(v == null) bindAllocation(null, mExportVarIdx_InPixel);
-        else bindAllocation(v, mExportVarIdx_InPixel);
-    }
-
-    public Allocation get_InPixel() {
-        return mExportVar_InPixel;
-    }
-
-    private final static int mExportVarIdx_OutPixel = 4;
-    private Allocation mExportVar_OutPixel;
-    public void bind_OutPixel(Allocation v) {
-        mExportVar_OutPixel = v;
-        if(v == null) bindAllocation(null, mExportVarIdx_OutPixel);
-        else bindAllocation(v, mExportVarIdx_OutPixel);
-    }
-
-    public Allocation get_OutPixel() {
-        return mExportVar_OutPixel;
-    }
-
-    private final static int mExportVarIdx_ScratchPixel = 5;
-    private Allocation mExportVar_ScratchPixel;
-    public void bind_ScratchPixel(Allocation v) {
-        mExportVar_ScratchPixel = v;
-        if(v == null) bindAllocation(null, mExportVarIdx_ScratchPixel);
-        else bindAllocation(v, mExportVarIdx_ScratchPixel);
-    }
-
-    public Allocation get_ScratchPixel() {
-        return mExportVar_ScratchPixel;
-    }
-
-    private final static int mExportVarIdx_inBlack = 6;
-    private float mExportVar_inBlack;
-    public void set_inBlack(float v) {
-        mExportVar_inBlack = v;
-        setVar(mExportVarIdx_inBlack, v);
-    }
-
-    public float get_inBlack() {
-        return mExportVar_inBlack;
-    }
-
-    private final static int mExportVarIdx_outBlack = 7;
-    private float mExportVar_outBlack;
-    public void set_outBlack(float v) {
-        mExportVar_outBlack = v;
-        setVar(mExportVarIdx_outBlack, v);
-    }
-
-    public float get_outBlack() {
-        return mExportVar_outBlack;
-    }
-
-    private final static int mExportVarIdx_inWhite = 8;
-    private float mExportVar_inWhite;
-    public void set_inWhite(float v) {
-        mExportVar_inWhite = v;
-        setVar(mExportVarIdx_inWhite, v);
-    }
-
-    public float get_inWhite() {
-        return mExportVar_inWhite;
-    }
-
-    private final static int mExportVarIdx_outWhite = 9;
-    private float mExportVar_outWhite;
-    public void set_outWhite(float v) {
-        mExportVar_outWhite = v;
-        setVar(mExportVarIdx_outWhite, v);
-    }
-
-    public float get_outWhite() {
-        return mExportVar_outWhite;
-    }
-
-    private final static int mExportVarIdx_gamma = 10;
-    private float mExportVar_gamma;
-    public void set_gamma(float v) {
-        mExportVar_gamma = v;
-        setVar(mExportVarIdx_gamma, v);
-    }
-
-    public float get_gamma() {
-        return mExportVar_gamma;
-    }
-
-    private final static int mExportVarIdx_saturation = 11;
-    private float mExportVar_saturation;
-    public void set_saturation(float v) {
-        mExportVar_saturation = v;
-        setVar(mExportVarIdx_saturation, v);
-    }
-
-    public float get_saturation() {
-        return mExportVar_saturation;
-    }
-
-    private final static int mExportVarIdx_vBlurScript = 12;
-    private Script mExportVar_vBlurScript;
-    public void set_vBlurScript(Script v) {
-        mExportVar_vBlurScript = v;
-        setVar(mExportVarIdx_vBlurScript, (v == null) ? 0 : v.getID());
-    }
-
-    public Script get_vBlurScript() {
-        return mExportVar_vBlurScript;
-    }
-
-    private final static int mExportVarIdx_hBlurScript = 13;
-    private Script mExportVar_hBlurScript;
-    public void set_hBlurScript(Script v) {
-        mExportVar_hBlurScript = v;
-        setVar(mExportVarIdx_hBlurScript, (v == null) ? 0 : v.getID());
-    }
-
-    public Script get_hBlurScript() {
-        return mExportVar_hBlurScript;
-    }
-
-    private final static int mExportFuncIdx_filter = 0;
-    public void invoke_filter() {
-        invoke(mExportFuncIdx_filter);
-    }
-
-    private final static int mExportFuncIdx_filterBenchmark = 1;
-    public void invoke_filterBenchmark() {
-        invoke(mExportFuncIdx_filterBenchmark);
-    }
-
-}
-
diff --git a/libs/rs/java/ImageProcessing/src/com/android/rs/image/ScriptC_Vertical_blur.java b/libs/rs/java/ImageProcessing/src/com/android/rs/image/ScriptC_Vertical_blur.java
deleted file mode 100644
index cee74d9..0000000
--- a/libs/rs/java/ImageProcessing/src/com/android/rs/image/ScriptC_Vertical_blur.java
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * Copyright (C) 2010 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.rs.image;
-
-import android.renderscript.*;
-import android.content.res.Resources;
-import android.util.Log;
-
-public class ScriptC_Vertical_blur extends ScriptC {
-    // Constructor
-    public  ScriptC_Vertical_blur(RenderScript rs, Resources resources, int id, boolean isRoot) {
-        super(rs, resources, id, isRoot);
-    }
-
-}
-
diff --git a/libs/rs/java/ImageProcessing/res/raw/horizontal_blur.rs b/libs/rs/java/ImageProcessing/src/com/android/rs/image/horizontal_blur.rs
similarity index 92%
rename from libs/rs/java/ImageProcessing/res/raw/horizontal_blur.rs
rename to libs/rs/java/ImageProcessing/src/com/android/rs/image/horizontal_blur.rs
index 10815fb..b580393 100644
--- a/libs/rs/java/ImageProcessing/res/raw/horizontal_blur.rs
+++ b/libs/rs/java/ImageProcessing/src/com/android/rs/image/horizontal_blur.rs
@@ -1,7 +1,7 @@
 #pragma version(1)
 
-#include "../../../../scriptc/rs_types.rsh"
-#include "../../../../scriptc/rs_math.rsh"
+#include "rs_types.rsh"
+#include "rs_math.rsh"
 
 #include "ip.rsh"
 
diff --git a/libs/rs/java/ImageProcessing/res/raw/ip.rsh b/libs/rs/java/ImageProcessing/src/com/android/rs/image/ip.rsh
similarity index 88%
rename from libs/rs/java/ImageProcessing/res/raw/ip.rsh
rename to libs/rs/java/ImageProcessing/src/com/android/rs/image/ip.rsh
index dea92c3..34213f5 100644
--- a/libs/rs/java/ImageProcessing/res/raw/ip.rsh
+++ b/libs/rs/java/ImageProcessing/src/com/android/rs/image/ip.rsh
@@ -6,8 +6,6 @@
     rs_allocation ain;
 
     float *gaussian; //[MAX_RADIUS * 2 + 1];
-    rs_matrix3x3 colorMat;
-
     int height;
     int width;
     int radius;
diff --git a/libs/rs/java/ImageProcessing/src/com/android/rs/image/levels.rs b/libs/rs/java/ImageProcessing/src/com/android/rs/image/levels.rs
new file mode 100644
index 0000000..b0db8a3
--- /dev/null
+++ b/libs/rs/java/ImageProcessing/src/com/android/rs/image/levels.rs
@@ -0,0 +1,88 @@
+#pragma version(1)
+
+#include "rs_types.rsh"
+#include "rs_math.rsh"
+
+#include "ip.rsh"
+
+
+static float inBlack;
+static float outBlack;
+static float inWhite;
+static float outWhite;
+static float3 gamma;
+static float saturation;
+
+static float inWMinInB;
+static float outWMinOutB;
+static float overInWMinInB;
+static rs_matrix3x3 colorMat;
+
+//#pragma rs export_var(height, width, radius, InPixel, OutPixel, ScratchPixel, inBlack, outBlack, inWhite, outWhite, gamma, saturation, InPixel, OutPixel, ScratchPixel, vBlurScript, hBlurScript)
+#pragma rs export_func(setLevels, setSaturation, setGamma);
+
+void setLevels(float iBlk, float oBlk, float iWht, float oWht) {
+    inBlack = iBlk;
+    outBlack = oBlk;
+    inWhite = iWht;
+    outWhite = oWht;
+
+    inWMinInB = inWhite - inBlack;
+    outWMinOutB = outWhite - outBlack;
+    overInWMinInB = 1.f / inWMinInB;
+}
+
+void setSaturation(float sat) {
+    saturation = sat;
+
+    // Saturation
+    // Linear weights
+    //float rWeight = 0.3086f;
+    //float gWeight = 0.6094f;
+    //float bWeight = 0.0820f;
+
+    // Gamma 2.2 weights (we haven't converted our image to linear space yet for perf reasons)
+    float rWeight = 0.299f;
+    float gWeight = 0.587f;
+    float bWeight = 0.114f;
+
+    float oneMinusS = 1.0f - saturation;
+    rsMatrixSet(&colorMat, 0, 0, oneMinusS * rWeight + saturation);
+    rsMatrixSet(&colorMat, 0, 1, oneMinusS * rWeight);
+    rsMatrixSet(&colorMat, 0, 2, oneMinusS * rWeight);
+    rsMatrixSet(&colorMat, 1, 0, oneMinusS * gWeight);
+    rsMatrixSet(&colorMat, 1, 1, oneMinusS * gWeight + saturation);
+    rsMatrixSet(&colorMat, 1, 2, oneMinusS * gWeight);
+    rsMatrixSet(&colorMat, 2, 0, oneMinusS * bWeight);
+    rsMatrixSet(&colorMat, 2, 1, oneMinusS * bWeight);
+    rsMatrixSet(&colorMat, 2, 2, oneMinusS * bWeight + saturation);
+}
+
+void setGamma(float g) {
+    gamma = (float3)g;
+}
+
+
+void root(const void *v_in, void *v_out, const void *usrData, uint32_t x, uint32_t y) {
+    const uchar4 *input = v_in;
+    uchar4 *output = v_out;
+
+    float4 currentPixel = 0;
+
+    //currentPixel.xyz = convert_float3(input.xyz);
+    currentPixel.x = (float)(input->x);
+    currentPixel.y = (float)(input->y);
+    currentPixel.z = (float)(input->z);
+
+    float3 temp = rsMatrixMultiply(&colorMat, currentPixel.xyz);
+    temp = (clamp(temp, 0.f, 255.f) - inBlack) * overInWMinInB;
+    temp = pow(temp, (float3)gamma);
+    currentPixel.xyz = clamp(temp * outWMinOutB + outBlack, 0.f, 255.f);
+
+    //output.xyz = convert_uchar3(currentPixel.xyz);
+    output->x = (uint8_t)currentPixel.x;
+    output->y = (uint8_t)currentPixel.y;
+    output->z = (uint8_t)currentPixel.z;
+    output->w = input->w;
+}
+
diff --git a/libs/rs/java/ImageProcessing/src/com/android/rs/image/threshold.rs b/libs/rs/java/ImageProcessing/src/com/android/rs/image/threshold.rs
new file mode 100644
index 0000000..3cd43c7
--- /dev/null
+++ b/libs/rs/java/ImageProcessing/src/com/android/rs/image/threshold.rs
@@ -0,0 +1,105 @@
+#pragma version(1)
+
+#include "rs_types.rsh"
+#include "rs_math.rsh"
+
+#include "ip.rsh"
+
+int height;
+int width;
+int radius;
+
+uchar4 * InPixel;
+uchar4 * OutPixel;
+uchar4 * ScratchPixel;
+
+#pragma rs export_var(height, width, radius, InPixel, OutPixel, ScratchPixel, vBlurScript, hBlurScript, levelsScript)
+#pragma rs export_func(filter, filterBenchmark);
+
+rs_script vBlurScript;
+rs_script hBlurScript;
+rs_script levelsScript;
+
+
+// Store our coefficients here
+static float gaussian[MAX_RADIUS * 2 + 1];
+
+
+static void computeGaussianWeights() {
+    // Compute gaussian weights for the blur
+    // e is the euler's number
+    float e = 2.718281828459045f;
+    float pi = 3.1415926535897932f;
+    // g(x) = ( 1 / sqrt( 2 * pi ) * sigma) * e ^ ( -x^2 / 2 * sigma^2 )
+    // x is of the form [-radius .. 0 .. radius]
+    // and sigma varies with radius.
+    // Based on some experimental radius values and sigma's
+    // we approximately fit sigma = f(radius) as
+    // sigma = radius * 0.4  + 0.6
+    // The larger the radius gets, the more our gaussian blur
+    // will resemble a box blur since with large sigma
+    // the gaussian curve begins to lose its shape
+    float sigma = 0.4f * (float)radius + 0.6f;
+
+    // Now compute the coefficints
+    // We will store some redundant values to save some math during
+    // the blur calculations
+    // precompute some values
+    float coeff1 = 1.0f / (sqrt( 2.0f * pi ) * sigma);
+    float coeff2 = - 1.0f / (2.0f * sigma * sigma);
+
+    float normalizeFactor = 0.0f;
+    float floatR = 0.0f;
+    int r;
+    for(r = -radius; r <= radius; r ++) {
+        floatR = (float)r;
+        gaussian[r + radius] = coeff1 * pow(e, floatR * floatR * coeff2);
+        normalizeFactor += gaussian[r + radius];
+    }
+
+    //Now we need to normalize the weights because all our coefficients need to add up to one
+    normalizeFactor = 1.0f / normalizeFactor;
+    for(r = -radius; r <= radius; r ++) {
+        floatR = (float)r;
+        gaussian[r + radius] *= normalizeFactor;
+    }
+}
+
+
+static void blur() {
+    computeGaussianWeights();
+
+    FilterStruct fs;
+    fs.gaussian = gaussian;
+    fs.width = width;
+    fs.height = height;
+    fs.radius = radius;
+
+    fs.ain = rsGetAllocation(InPixel);
+    rsForEach(hBlurScript, fs.ain, rsGetAllocation(ScratchPixel), &fs);
+
+    fs.ain = rsGetAllocation(ScratchPixel);
+    rsForEach(vBlurScript, fs.ain, rsGetAllocation(OutPixel), &fs);
+}
+
+void filter() {
+    //RS_DEBUG(radius);
+
+    if(radius > 0) {
+        blur();
+        rsForEach(levelsScript, rsGetAllocation(OutPixel), rsGetAllocation(OutPixel), 0);
+    } else {
+        rsForEach(levelsScript, rsGetAllocation(InPixel), rsGetAllocation(OutPixel), 0);
+    }
+
+    int count = 0;
+    rsSendToClient(&count, 1, 4, 0);
+}
+
+void filterBenchmark() {
+    blur();
+
+    int count = 0;
+    rsSendToClient(&count, 1, 4, 0);
+}
+
diff --git a/libs/rs/java/ImageProcessing/res/raw/vertical_blur.rs b/libs/rs/java/ImageProcessing/src/com/android/rs/image/vertical_blur.rs
similarity index 93%
rename from libs/rs/java/ImageProcessing/res/raw/vertical_blur.rs
rename to libs/rs/java/ImageProcessing/src/com/android/rs/image/vertical_blur.rs
index f5f2d69..23387ef 100644
--- a/libs/rs/java/ImageProcessing/res/raw/vertical_blur.rs
+++ b/libs/rs/java/ImageProcessing/src/com/android/rs/image/vertical_blur.rs
@@ -1,7 +1,7 @@
 #pragma version(1)
 
-#include "../../../../scriptc/rs_types.rsh"
-#include "../../../../scriptc/rs_math.rsh"
+#include "rs_types.rsh"
+#include "rs_math.rsh"
 
 #include "ip.rsh"
 
diff --git a/libs/rs/rsContext.cpp b/libs/rs/rsContext.cpp
index 629b481..e897d00 100644
--- a/libs/rs/rsContext.cpp
+++ b/libs/rs/rsContext.cpp
@@ -361,7 +361,7 @@
      Context *rsc = static_cast<Context *>(vrsc);
      uint32_t idx = (uint32_t)android_atomic_inc(&rsc->mWorkers.mLaunchCount);
 
-     LOGE("helperThreadProc 1 %p idx=%i", rsc, idx);
+     LOGV("RS helperThread starting %p idx=%i", rsc, idx);
 
      rsc->mWorkers.mLaunchSignals[idx].init();
      rsc->mWorkers.mNativeThreadId[idx] = gettid();
@@ -376,13 +376,13 @@
      while(rsc->mRunning) {
          rsc->mWorkers.mLaunchSignals[idx].wait();
          if (rsc->mWorkers.mLaunchCallback) {
-    LOGE("helperThreadProc 4");
             rsc->mWorkers.mLaunchCallback(rsc->mWorkers.mLaunchData, idx);
          }
-    LOGE("helperThreadProc 5");
          android_atomic_dec(&rsc->mWorkers.mRunningCount);
          rsc->mWorkers.mCompleteSignal.set();
      }
+
+     LOGV("RS helperThread exiting %p idx=%i", rsc, idx);
      return NULL;
 }
 
@@ -479,6 +479,10 @@
         LOGE("Failed to start rs context thread.");
         return;
     }
+    while(!mRunning) {
+        usleep(100);
+    }
+
     mWorkers.mRunningCount = 0;
     mWorkers.mLaunchCount = 0;
     for (uint32_t ct=0; ct < mWorkers.mCount; ct++) {
@@ -490,9 +494,6 @@
         }
     }
 
-    while(!mRunning) {
-        usleep(100);
-    }
 
     pthread_attr_destroy(&threadAttr);
 }
diff --git a/libs/rs/rsContext.h b/libs/rs/rsContext.h
index 98ad3a4..b8fffbf 100644
--- a/libs/rs/rsContext.h
+++ b/libs/rs/rsContext.h
@@ -174,6 +174,7 @@
     bool ext_OES_texture_npot() const {return mGL.OES_texture_npot;}
 
     void launchThreads(WorkerCallback_t cbk, void *data);
+    uint32_t getWorkerPoolSize() const {return (uint32_t)mWorkers.mRunningCount;}
 
 protected:
     Device *mDev;
diff --git a/libs/rs/rsScriptC.cpp b/libs/rs/rsScriptC.cpp
index 9693b16e..7c7b037 100644
--- a/libs/rs/rsScriptC.cpp
+++ b/libs/rs/rsScriptC.cpp
@@ -171,7 +171,6 @@
 static void wc_xy(void *usr, uint32_t idx)
 {
     MTLaunchStruct *mtls = (MTLaunchStruct *)usr;
-    LOGE("usr %p, idx %i", usr, idx);
 
     while (1) {
         uint32_t slice = (uint32_t)android_atomic_inc(&mtls->mSliceNum);
@@ -279,32 +278,32 @@
     }
 
 
-    {
-        LOGE("launch 1");
+    if ((rsc->getWorkerPoolSize() > 1) &&
+        ((mtls.dimY * mtls.dimZ * mtls.dimArray) > 1)) {
+
+        //LOGE("launch 1");
         rsc->launchThreads(wc_xy, &mtls);
-        LOGE("launch 2");
-    }
+        //LOGE("launch 2");
+    } else {
+        for (uint32_t ar = mtls.arrayStart; ar < mtls.arrayEnd; ar++) {
+            for (uint32_t z = mtls.zStart; z < mtls.zEnd; z++) {
+                for (uint32_t y = mtls.yStart; y < mtls.yEnd; y++) {
+                    uint32_t offset = mtls.dimX * mtls.dimY * mtls.dimZ * ar +
+                                      mtls.dimX * mtls.dimY * z +
+                                      mtls.dimX * y;
+                    uint8_t *xPtrOut = mtls.ptrOut + (mtls.eStrideOut * offset);
+                    const uint8_t *xPtrIn = mtls.ptrIn + (mtls.eStrideIn * offset);
 
-/*
-    for (uint32_t ar = arrayStart; ar < arrayEnd; ar++) {
-        for (uint32_t z = zStart; z < zEnd; z++) {
-            for (uint32_t y = yStart; y < yEnd; y++) {
-                uint32_t offset = dimX * dimY * dimZ * ar +
-                                  dimX * dimY * z +
-                                  dimX * y;
-                uint8_t *xPtrOut = ptrOut + (eStrideOut * offset);
-                const uint8_t *xPtrIn = ptrIn + (eStrideIn * offset);
-
-                for (uint32_t x = xStart; x < xEnd; x++) {
-                    ((rs_t)mProgram.mRoot) (xPtrIn, xPtrOut, usr, x, y, z, ar);
-                    xPtrIn += eStrideIn;
-                    xPtrOut += eStrideOut;
+                    for (uint32_t x = mtls.xStart; x < mtls.xEnd; x++) {
+                        ((rs_t)mProgram.mRoot) (xPtrIn, xPtrOut, usr, x, y, z, ar);
+                        xPtrIn += mtls.eStrideIn;
+                        xPtrOut += mtls.eStrideOut;
+                    }
                 }
             }
         }
-
     }
-*/
+
     setTLS(oldTLS);
 }
 
@@ -391,9 +390,16 @@
         bccGetExportFuncs(s->mBccScript, NULL, s->mEnviroment.mInvokeFunctionCount, (BCCvoid **) s->mEnviroment.mInvokeFunctions);
     }
 
-    s->mEnviroment.mFieldAddress = (void **)calloc(100, sizeof(void *));
-    bccGetExportVars(s->mBccScript, (BCCsizei *)&s->mEnviroment.mFieldCount,
-                     100, s->mEnviroment.mFieldAddress);
+    bccGetExportVars(s->mBccScript, (BCCsizei*) &s->mEnviroment.mFieldCount, 0, NULL);
+    if(s->mEnviroment.mFieldCount <= 0)
+        s->mEnviroment.mFieldAddress = NULL;
+    else {
+        s->mEnviroment.mFieldAddress = (void **) calloc(s->mEnviroment.mFieldCount, sizeof(void *));
+        bccGetExportVars(s->mBccScript, NULL, s->mEnviroment.mFieldCount, (BCCvoid **) s->mEnviroment.mFieldAddress);
+    }
+    //for (int ct2=0; ct2 < s->mEnviroment.mFieldCount; ct2++ ) {
+        //LOGE("Script field %i = %p", ct2, s->mEnviroment.mFieldAddress[ct2]);
+    //}
 
     s->mEnviroment.mFragment.set(rsc->getDefaultProgramFragment());
     s->mEnviroment.mVertex.set(rsc->getDefaultProgramVertex());