Merge "Documentation cleanup"
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index f20fd33..809acac 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -2708,7 +2708,12 @@
         // metadata is available.
         Intent upIntent = getParentActivityIntent();
         if (upIntent != null) {
-            if (shouldUpRecreateTask(upIntent)) {
+            if (mActivityInfo.taskAffinity == null) {
+                // Activities with a null affinity are special; they really shouldn't
+                // specify a parent activity intent in the first place. Just finish
+                // the current activity and call it a day.
+                finish();
+            } else if (shouldUpRecreateTask(upIntent)) {
                 TaskStackBuilder b = TaskStackBuilder.create(this);
                 onCreateNavigateUpTaskStack(b);
                 onPrepareNavigateUpTaskStack(b);
diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java
index 318c0ae..b6e606c 100644
--- a/core/java/android/os/PowerManager.java
+++ b/core/java/android/os/PowerManager.java
@@ -542,14 +542,18 @@
 
         private void acquireLocked() {
             if (!mRefCounted || mCount++ == 0) {
+                // Do this even if the wake lock is already thought to be held (mHeld == true)
+                // because non-reference counted wake locks are not always properly released.
+                // For example, the keyguard's wake lock might be forcibly released by the
+                // power manager without the keyguard knowing.  A subsequent call to acquire
+                // should immediately acquire the wake lock once again despite never having
+                // been explicitly released by the keyguard.
                 mHandler.removeCallbacks(mReleaser);
-                if (!mHeld) {
-                    try {
-                        mService.acquireWakeLock(mFlags, mToken, mTag, mWorkSource);
-                    } catch (RemoteException e) {
-                    }
-                    mHeld = true;
+                try {
+                    mService.acquireWakeLock(mFlags, mToken, mTag, mWorkSource);
+                } catch (RemoteException e) {
                 }
+                mHeld = true;
             }
         }
 
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 043d1d4..697f38e 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -6387,7 +6387,8 @@
             case IMPORTANT_FOR_ACCESSIBILITY_NO:
                 return false;
             case IMPORTANT_FOR_ACCESSIBILITY_AUTO:
-                return isActionableForAccessibility() || hasListenersForAccessibility();
+                return isActionableForAccessibility() || hasListenersForAccessibility()
+                        || getAccessibilityNodeProvider() != null;
             default:
                 throw new IllegalArgumentException("Unknow important for accessibility mode: "
                         + mode);
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index 8705d20..58f0b85 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -355,6 +355,9 @@
                 }
                 case MSG_BIND: {
                     final InputBindResult res = (InputBindResult)msg.obj;
+                    if (DEBUG) {
+                        Log.i(TAG, "handleMessage: MSG_BIND " + res.sequence + "," + res.id);
+                    }
                     synchronized (mH) {
                         if (mBindSequence < 0 || mBindSequence != res.sequence) {
                             Log.w(TAG, "Ignoring onBind: cur seq=" + mBindSequence
@@ -371,6 +374,9 @@
                 }
                 case MSG_UNBIND: {
                     final int sequence = msg.arg1;
+                    if (DEBUG) {
+                        Log.i(TAG, "handleMessage: MSG_UNBIND " + sequence);
+                    }
                     boolean startInput = false;
                     synchronized (mH) {
                         if (mBindSequence == sequence) {
@@ -403,6 +409,9 @@
                 }
                 case MSG_SET_ACTIVE: {
                     final boolean active = msg.arg1 != 0;
+                    if (DEBUG) {
+                        Log.i(TAG, "handleMessage: MSG_SET_ACTIVE " + active + ", was " + mActive);
+                    }
                     synchronized (mH) {
                         mActive = active;
                         mFullscreenMode = false;
@@ -420,7 +429,16 @@
                             // Check focus again in case that "onWindowFocus" is called before
                             // handling this message.
                             if (mServedView != null && mServedView.hasWindowFocus()) {
-                                checkFocus(mHasBeenInactive);
+                                // "finishComposingText" has been already called above. So we
+                                // should not call mServedInputConnection.finishComposingText here.
+                                // Also, please note that this handler thread could be different
+                                // from a thread that created mServedView. That could happen
+                                // the current activity is running in the system process.
+                                // In that case, we really should not call
+                                // mServedInputConnection.finishComposingText.
+                                if (checkFocusNoStartInput(mHasBeenInactive, false)) {
+                                    startInputInner(null, 0, 0, 0);
+                                }
                             }
                         }
                     }
@@ -1231,20 +1249,16 @@
         }
     }
 
-    private void checkFocus(boolean forceNewFocus) {
-        if (checkFocusNoStartInput(forceNewFocus)) {
-            startInputInner(null, 0, 0, 0);
-        }
-    }
-
     /**
      * @hide
      */
     public void checkFocus() {
-        checkFocus(false);
+        if (checkFocusNoStartInput(false, true)) {
+            startInputInner(null, 0, 0, 0);
+        }
     }
 
-    private boolean checkFocusNoStartInput(boolean forceNewFocus) {
+    private boolean checkFocusNoStartInput(boolean forceNewFocus, boolean finishComposingText) {
         // This is called a lot, so short-circuit before locking.
         if (mServedView == mNextServedView && !forceNewFocus) {
             return false;
@@ -1278,7 +1292,7 @@
             mServedConnecting = true;
         }
 
-        if (ic != null) {
+        if (finishComposingText && ic != null) {
             ic.finishComposingText();
         }
 
@@ -1323,7 +1337,7 @@
             controlFlags |= CONTROL_WINDOW_FIRST;
         }
         
-        if (checkFocusNoStartInput(forceNewFocus)) {
+        if (checkFocusNoStartInput(forceNewFocus, true)) {
             // We need to restart input on the current focus view.  This
             // should be done in conjunction with telling the system service
             // about the window gaining focus, to help make the transition
diff --git a/core/java/android/webkit/JWebCoreJavaBridge.java b/core/java/android/webkit/JWebCoreJavaBridge.java
index e6eaa14..d9aeb70 100644
--- a/core/java/android/webkit/JWebCoreJavaBridge.java
+++ b/core/java/android/webkit/JWebCoreJavaBridge.java
@@ -89,6 +89,7 @@
     private void fireSharedTimer() { 
         // clear the flag so that sharedTimerFired() can set a new timer
         mHasInstantTimer = false;
+        removeMessages(TIMER_MESSAGE);
         sharedTimerFired();
     }
 
diff --git a/core/java/android/webkit/WebSettingsClassic.java b/core/java/android/webkit/WebSettingsClassic.java
index 1288613..bd30464 100644
--- a/core/java/android/webkit/WebSettingsClassic.java
+++ b/core/java/android/webkit/WebSettingsClassic.java
@@ -34,7 +34,7 @@
  */
 public class WebSettingsClassic extends WebSettings {
     // TODO: Keep this up to date
-    private static final String PREVIOUS_VERSION = "4.0.4";
+    private static final String PREVIOUS_VERSION = "4.1.1";
 
     // WebView associated with this WebSettings.
     private WebViewClassic mWebView;
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 7691f00..ad25704 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -333,16 +333,12 @@
     @Deprecated
     public interface PictureListener {
         /**
-         * Notifies the listener that the picture has changed.
+         * Used to provide notification that the WebView's picture has changed.
+         * See {@link WebView#capturePicture} for details of the picture.
          *
          * @param view the WebView that owns the picture
          * @param picture the new picture
-         * @deprecated Due to internal changes, the picture does not include
-         *             composited layers such as fixed position elements or
-         *             scrollable divs. While the PictureListener API can still
-         *             be used to detect changes in the WebView content, you
-         *             are advised against its usage until a replacement is
-         *             provided in a future Android release.
+         * @deprecated Deprecated due to internal changes.
          */
         @Deprecated
         public void onNewPicture(WebView view, Picture picture);
@@ -987,13 +983,18 @@
     }
 
     /**
-     * Gets a new picture that captures the current display of this WebView.
-     * This is a copy of the display, and will be unaffected if this WebView
-     * later loads a different URL.
+     * Gets a new picture that captures the current contents of this WebView.
+     * The picture is of the entire document being displayed, and is not
+     * limited to the area currently displayed by this WebView. Also, the
+     * picture is a static copy and is unaffected by later changes to the
+     * content being displayed.
+     * <p>
+     * Note that due to internal changes, for API levels between
+     * {@link android.os.Build.VERSION_CODES#HONEYCOMB} and
+     * {@link android.os.Build.VERSION_CODES#ICE_CREAM_SANDWICH} inclusive, the
+     * picture does not include fixed position elements or scrollable divs.
      *
-     * @return a picture containing the current contents of this WebView. Note
-     *         this picture is of the entire document, and is not restricted to
-     *         the bounds of the view.
+     * @return a picture that captures the current contents of this WebView
      */
     public Picture capturePicture() {
         checkThread();
diff --git a/core/java/android/webkit/WebViewCore.java b/core/java/android/webkit/WebViewCore.java
index 40229af..59036e7 100644
--- a/core/java/android/webkit/WebViewCore.java
+++ b/core/java/android/webkit/WebViewCore.java
@@ -2197,12 +2197,20 @@
                 mEventHub.sendMessage(Message.obtain(null, EventHub.WEBKIT_DRAW));
             }
             m_skipDrawFlag = false;
+            m_skipDrawFlagLock.notify();
         }
     }
 
     private void webkitDraw() {
         synchronized (m_skipDrawFlagLock) {
             if (m_skipDrawFlag) {
+                try {
+                    // Aggressively throttle webkit to give the UI more CPU
+                    // to catch up with
+                    m_skipDrawFlagLock.wait(50);
+                } catch (InterruptedException e) {}
+            }
+            if (m_skipDrawFlag) {
                 m_drawWasSkipped = true;
                 return;
             }
diff --git a/core/java/com/android/internal/app/ResolverActivity.java b/core/java/com/android/internal/app/ResolverActivity.java
index 7334ac3..ff8a6d2 100644
--- a/core/java/com/android/internal/app/ResolverActivity.java
+++ b/core/java/com/android/internal/app/ResolverActivity.java
@@ -76,6 +76,7 @@
     private int mIconDpi;
     private int mIconSize;
     private int mMaxColumns;
+    private int mLastSelected = GridView.INVALID_POSITION;
 
     private boolean mRegistered;
     private final PackageMonitor mPackageMonitor = new PackageMonitor() {
@@ -247,6 +248,7 @@
         if (mAlwaysUseOption) {
             final int checkedPos = mGrid.getCheckedItemPosition();
             final boolean enabled = checkedPos != GridView.INVALID_POSITION;
+            mLastSelected = checkedPos;
             mAlwaysButton.setEnabled(enabled);
             mOnceButton.setEnabled(enabled);
             if (enabled) {
@@ -257,14 +259,15 @@
 
     @Override
     public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
-        if (mAlwaysUseOption) {
-            final int checkedPos = mGrid.getCheckedItemPosition();
-            final boolean enabled = checkedPos != GridView.INVALID_POSITION;
-            mAlwaysButton.setEnabled(enabled);
-            mOnceButton.setEnabled(enabled);
-            if (enabled) {
+        final int checkedPos = mGrid.getCheckedItemPosition();
+        final boolean hasValidSelection = checkedPos != GridView.INVALID_POSITION;
+        if (!hasValidSelection || (mAlwaysUseOption && mLastSelected != checkedPos)) {
+            mAlwaysButton.setEnabled(hasValidSelection);
+            mOnceButton.setEnabled(hasValidSelection);
+            if (hasValidSelection) {
                 mGrid.smoothScrollToPosition(checkedPos);
             }
+            mLastSelected = checkedPos;
         } else {
             startSelected(position, false);
         }
@@ -371,7 +374,8 @@
 
     void showAppDetails(ResolveInfo ri) {
         Intent in = new Intent().setAction("android.settings.APPLICATION_DETAILS_SETTINGS")
-                .setData(Uri.fromParts("package", ri.activityInfo.packageName, null));
+                .setData(Uri.fromParts("package", ri.activityInfo.packageName, null))
+                .addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
         startActivity(in);
     }
 
diff --git a/core/java/com/android/internal/net/VpnProfile.java b/core/java/com/android/internal/net/VpnProfile.java
new file mode 100644
index 0000000..154b16b
--- /dev/null
+++ b/core/java/com/android/internal/net/VpnProfile.java
@@ -0,0 +1,123 @@
+/*
+ * Copyright (C) 2011 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.internal.net;
+
+import java.nio.charset.Charsets;
+
+/**
+ * Parcel-like entity class for VPN profiles. To keep things simple, all
+ * fields are package private. Methods are provided for serialization, so
+ * storage can be implemented easily. Two rules are set for this class.
+ * First, all fields must be kept non-null. Second, always make a copy
+ * using clone() before modifying.
+ *
+ * @hide
+ */
+public class VpnProfile implements Cloneable {
+    // Match these constants with R.array.vpn_types.
+    public static final int TYPE_PPTP = 0;
+    public static final int TYPE_L2TP_IPSEC_PSK = 1;
+    public static final int TYPE_L2TP_IPSEC_RSA = 2;
+    public static final int TYPE_IPSEC_XAUTH_PSK = 3;
+    public static final int TYPE_IPSEC_XAUTH_RSA = 4;
+    public static final int TYPE_IPSEC_HYBRID_RSA = 5;
+    public static final int TYPE_MAX = 5;
+
+    // Entity fields.
+    public final String key;           // -1
+    public String name = "";           // 0
+    public int type = TYPE_PPTP;       // 1
+    public String server = "";         // 2
+    public String username = "";       // 3
+    public String password = "";       // 4
+    public String dnsServers = "";     // 5
+    public String searchDomains = "";  // 6
+    public String routes = "";         // 7
+    public boolean mppe = true;        // 8
+    public String l2tpSecret = "";     // 9
+    public String ipsecIdentifier = "";// 10
+    public String ipsecSecret = "";    // 11
+    public String ipsecUserCert = "";  // 12
+    public String ipsecCaCert = "";    // 13
+    public String ipsecServerCert = "";// 14
+
+    // Helper fields.
+    public boolean saveLogin = false;
+
+    public VpnProfile(String key) {
+        this.key = key;
+    }
+
+    public static VpnProfile decode(String key, byte[] value) {
+        try {
+            if (key == null) {
+                return null;
+            }
+
+            String[] values = new String(value, Charsets.UTF_8).split("\0", -1);
+            // There can be 14 or 15 values in ICS MR1.
+            if (values.length < 14 || values.length > 15) {
+                return null;
+            }
+
+            VpnProfile profile = new VpnProfile(key);
+            profile.name = values[0];
+            profile.type = Integer.valueOf(values[1]);
+            if (profile.type < 0 || profile.type > TYPE_MAX) {
+                return null;
+            }
+            profile.server = values[2];
+            profile.username = values[3];
+            profile.password = values[4];
+            profile.dnsServers = values[5];
+            profile.searchDomains = values[6];
+            profile.routes = values[7];
+            profile.mppe = Boolean.valueOf(values[8]);
+            profile.l2tpSecret = values[9];
+            profile.ipsecIdentifier = values[10];
+            profile.ipsecSecret = values[11];
+            profile.ipsecUserCert = values[12];
+            profile.ipsecCaCert = values[13];
+            profile.ipsecServerCert = (values.length > 14) ? values[14] : "";
+
+            profile.saveLogin = !profile.username.isEmpty() || !profile.password.isEmpty();
+            return profile;
+        } catch (Exception e) {
+            // ignore
+        }
+        return null;
+    }
+
+    public byte[] encode() {
+        StringBuilder builder = new StringBuilder(name);
+        builder.append('\0').append(type);
+        builder.append('\0').append(server);
+        builder.append('\0').append(saveLogin ? username : "");
+        builder.append('\0').append(saveLogin ? password : "");
+        builder.append('\0').append(dnsServers);
+        builder.append('\0').append(searchDomains);
+        builder.append('\0').append(routes);
+        builder.append('\0').append(mppe);
+        builder.append('\0').append(l2tpSecret);
+        builder.append('\0').append(ipsecIdentifier);
+        builder.append('\0').append(ipsecSecret);
+        builder.append('\0').append(ipsecUserCert);
+        builder.append('\0').append(ipsecCaCert);
+        builder.append('\0').append(ipsecServerCert);
+        return builder.toString().getBytes(Charsets.UTF_8);
+    }
+}
diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml
index 6763ed7..e6e85ed 100644
--- a/core/res/res/values-en-rGB/strings.xml
+++ b/core/res/res/values-en-rGB/strings.xml
@@ -1294,7 +1294,7 @@
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"Always"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"Just once"</string>
     <string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"Tablet"</string>
-    <string name="default_audio_route_name" product="default" msgid="4239291273420140123">"Phones"</string>
+    <string name="default_audio_route_name" product="default" msgid="4239291273420140123">"Phone"</string>
     <string name="default_audio_route_name_headphones" msgid="8119971843803439110">"Headphones"</string>
     <string name="default_audio_route_name_dock_speakers" msgid="6240602982276591864">"Dock speakers"</string>
     <string name="default_audio_route_name_hdmi" msgid="7986404173839007682">"HDMI audio"</string>
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index 941d5c3..a6fda3b 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -44,7 +44,7 @@
     <string name="passwordIncorrect" msgid="7612208839450128715">"رمز ورود اشتباه است."</string>
     <string name="mmiComplete" msgid="8232527495411698359">"MMI کامل شد."</string>
     <string name="badPin" msgid="9015277645546710014">"پین قدیمی که نوشته‎اید صحیح نیست."</string>
-    <string name="badPuk" msgid="5487257647081132201">"PUK که نوشته اید صحیح نیست."</string>
+    <string name="badPuk" msgid="5487257647081132201">"PUK که نوشته‌اید صحیح نیست."</string>
     <string name="mismatchPin" msgid="609379054496863419">"پین‎هایی که وارد کرده‎اید با یکدیگر مطابقت ندارند."</string>
     <string name="invalidPin" msgid="3850018445187475377">"یک پین بنویسید که 4 تا 8 رقم باشد."</string>
     <string name="invalidPuk" msgid="8761456210898036513">"یک PUK با 8 رقم یا بیشتر تایپ کنید."</string>
@@ -147,7 +147,7 @@
     <string name="shutdown_confirm" product="default" msgid="649792175242821353">"گوشی شما خاموش می‌شود."</string>
     <string name="shutdown_confirm_question" msgid="2906544768881136183">"آیا می‎خواهید تلفن خاموش شود؟"</string>
     <string name="reboot_safemode_title" msgid="7054509914500140361">"راه‌اندازی مجدد در حالت امن"</string>
-    <string name="reboot_safemode_confirm" msgid="55293944502784668">"آیا می‌خواهید با حالت امن راه‌اندازی مجدد کنید؟ با این کار کلیه برنامه‌های شخص ثالثی که نصب کرده‌اید غیرفعال می‌شوند. با راه‌اندازی دوباره سیستم این برنامه‌ها دوباره بازیابی می‌شوند."</string>
+    <string name="reboot_safemode_confirm" msgid="55293944502784668">"آیا می‌خواهید با حالت امن راه‌اندازی مجدد کنید؟ با این کار همهٔ برنامه‌های شخص ثالثی که نصب کرده‌اید غیرفعال می‌شوند. با راه‌اندازی دوباره سیستم این برنامه‌ها دوباره بازیابی می‌شوند."</string>
     <string name="recent_tasks_title" msgid="3691764623638127888">"اخیر"</string>
     <string name="no_recent_tasks" msgid="8794906658732193473">"برنامه‎های جدید موجود نیست."</string>
     <string name="global_actions" product="tablet" msgid="408477140088053665">"گزینه‌های رایانه لوحی"</string>
@@ -563,7 +563,7 @@
     <string name="policylab_setGlobalProxy" msgid="2784828293747791446">"تنظیم پروکسی جهانی دستگاه"</string>
     <string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"پروکسی جهانی دستگاه مورد نظر را جهت استفاده هنگام فعال بودن خط مشی تنظیم کنید. فقط اولین سرپرست دستگاه پروکسی جهانی مفید را تنظیم می‌کند."</string>
     <string name="policylab_expirePassword" msgid="885279151847254056">"تنظیم زمان انقضای رمز ورود قفل صفحه"</string>
-    <string name="policydesc_expirePassword" msgid="1729725226314691591">"کنترل کنید چند وقت یکبار باید گذرواژه صفحه قفل عوض شود."</string>
+    <string name="policydesc_expirePassword" msgid="1729725226314691591">"کنترل کنید چند وقت یک بار باید گذرواژه صفحه قفل عوض شود."</string>
     <string name="policylab_encryptedStorage" msgid="8901326199909132915">"تنظیم رمزگذاری حافظه"</string>
     <string name="policydesc_encryptedStorage" msgid="2637732115325316992">"باید اطلاعات ذخیره شده برنامه رمزگذاری شود."</string>
     <string name="policylab_disableCamera" msgid="6395301023152297826">"غیر فعال کردن دوربین ها"</string>
@@ -728,7 +728,7 @@
     <string name="lockscreen_too_many_failed_password_attempts_dialog_message" msgid="2725973286239344555">"گذرواژه خود را <xliff:g id="NUMBER_0">%d</xliff:g> بار اشتباه تایپ کرده‌اید. "\n\n"پس از <xliff:g id="NUMBER_1">%d</xliff:g> ثانیه دوباره امتحان کنید."</string>
     <string name="lockscreen_too_many_failed_pin_attempts_dialog_message" msgid="6216672706545696955">"پین را<xliff:g id="NUMBER_0">%d</xliff:g>  بار اشتباه تایپ کرده‎اید. "\n\n"پس از <xliff:g id="NUMBER_1">%d</xliff:g> ثانیه دوباره امتحان کنید."</string>
     <string name="lockscreen_failed_attempts_almost_glogin" product="tablet" msgid="9191611984625460820">"شما الگوی بازگشایی قفل خود را <xliff:g id="NUMBER_0">%d</xliff:g> بار اشتباه کشیده‎اید. بعد از <xliff:g id="NUMBER_1">%d</xliff:g> تلاش ناموفق، از شما خواسته می‎شود که برای بازگشایی قفل رایانه لوحی خود به Google وارد شوید."\n\n" لطفاً پس از <xliff:g id="NUMBER_2">%d</xliff:g> ثانیه دوباره امتحان کنید."</string>
-    <string name="lockscreen_failed_attempts_almost_glogin" product="default" msgid="2590227559763762751">"شما الگوی بازگشایی قفل خود را <xliff:g id="NUMBER_0">%d</xliff:g> بار اشتباه کشیده اید. پس از <xliff:g id="NUMBER_1">%d</xliff:g> تلاش ناموفق دیگر از شما خواسته می‎شود که برای بازگشایی قفل گوشی خود به برنامه Google وارد شوید."\n\n" لطفاً پس از <xliff:g id="NUMBER_2">%d</xliff:g> ثانیه دوباره امتحان کنید."</string>
+    <string name="lockscreen_failed_attempts_almost_glogin" product="default" msgid="2590227559763762751">"شما الگوی بازگشایی قفل خود را <xliff:g id="NUMBER_0">%d</xliff:g> بار اشتباه کشیده‌اید. پس از <xliff:g id="NUMBER_1">%d</xliff:g> تلاش ناموفق دیگر از شما خواسته می‎شود که برای بازگشایی قفل گوشی خود به برنامه Google وارد شوید."\n\n" لطفاً پس از <xliff:g id="NUMBER_2">%d</xliff:g> ثانیه دوباره امتحان کنید."</string>
     <string name="lockscreen_failed_attempts_almost_at_wipe" product="tablet" msgid="6128106399745755604">"شما به اشتباه <xliff:g id="NUMBER_0">%d</xliff:g> بار اقدام به باز کردن قفل رایانه لوحی کرده‌اید. پس از <xliff:g id="NUMBER_1">%d</xliff:g> تلاش ناموفق دیگر، رایانه لوحی به پیش‌فرض کارخانه بازنشانی می‌شود و تمام داده‌های کاربر از دست خواهد رفت."</string>
     <string name="lockscreen_failed_attempts_almost_at_wipe" product="default" msgid="8603565142156826565">"شما به اشتباه <xliff:g id="NUMBER_0">%d</xliff:g> بار اقدام به باز کردن قفل تلفن کرده‌اید. پس از<xliff:g id="NUMBER_1">%d</xliff:g> تلاش ناموفق دیگر، تلفن به پیش‌فرض کارخانه بازنشانی می‌شود و تمام داده‌های کاربر از دست خواهد رفت."</string>
     <string name="lockscreen_failed_attempts_now_wiping" product="tablet" msgid="280873516493934365">"شما به اشتباه اقدام به باز کردن قفل <xliff:g id="NUMBER">%d</xliff:g> رایانه لوحی کرده‌اید. رایانه لوحی در حال حاضر به پیش‌فرض کارخانه بازنشانی می‌شود."</string>
@@ -762,7 +762,7 @@
     <string name="hour_cap_ampm" msgid="2083465992940444366">"<xliff:g id="HOUR">%-l</xliff:g><xliff:g id="AMPM">%p</xliff:g>"</string>
     <string name="factorytest_failed" msgid="5410270329114212041">"تست کارخانه انجام نشد"</string>
     <string name="factorytest_not_system" msgid="4435201656767276723">"عملکرد FACTORY_TEST تنها برای بسته‌های نصب شده در /system/app پشتیبانی می‌شود."</string>
-    <string name="factorytest_no_action" msgid="872991874799998561">"بسته ای یافت نشد که عملکرد FACTORY_TEST را ارائه کند."</string>
+    <string name="factorytest_no_action" msgid="872991874799998561">"بسته‌ای یافت نشد که عملکرد FACTORY_TEST را ارائه کند."</string>
     <string name="factorytest_reboot" msgid="6320168203050791643">"راه اندازی مجدد"</string>
     <string name="js_dialog_title" msgid="1987483977834603872">"صفحه در \"<xliff:g id="TITLE">%s</xliff:g>\" می‎گوید:"</string>
     <string name="js_dialog_title_default" msgid="6961903213729667573">"جاوا اسکریپت"</string>
@@ -1080,7 +1080,7 @@
     <string name="dlg_confirm_kill_storage_users_text" msgid="5100428757107469454">"در صورت فعال کردن حافظهٔ USB، برخی از برنامه‎هایی که از آن‌ها استفاده می‎کنید متوقف می‎شوند و تا زمانی که حافظهٔ USB را غیرفعال نکنید امکان استفاده از آن‌ها وجود نخواهد داشت."</string>
     <string name="dlg_error_title" msgid="7323658469626514207">"راه‌اندازی USB ناموفق بود."</string>
     <string name="dlg_ok" msgid="7376953167039865701">"تأیید"</string>
-    <string name="usb_mtp_notification_title" msgid="3699913097391550394">"متصل شده به عنوان دستگاه رسانه ای"</string>
+    <string name="usb_mtp_notification_title" msgid="3699913097391550394">"متصل شده به عنوان دستگاه رسانه‌ای"</string>
     <string name="usb_ptp_notification_title" msgid="1960817192216064833">"متصل شده به عنوان دوربین"</string>
     <string name="usb_cd_installer_notification_title" msgid="6774712827892090754">"متصل شده به عنوان نصب کننده"</string>
     <string name="usb_accessory_notification_title" msgid="7848236974087653666">"به یک وسیله جانبی USB وصل شده است"</string>
@@ -1112,8 +1112,8 @@
     <string name="ext_media_unmountable_notification_title" product="default" msgid="6410723906019100189">"کارت SD آسیب دیده"</string>
     <string name="ext_media_unmountable_notification_message" product="nosdcard" msgid="1795917578395333280">"حافظهٔ USB خراب است. سعی کنید آنرا دوباره فرمت کنید."</string>
     <string name="ext_media_unmountable_notification_message" product="default" msgid="1753898567525568253">"کارت SD خراب است. سعی کنید آنرا دوباره فرمت کنید."</string>
-    <string name="ext_media_badremoval_notification_title" product="nosdcard" msgid="1661683031330951073">"حافظهٔ USB به صورت غیر منتظره جدا شد"</string>
-    <string name="ext_media_badremoval_notification_title" product="default" msgid="6872152882604407837">"کارت SD به صورت غیر منتظره ای جدا شد"</string>
+    <string name="ext_media_badremoval_notification_title" product="nosdcard" msgid="1661683031330951073">"حافظهٔ USB به صورت غیرمنتظره جدا شد"</string>
+    <string name="ext_media_badremoval_notification_title" product="default" msgid="6872152882604407837">"کارت SD به صورت غیرمنتظره‌ای جدا شد"</string>
     <string name="ext_media_badremoval_notification_message" product="nosdcard" msgid="4329848819865594241">"اتصال حافظهٔ USB را قبل از بیرون آوردن قطع کنید تا سبب از بین رفتن داده‌ها نشود."</string>
     <string name="ext_media_badremoval_notification_message" product="default" msgid="7260183293747448241">"کارت SD را قبل از بیرون آوردن جدا کنید تا سبب از بین رفتن داده‌ها نشود."</string>
     <string name="ext_media_safe_unmount_notification_title" product="nosdcard" msgid="3967973893270360230">"حافظهٔ USB را می‌توانید با ایمنی جدا کنید"</string>
diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml
index 43e22da..76c791d 100644
--- a/core/res/res/values-sw/strings.xml
+++ b/core/res/res/values-sw/strings.xml
@@ -474,8 +474,8 @@
     <string name="permlab_getAccounts" msgid="1086795467760122114">"pata akaunti kwenye kifaa"</string>
     <string name="permdesc_getAccounts" product="tablet" msgid="2741496534769660027">"Inaruhusu programu kupata orodha ya akaunti zinazojulikana kwa kompyuta kibao. Hii inaweza kujumuisha akaunti zozote zilizoundwa na programu ambazo umesakinisha."</string>
     <string name="permdesc_getAccounts" product="default" msgid="3448316822451807382">"Inaruhusu programu kupata orodha ya akaunti zinazojulikana kwa simu. Hii inaweza kujumuisha akaunti zozote zilizoundwa na programu ambazo umesakinisha."</string>
-    <string name="permlab_authenticateAccounts" msgid="5265908481172736933">"unda akaunti na weka manenosiri"</string>
-    <string name="permdesc_authenticateAccounts" msgid="5472124296908977260">"Inaruhusu programu kutumia uwezo wa uthibitishaji akaunti wa KidhibitiAkaunti, pamoja na kuunda akaunti na kupata na kuweka nywila zao."</string>
+    <string name="permlab_authenticateAccounts" msgid="5265908481172736933">"fungua akaunti na weka manenosiri"</string>
+    <string name="permdesc_authenticateAccounts" msgid="5472124296908977260">"Inaruhusu programu kutumia uwezo wa uthibitishaji akaunti wa KidhibitiAkaunti, ikiwa ni pamoja na kufungua akaunti na kupata na kuweka manenosiri ya akaunti hizo."</string>
     <string name="permlab_manageAccounts" msgid="4983126304757177305">"ongeza au uondoe akaunti"</string>
     <string name="permdesc_manageAccounts" msgid="8698295625488292506">"Inaruhusu programu kutekeleza shughuli kama vile kuongeza na kutoa akaunti, na kufuta manenosiri yazo."</string>
     <string name="permlab_useCredentials" msgid="235481396163877642">"tumia akaunti kwenye kifaa"</string>
@@ -741,7 +741,7 @@
     <string name="lockscreen_glogin_username_hint" msgid="8846881424106484447">"Jina la mtumiaji (barua pepe)"</string>
     <string name="lockscreen_glogin_password_hint" msgid="5958028383954738528">"Nenosiri"</string>
     <string name="lockscreen_glogin_submit_button" msgid="7130893694795786300">"Ingia"</string>
-    <string name="lockscreen_glogin_invalid_input" msgid="1364051473347485908">"Jina batili la mtumiaji au nywila"</string>
+    <string name="lockscreen_glogin_invalid_input" msgid="1364051473347485908">"Jina la mtumiaji au nenosiri batili."</string>
     <string name="lockscreen_glogin_account_recovery_hint" msgid="1696924763690379073">"Umesahau jina lako la mtumiaji au nenosiri?"\n"Tembela "<b>"google.com/accounts/recovery"</b>"."</string>
     <string name="lockscreen_glogin_checking_password" msgid="7114627351286933867">"Inakagua..."</string>
     <string name="lockscreen_unlock_label" msgid="737440483220667054">"Fungua"</string>
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index c7fc993..12f80da 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -243,14 +243,10 @@
     <string name="permdesc_dump" msgid="1778299088692290329">"允许应用检索系统的内部状态。恶意应用可能会检索一般情况下绝不需要检索的多种私人信息和安全信息。"</string>
     <string name="permlab_retrieve_window_content" msgid="8022588608994589938">"检索屏幕内容"</string>
     <string name="permdesc_retrieve_window_content" msgid="3193269069469700265">"允许应用检索活动窗口的内容。恶意应用可能会检索整个窗口的内容,并检查其中除密码以外的所有文字。"</string>
-    <!-- no translation found for permlab_retrieve_window_info (8532295199112519378) -->
-    <skip />
-    <!-- no translation found for permdesc_retrieve_window_info (4998836370424186849) -->
-    <skip />
-    <!-- no translation found for permlab_filter_events (8675535648807427389) -->
-    <skip />
-    <!-- no translation found for permdesc_filter_events (8006236315888347680) -->
-    <skip />
+    <string name="permlab_retrieve_window_info" msgid="8532295199112519378">"检索窗口信息"</string>
+    <string name="permdesc_retrieve_window_info" msgid="4998836370424186849">"允许应用通过窗口管理器检索窗口信息。恶意应用可能会检索供内部系统使用的信息。"</string>
+    <string name="permlab_filter_events" msgid="8675535648807427389">"过滤活动"</string>
+    <string name="permdesc_filter_events" msgid="8006236315888347680">"允许应用注册输入过滤器,这类过滤器会在所有用户活动分派之前对这些用户活动的信息流进行过滤。恶意应用可能会在没有用户干预的情况下控制系统用户界面。"</string>
     <string name="permlab_shutdown" msgid="7185747824038909016">"部分关机"</string>
     <string name="permdesc_shutdown" msgid="7046500838746291775">"使活动管理器进入关闭状态。不执行彻底关机。"</string>
     <string name="permlab_stopAppSwitches" msgid="4138608610717425573">"禁止切换应用"</string>
diff --git a/docs/html/index.jd b/docs/html/index.jd
index 8930c7f..1d47ed7 100644
--- a/docs/html/index.jd
+++ b/docs/html/index.jd
@@ -43,11 +43,11 @@
                         <img src="{@docRoot}images/home/google-io.png">
                         </div>
                         <div class="content-right col-5">
-                        <h1>Watch Android at <br/>Google I/O!</h1>
-                        <p>See the keynote and more than 40 Android developer sessions streamed live from Moscone Center in San Francisco.</p>
-                        <p>Begins June 27, 9AM PDT (UTC-7).</p>
-                        <p><a href="https://developers.google.com/events/io/sessions#android"
-class="button">See the Android Sessions</a></p>
+                        <h1>Android videos<br/> from Google I/O!</h1>
+                        <p>If you couldn't make it to Google I/O this year or want to review some of the material,
+                          all of the Android sessions are now available for viewing online.</p>
+                        <p><a href="http://www.youtube.com/playlist?list=PL4C6BCDE45E05F49E&feature=plcp"
+class="button">Watch the Android sessions</a></p>
                         </div>
                 </li>
                 <li class="item carousel-home">
@@ -68,7 +68,6 @@
     <!-- /End slideshow -->
     
     
-    
 </div>
 <div class="wrap" style="padding-bottom:20px">
     <!-- Section links -->
diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java b/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java
index 0bdf84a..cb69660 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java
@@ -21,6 +21,7 @@
 import android.app.ActivityManager;
 import android.app.ActivityManagerNative;
 import android.app.ActivityOptions;
+import android.app.TaskStackBuilder;
 import android.content.Context;
 import android.content.Intent;
 import android.content.res.Configuration;
@@ -845,8 +846,9 @@
     private void startApplicationDetailsActivity(String packageName) {
         Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS,
                 Uri.fromParts("package", packageName, null));
-        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-        getContext().startActivity(intent);
+        intent.setComponent(intent.resolveActivity(mContext.getPackageManager()));
+        TaskStackBuilder.create(getContext())
+                .addNextIntentWithParentStack(intent).startActivities();
     }
 
     public boolean onInterceptTouchEvent(MotionEvent ev) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
index bd8be1f..b392648 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
@@ -16,9 +16,24 @@
 
 package com.android.systemui.statusbar;
 
+import com.android.internal.statusbar.IStatusBarService;
+import com.android.internal.statusbar.StatusBarIcon;
+import com.android.internal.statusbar.StatusBarIconList;
+import com.android.internal.statusbar.StatusBarNotification;
+import com.android.internal.widget.SizeAdaptiveLayout;
+import com.android.systemui.R;
+import com.android.systemui.SearchPanelView;
+import com.android.systemui.SystemUI;
+import com.android.systemui.recent.RecentTasksLoader;
+import com.android.systemui.recent.RecentsPanelView;
+import com.android.systemui.recent.TaskDescription;
+import com.android.systemui.statusbar.policy.NotificationRowLayout;
+import com.android.systemui.statusbar.tablet.StatusBarPanel;
+
 import android.app.ActivityManagerNative;
 import android.app.KeyguardManager;
 import android.app.PendingIntent;
+import android.app.TaskStackBuilder;
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.ApplicationInfo;
@@ -51,22 +66,6 @@
 import android.widget.PopupMenu;
 import android.widget.RemoteViews;
 
-import com.android.internal.statusbar.IStatusBarService;
-import com.android.internal.statusbar.StatusBarIcon;
-import com.android.internal.statusbar.StatusBarIconList;
-import com.android.internal.statusbar.StatusBarNotification;
-import com.android.internal.widget.SizeAdaptiveLayout;
-import com.android.systemui.R;
-import com.android.systemui.SearchPanelView;
-import com.android.systemui.SystemUI;
-import com.android.systemui.recent.RecentTasksLoader;
-import com.android.systemui.recent.RecentsPanelView;
-import com.android.systemui.recent.TaskDescription;
-import com.android.systemui.statusbar.CommandQueue;
-import com.android.systemui.statusbar.NotificationData.Entry;
-import com.android.systemui.statusbar.policy.NotificationRowLayout;
-import com.android.systemui.statusbar.tablet.StatusBarPanel;
-
 import java.util.ArrayList;
 
 public abstract class BaseStatusBar extends SystemUI implements
@@ -299,8 +298,8 @@
     private void startApplicationDetailsActivity(String packageName) {
         Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS,
                 Uri.fromParts("package", packageName, null));
-        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-        mContext.startActivity(intent);
+        intent.setComponent(intent.resolveActivity(mContext.getPackageManager()));
+        TaskStackBuilder.create(mContext).addNextIntentWithParentStack(intent).startActivities();
     }
 
     protected View.OnLongClickListener getNotificationLongClicker() {
diff --git a/tests/RenderScriptTests/ImageProcessing/res/layout/main.xml b/tests/RenderScriptTests/ImageProcessing/res/layout/main.xml
index 08a010d..bd56d62 100644
--- a/tests/RenderScriptTests/ImageProcessing/res/layout/main.xml
+++ b/tests/RenderScriptTests/ImageProcessing/res/layout/main.xml
@@ -50,8 +50,12 @@
                         android:textSize="8pt"
                         android:text="@string/saturation"/>
             </LinearLayout>
+            <Spinner
+                android:id="@+id/filterselection"
+                android:layout_width="fill_parent"
+                android:layout_height="wrap_content"/>
             <TextView
-                android:id="@+id/inSaturationText"
+                android:id="@+id/slider1Text"
                 android:layout_width="match_parent"
                 android:layout_height="wrap_content"
                 android:textSize="8pt"
@@ -59,13 +63,13 @@
                 android:layout_marginTop="15sp"
                 android:text="@string/saturation"/>
              <SeekBar
-                android:id="@+id/inSaturation"
+                android:id="@+id/slider1"
                 android:layout_marginLeft="10sp"
                 android:layout_marginRight="10sp"
                 android:layout_width="match_parent"
                 android:layout_height="wrap_content"/>
             <TextView
-                android:id="@+id/inGammaText"
+                android:id="@+id/slider2Text"
                 android:layout_width="match_parent"
                 android:layout_height="wrap_content"
                 android:textSize="8pt"
@@ -73,13 +77,13 @@
                 android:layout_marginTop="15sp"
                 android:text="@string/gamma"/>
             <SeekBar
-                android:id="@+id/inGamma"
+                android:id="@+id/slider2"
                 android:layout_marginLeft="10sp"
                 android:layout_marginRight="10sp"
                 android:layout_width="match_parent"
                 android:layout_height="wrap_content"/>
             <TextView
-                android:id="@+id/outWhiteText"
+                android:id="@+id/slider3Text"
                 android:layout_width="match_parent"
                 android:layout_height="wrap_content"
                 android:layout_marginLeft="10sp"
@@ -87,13 +91,13 @@
                 android:textSize="8pt"
                 android:text="@string/out_white"/>
             <SeekBar
-                android:id="@+id/outWhite"
+                android:id="@+id/slider3"
                 android:layout_marginLeft="10sp"
                 android:layout_marginRight="10sp"
                 android:layout_width="match_parent"
                 android:layout_height="wrap_content"/>
             <TextView
-                android:id="@+id/inWhiteText"
+                android:id="@+id/slider4Text"
                 android:layout_width="match_parent"
                 android:layout_height="wrap_content"
                 android:textSize="8pt"
@@ -101,49 +105,21 @@
                 android:layout_marginTop="15sp"
                 android:text="@string/in_white"/>
             <SeekBar
-                android:id="@+id/inWhite"
+                android:id="@+id/slider4"
                 android:layout_marginLeft="10sp"
                 android:layout_marginRight="10sp"
                 android:layout_width="match_parent"
                 android:layout_height="wrap_content"/>
             <TextView
-                android:id="@+id/outBlackText"
+                android:id="@+id/slider5Text"
                 android:layout_width="match_parent"
                 android:layout_height="wrap_content"
                 android:textSize="8pt"
                 android:layout_marginLeft="10sp"
                 android:layout_marginTop="15sp"
-                android:text="@string/out_black"/>
+                android:text="@string/in_white"/>
             <SeekBar
-                android:id="@+id/outBlack"
-                android:layout_marginLeft="10sp"
-                android:layout_marginRight="10sp"
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"/>
-            <TextView
-                android:id="@+id/inBlackText"
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                android:textSize="8pt"
-                android:layout_marginLeft="10sp"
-                android:layout_marginTop="15sp"
-                android:text="@string/in_black"/>
-            <SeekBar
-                android:id="@+id/inBlack"
-                android:layout_marginLeft="10sp"
-                android:layout_marginRight="10sp"
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"/>
-            <TextView
-                android:id="@+id/blurText"
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                android:textSize="8pt"
-                 android:layout_marginLeft="10sp"
-                android:layout_marginTop="15sp"
-                android:text="@string/blur_description"/>
-            <SeekBar
-                android:id="@+id/radius"
+                android:id="@+id/slider5"
                 android:layout_marginLeft="10sp"
                 android:layout_marginRight="10sp"
                 android:layout_width="match_parent"
diff --git a/tests/RenderScriptTests/ImageProcessing/res/layout/spinner_layout.xml b/tests/RenderScriptTests/ImageProcessing/res/layout/spinner_layout.xml
new file mode 100644
index 0000000..8196bbf
--- /dev/null
+++ b/tests/RenderScriptTests/ImageProcessing/res/layout/spinner_layout.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!-- Copyright (C) 2012 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.
+-->
+
+<TextView xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="fill_parent"
+    android:layout_height="fill_parent"
+    android:padding="10dp"
+    android:textSize="16sp"
+/>
diff --git a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/Blur25.java b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/Blur25.java
new file mode 100644
index 0000000..697bbb1
--- /dev/null
+++ b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/Blur25.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2012 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 java.lang.Math;
+
+import android.renderscript.Allocation;
+import android.renderscript.Element;
+import android.renderscript.RenderScript;
+import android.renderscript.Script;
+import android.renderscript.ScriptC;
+import android.renderscript.Type;
+import android.util.Log;
+import android.widget.SeekBar;
+import android.widget.TextView;
+
+public class Blur25 extends TestBase {
+    private int MAX_RADIUS = 25;
+    private ScriptC_threshold mScript;
+    private ScriptC_vertical_blur mScriptVBlur;
+    private ScriptC_horizontal_blur mScriptHBlur;
+    private int mRadius = MAX_RADIUS;
+    private float mSaturation = 1.0f;
+    private Allocation mScratchPixelsAllocation1;
+    private Allocation mScratchPixelsAllocation2;
+
+
+    public boolean onBar1Setup(SeekBar b, TextView t) {
+        t.setText("Radius");
+        b.setProgress(100);
+        return true;
+    }
+    public boolean onBar2Setup(SeekBar b, TextView t) {
+        b.setProgress(50);
+        t.setText("Saturation");
+        return true;
+    }
+
+
+    public void onBar1Changed(int progress) {
+        float fRadius = progress / 100.0f;
+        fRadius *= (float)(MAX_RADIUS);
+        mRadius = (int)fRadius;
+        mScript.set_radius(mRadius);
+    }
+    public void onBar2Changed(int progress) {
+        mSaturation = (float)progress / 50.0f;
+        mScriptVBlur.invoke_setSaturation(mSaturation);
+    }
+
+
+    public void createTest(android.content.res.Resources res) {
+        int width = mInPixelsAllocation.getType().getX();
+        int height = mInPixelsAllocation.getType().getY();
+
+        Type.Builder tb = new Type.Builder(mRS, Element.F32_4(mRS));
+        tb.setX(width);
+        tb.setY(height);
+        mScratchPixelsAllocation1 = Allocation.createTyped(mRS, tb.create());
+        mScratchPixelsAllocation2 = Allocation.createTyped(mRS, tb.create());
+
+        mScriptVBlur = new ScriptC_vertical_blur(mRS, res, R.raw.vertical_blur);
+        mScriptHBlur = new ScriptC_horizontal_blur(mRS, res, R.raw.horizontal_blur);
+
+        mScript = new ScriptC_threshold(mRS, res, R.raw.threshold);
+        mScript.set_width(width);
+        mScript.set_height(height);
+        mScript.set_radius(mRadius);
+
+        mScriptVBlur.invoke_setSaturation(mSaturation);
+
+        mScript.bind_InPixel(mInPixelsAllocation);
+        mScript.bind_OutPixel(mOutPixelsAllocation);
+        mScript.bind_ScratchPixel1(mScratchPixelsAllocation1);
+        mScript.bind_ScratchPixel2(mScratchPixelsAllocation2);
+
+        mScript.set_vBlurScript(mScriptVBlur);
+        mScript.set_hBlurScript(mScriptHBlur);
+    }
+
+    public void runTest() {
+        mScript.invoke_filter();
+    }
+
+    public void setupBenchmark() {
+        mScript.set_radius(MAX_RADIUS);
+    }
+
+    public void exitBenchmark() {
+        mScript.set_radius(mRadius);
+    }
+}
diff --git a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/Greyscale.java b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/Greyscale.java
new file mode 100644
index 0000000..3db210a
--- /dev/null
+++ b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/Greyscale.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2012 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 java.lang.Math;
+
+import android.renderscript.Allocation;
+import android.renderscript.Element;
+import android.renderscript.RenderScript;
+import android.renderscript.Script;
+import android.renderscript.ScriptC;
+import android.renderscript.Type;
+import android.util.Log;
+
+public class Greyscale extends TestBase {
+    private ScriptC_greyscale mScript;
+
+    public void createTest(android.content.res.Resources res) {
+        mScript = new ScriptC_greyscale(mRS, res, R.raw.greyscale);
+    }
+
+    public void runTest() {
+        mScript.forEach_root(mInPixelsAllocation, mOutPixelsAllocation);
+    }
+
+}
diff --git a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/ImageProcessingActivity.java b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/ImageProcessingActivity.java
index 7368260..e085582 100644
--- a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/ImageProcessingActivity.java
+++ b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/ImageProcessingActivity.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2009 The Android Open Source Project
+ * Copyright (C) 2012 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.
@@ -29,124 +29,65 @@
 import android.renderscript.Script;
 import android.view.SurfaceView;
 import android.view.SurfaceHolder;
+import android.widget.AdapterView;
+import android.widget.ArrayAdapter;
 import android.widget.ImageView;
 import android.widget.SeekBar;
+import android.widget.Spinner;
 import android.widget.TextView;
 import android.view.View;
 import android.util.Log;
 import java.lang.Math;
 
 public class ImageProcessingActivity extends Activity
-                                       implements SurfaceHolder.Callback,
-                                       SeekBar.OnSeekBarChangeListener {
+                                       implements SeekBar.OnSeekBarChangeListener {
     private final String TAG = "Img";
-    private Bitmap mBitmapIn;
-    private Bitmap mBitmapOut;
-    private ScriptC_threshold mScript;
-    private ScriptC_vertical_blur mScriptVBlur;
-    private ScriptC_horizontal_blur mScriptHBlur;
-    private int mRadius = 0;
-    private SeekBar mRadiusSeekBar;
+    Bitmap mBitmapIn;
+    Bitmap mBitmapOut;
+    String mTestNames[];
 
-    private float mInBlack = 0.0f;
-    private SeekBar mInBlackSeekBar;
-    private float mOutBlack = 0.0f;
-    private SeekBar mOutBlackSeekBar;
-    private float mInWhite = 255.0f;
-    private SeekBar mInWhiteSeekBar;
-    private float mOutWhite = 255.0f;
-    private SeekBar mOutWhiteSeekBar;
-    private float mGamma = 1.0f;
-    private SeekBar mGammaSeekBar;
+    private SeekBar mBar1;
+    private SeekBar mBar2;
+    private SeekBar mBar3;
+    private SeekBar mBar4;
+    private SeekBar mBar5;
+    private TextView mText1;
+    private TextView mText2;
+    private TextView mText3;
+    private TextView mText4;
+    private TextView mText5;
 
     private float mSaturation = 1.0f;
-    private SeekBar mSaturationSeekBar;
 
     private TextView mBenchmarkResult;
-
-    @SuppressWarnings({"FieldCanBeLocal"})
-    private RenderScript mRS;
-    @SuppressWarnings({"FieldCanBeLocal"})
-    private Type mPixelType;
-    @SuppressWarnings({"FieldCanBeLocal"})
-    private Allocation mInPixelsAllocation;
-    @SuppressWarnings({"FieldCanBeLocal"})
-    private Allocation mOutPixelsAllocation;
-    @SuppressWarnings({"FieldCanBeLocal"})
-    private Allocation mScratchPixelsAllocation1;
-    private Allocation mScratchPixelsAllocation2;
+    private Spinner mTestSpinner;
 
     private SurfaceView mSurfaceView;
     private ImageView mDisplayView;
 
-    private boolean mIsProcessing;
+    private boolean mDoingBenchmark;
 
-    class FilterCallback extends RenderScript.RSMessageHandler {
-        private Runnable mAction = new Runnable() {
-            public void run() {
+    private TestBase mTest;
 
-                synchronized (mDisplayView) {
-                    mIsProcessing = false;
-                }
-
-                mOutPixelsAllocation.copyTo(mBitmapOut);
-                mDisplayView.invalidate();
-            }
-        };
-
-        @Override
-        public void run() {
-            mSurfaceView.removeCallbacks(mAction);
-            mSurfaceView.post(mAction);
-        }
-    }
-
-    int in[];
-    int interm[];
-    int out[];
-    int MAX_RADIUS = 25;
-    // Store our coefficients here
-    float gaussian[];
 
     public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
         if (fromUser) {
 
-            if (seekBar == mRadiusSeekBar) {
-                float fRadius = progress / 100.0f;
-                fRadius *= (float)(MAX_RADIUS);
-                mRadius = (int)fRadius;
-
-                mScript.set_radius(mRadius);
-            } else if (seekBar == mInBlackSeekBar) {
-                mInBlack = (float)progress;
-                mScriptVBlur.invoke_setLevels(mInBlack, mOutBlack, mInWhite, mOutWhite);
-            } else if (seekBar == mOutBlackSeekBar) {
-                mOutBlack = (float)progress;
-                mScriptVBlur.invoke_setLevels(mInBlack, mOutBlack, mInWhite, mOutWhite);
-            } else if (seekBar == mInWhiteSeekBar) {
-                mInWhite = (float)progress + 127.0f;
-                mScriptVBlur.invoke_setLevels(mInBlack, mOutBlack, mInWhite, mOutWhite);
-            } else if (seekBar == mOutWhiteSeekBar) {
-                mOutWhite = (float)progress + 127.0f;
-                mScriptVBlur.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;
-                mScriptVBlur.invoke_setGamma(mGamma);
-            } else if (seekBar == mSaturationSeekBar) {
-                mSaturation = (float)progress / 50.0f;
-                mScriptVBlur.invoke_setSaturation(mSaturation);
+            if (seekBar == mBar1) {
+                mTest.onBar1Changed(progress);
+            } else if (seekBar == mBar2) {
+                mTest.onBar2Changed(progress);
+            } else if (seekBar == mBar3) {
+                mTest.onBar3Changed(progress);
+            } else if (seekBar == mBar4) {
+                mTest.onBar4Changed(progress);
+            } else if (seekBar == mBar5) {
+                mTest.onBar5Changed(progress);
             }
 
-            synchronized (mDisplayView) {
-                if (mIsProcessing) {
-                    return;
-                }
-                mIsProcessing = true;
-            }
-
-            mScript.invoke_filter();
+            mTest.runTest();
+            mTest.updateBitmap(mBitmapOut);
+            mDisplayView.invalidate();
         }
     }
 
@@ -156,6 +97,83 @@
     public void onStopTrackingTouch(SeekBar seekBar) {
     }
 
+    void setupBars() {
+        mBar1.setVisibility(View.VISIBLE);
+        mText1.setVisibility(View.VISIBLE);
+        mTest.onBar1Setup(mBar1, mText1);
+
+        mBar2.setVisibility(View.VISIBLE);
+        mText2.setVisibility(View.VISIBLE);
+        mTest.onBar2Setup(mBar2, mText2);
+
+        mBar3.setVisibility(View.VISIBLE);
+        mText3.setVisibility(View.VISIBLE);
+        mTest.onBar3Setup(mBar3, mText3);
+
+        mBar4.setVisibility(View.VISIBLE);
+        mText4.setVisibility(View.VISIBLE);
+        mTest.onBar4Setup(mBar4, mText4);
+
+        mBar5.setVisibility(View.VISIBLE);
+        mText5.setVisibility(View.VISIBLE);
+        mTest.onBar5Setup(mBar5, mText5);
+    }
+
+
+    void changeTest(int testID) {
+        switch(testID) {
+        case 0:
+            mTest = new LevelsV4(false, false);
+            break;
+        case 1:
+            mTest = new LevelsV4(false, true);
+            break;
+        case 2:
+            mTest = new LevelsV4(true, false);
+            break;
+        case 3:
+            mTest = new LevelsV4(true, true);
+            break;
+        case 4:
+            mTest = new Blur25();
+            break;
+        case 5:
+            mTest = new Greyscale();
+            break;
+        }
+
+        mTest.createBaseTest(this, mBitmapIn);
+        setupBars();
+
+        mTest.runTest();
+        mTest.updateBitmap(mBitmapOut);
+        mDisplayView.invalidate();
+        mBenchmarkResult.setText("Result: not run");
+    }
+
+    void setupTests() {
+        mTestNames = new String[6];
+        mTestNames[0] = "Levels Vec3 Relaxed";
+        mTestNames[1] = "Levels Vec4 Relaxed";
+        mTestNames[2] = "Levels Vec3 Full";
+        mTestNames[3] = "Levels Vec4 Full";
+        mTestNames[4] = "Blur radius 25";
+        mTestNames[5] = "Greyscale";
+        mTestSpinner.setAdapter(new ArrayAdapter<String>(
+            this, R.layout.spinner_layout, mTestNames));
+    }
+
+    private AdapterView.OnItemSelectedListener mTestSpinnerListener =
+            new AdapterView.OnItemSelectedListener() {
+                public void onItemSelected(AdapterView<?> parent, View view, int pos, long id) {
+                    changeTest(pos);
+                }
+
+                public void onNothingSelected(AdapterView parent) {
+
+                }
+            };
+
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
@@ -165,94 +183,38 @@
         mBitmapOut = loadBitmap(R.drawable.city);
 
         mSurfaceView = (SurfaceView) findViewById(R.id.surface);
-        mSurfaceView.getHolder().addCallback(this);
 
         mDisplayView = (ImageView) findViewById(R.id.display);
         mDisplayView.setImageBitmap(mBitmapOut);
 
-        mRadiusSeekBar = (SeekBar) findViewById(R.id.radius);
-        mRadiusSeekBar.setOnSeekBarChangeListener(this);
+        mBar1 = (SeekBar) findViewById(R.id.slider1);
+        mBar2 = (SeekBar) findViewById(R.id.slider2);
+        mBar3 = (SeekBar) findViewById(R.id.slider3);
+        mBar4 = (SeekBar) findViewById(R.id.slider4);
+        mBar5 = (SeekBar) findViewById(R.id.slider5);
 
-        mInBlackSeekBar = (SeekBar)findViewById(R.id.inBlack);
-        mInBlackSeekBar.setOnSeekBarChangeListener(this);
-        mInBlackSeekBar.setMax(128);
-        mInBlackSeekBar.setProgress(0);
-        mOutBlackSeekBar = (SeekBar)findViewById(R.id.outBlack);
-        mOutBlackSeekBar.setOnSeekBarChangeListener(this);
-        mOutBlackSeekBar.setMax(128);
-        mOutBlackSeekBar.setProgress(0);
+        mBar1.setOnSeekBarChangeListener(this);
+        mBar2.setOnSeekBarChangeListener(this);
+        mBar3.setOnSeekBarChangeListener(this);
+        mBar4.setOnSeekBarChangeListener(this);
+        mBar5.setOnSeekBarChangeListener(this);
 
-        mInWhiteSeekBar = (SeekBar)findViewById(R.id.inWhite);
-        mInWhiteSeekBar.setOnSeekBarChangeListener(this);
-        mInWhiteSeekBar.setMax(128);
-        mInWhiteSeekBar.setProgress(128);
-        mOutWhiteSeekBar = (SeekBar)findViewById(R.id.outWhite);
-        mOutWhiteSeekBar.setOnSeekBarChangeListener(this);
-        mOutWhiteSeekBar.setMax(128);
-        mOutWhiteSeekBar.setProgress(128);
+        mText1 = (TextView) findViewById(R.id.slider1Text);
+        mText2 = (TextView) findViewById(R.id.slider2Text);
+        mText3 = (TextView) findViewById(R.id.slider3Text);
+        mText4 = (TextView) findViewById(R.id.slider4Text);
+        mText5 = (TextView) findViewById(R.id.slider5Text);
 
-        mGammaSeekBar = (SeekBar)findViewById(R.id.inGamma);
-        mGammaSeekBar.setOnSeekBarChangeListener(this);
-        mGammaSeekBar.setMax(150);
-        mGammaSeekBar.setProgress(100);
-
-        mSaturationSeekBar = (SeekBar)findViewById(R.id.inSaturation);
-        mSaturationSeekBar.setOnSeekBarChangeListener(this);
-        mSaturationSeekBar.setProgress(50);
+        mTestSpinner = (Spinner) findViewById(R.id.filterselection);
+        mTestSpinner.setOnItemSelectedListener(mTestSpinnerListener);
 
         mBenchmarkResult = (TextView) findViewById(R.id.benchmarkText);
         mBenchmarkResult.setText("Result: not run");
+
+        setupTests();
+        changeTest(0);
     }
 
-    public void surfaceCreated(SurfaceHolder holder) {
-        createScript();
-        mScript.invoke_filter();
-        mOutPixelsAllocation.copyTo(mBitmapOut);
-    }
-
-    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
-    }
-
-    public void surfaceDestroyed(SurfaceHolder holder) {
-    }
-
-    private void createScript() {
-        mRS = RenderScript.create(this);
-        mRS.setMessageHandler(new FilterCallback());
-
-        mInPixelsAllocation = Allocation.createFromBitmap(mRS, mBitmapIn,
-                                                          Allocation.MipmapControl.MIPMAP_NONE,
-                                                          Allocation.USAGE_SCRIPT);
-        mOutPixelsAllocation = Allocation.createFromBitmap(mRS, mBitmapOut,
-                                                           Allocation.MipmapControl.MIPMAP_NONE,
-                                                           Allocation.USAGE_SCRIPT);
-
-        Type.Builder tb = new Type.Builder(mRS, Element.F32_4(mRS));
-        tb.setX(mBitmapIn.getWidth());
-        tb.setY(mBitmapIn.getHeight());
-        mScratchPixelsAllocation1 = Allocation.createTyped(mRS, tb.create());
-        mScratchPixelsAllocation2 = Allocation.createTyped(mRS, tb.create());
-
-        mScriptVBlur = new ScriptC_vertical_blur(mRS, getResources(), R.raw.vertical_blur);
-        mScriptHBlur = new ScriptC_horizontal_blur(mRS, getResources(), R.raw.horizontal_blur);
-
-        mScript = new ScriptC_threshold(mRS, getResources(), R.raw.threshold);
-        mScript.set_width(mBitmapIn.getWidth());
-        mScript.set_height(mBitmapIn.getHeight());
-        mScript.set_radius(mRadius);
-
-        mScriptVBlur.invoke_setLevels(mInBlack, mOutBlack, mInWhite, mOutWhite);
-        mScriptVBlur.invoke_setGamma(mGamma);
-        mScriptVBlur.invoke_setSaturation(mSaturation);
-
-        mScript.bind_InPixel(mInPixelsAllocation);
-        mScript.bind_OutPixel(mOutPixelsAllocation);
-        mScript.bind_ScratchPixel1(mScratchPixelsAllocation1);
-        mScript.bind_ScratchPixel2(mScratchPixelsAllocation2);
-
-        mScript.set_vBlurScript(mScriptVBlur);
-        mScript.set_hBlurScript(mScriptHBlur);
-    }
 
     private Bitmap loadBitmap(int resource) {
         final BitmapFactory.Options options = new BitmapFactory.Options();
@@ -278,26 +240,29 @@
 
     // For benchmark test
     public long getBenchmark() {
+        mDoingBenchmark = true;
+
+        mTest.setupBenchmark();
+        long result = 0;
+
+        Log.v(TAG, "Warming");
+        long t = java.lang.System.currentTimeMillis() + 2000;
+        do {
+            mTest.runTest();
+            mTest.finish();
+        } while (t > java.lang.System.currentTimeMillis());
+
+
         Log.v(TAG, "Benchmarking");
-        int oldRadius = mRadius;
-        mRadius = MAX_RADIUS;
-        mScript.set_radius(mRadius);
-
-        mScript.invoke_filter();
-        mRS.finish();
-
-        long t = java.lang.System.currentTimeMillis();
-
-        mScript.invoke_filter();
-        mOutPixelsAllocation.copyTo(mBitmapOut);
-
+        t = java.lang.System.currentTimeMillis();
+        mTest.runTest();
+        mTest.finish();
         t = java.lang.System.currentTimeMillis() - t;
-        Log.v(TAG, "getBenchmark: Renderscript frame time core ms " + t);
-        mRadius = oldRadius;
-        mScript.set_radius(mRadius);
 
-        mScript.invoke_filter();
-        mOutPixelsAllocation.copyTo(mBitmapOut);
+        Log.v(TAG, "getBenchmark: Renderscript frame time core ms " + t);
+        mTest.exitBenchmark();
+        mDoingBenchmark = false;
+
         return t;
     }
 }
diff --git a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/LevelsV4.java b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/LevelsV4.java
new file mode 100644
index 0000000..9eb5647
--- /dev/null
+++ b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/LevelsV4.java
@@ -0,0 +1,167 @@
+/*
+ * Copyright (C) 2012 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 java.lang.Math;
+
+import android.renderscript.Allocation;
+import android.renderscript.Element;
+import android.renderscript.RenderScript;
+import android.renderscript.Matrix3f;
+import android.renderscript.Script;
+import android.renderscript.ScriptC;
+import android.renderscript.Type;
+import android.util.Log;
+import android.widget.SeekBar;
+import android.widget.TextView;
+
+
+public class LevelsV4 extends TestBase {
+    private ScriptC_levels_relaxed mScriptR;
+    private ScriptC_levels_full mScriptF;
+    private float mInBlack = 0.0f;
+    private float mOutBlack = 0.0f;
+    private float mInWhite = 255.0f;
+    private float mOutWhite = 255.0f;
+    private float mSaturation = 1.0f;
+
+    Matrix3f satMatrix = new Matrix3f();
+    float mInWMinInB;
+    float mOutWMinOutB;
+    float mOverInWMinInB;
+
+    boolean mUseFull;
+    boolean mUseV4;
+
+    LevelsV4(boolean useFull, boolean useV4) {
+        mUseFull = useFull;
+        mUseV4 = useV4;
+    }
+
+
+    private void setLevels() {
+        mInWMinInB = mInWhite - mInBlack;
+        mOutWMinOutB = mOutWhite - mOutBlack;
+        mOverInWMinInB = 1.f / mInWMinInB;
+
+        mScriptR.set_inBlack(mInBlack);
+        mScriptR.set_outBlack(mOutBlack);
+        mScriptR.set_inWMinInB(mInWMinInB);
+        mScriptR.set_outWMinOutB(mOutWMinOutB);
+        mScriptR.set_overInWMinInB(mOverInWMinInB);
+        mScriptF.set_inBlack(mInBlack);
+        mScriptF.set_outBlack(mOutBlack);
+        mScriptF.set_inWMinInB(mInWMinInB);
+        mScriptF.set_outWMinOutB(mOutWMinOutB);
+        mScriptF.set_overInWMinInB(mOverInWMinInB);
+    }
+
+    private void setSaturation() {
+        float rWeight = 0.299f;
+        float gWeight = 0.587f;
+        float bWeight = 0.114f;
+        float oneMinusS = 1.0f - mSaturation;
+
+        satMatrix.set(0, 0, oneMinusS * rWeight + mSaturation);
+        satMatrix.set(0, 1, oneMinusS * rWeight);
+        satMatrix.set(0, 2, oneMinusS * rWeight);
+        satMatrix.set(1, 0, oneMinusS * gWeight);
+        satMatrix.set(1, 1, oneMinusS * gWeight + mSaturation);
+        satMatrix.set(1, 2, oneMinusS * gWeight);
+        satMatrix.set(2, 0, oneMinusS * bWeight);
+        satMatrix.set(2, 1, oneMinusS * bWeight);
+        satMatrix.set(2, 2, oneMinusS * bWeight + mSaturation);
+        mScriptR.set_colorMat(satMatrix);
+        mScriptF.set_colorMat(satMatrix);
+    }
+
+    public boolean onBar1Setup(SeekBar b, TextView t) {
+        b.setProgress(50);
+        t.setText("Saturation");
+        return true;
+    }
+    public boolean onBar2Setup(SeekBar b, TextView t) {
+        b.setMax(128);
+        b.setProgress(0);
+        t.setText("In Black");
+        return true;
+    }
+    public boolean onBar3Setup(SeekBar b, TextView t) {
+        b.setMax(128);
+        b.setProgress(0);
+        t.setText("Out Black");
+        return true;
+    }
+    public boolean onBar4Setup(SeekBar b, TextView t) {
+        b.setMax(128);
+        b.setProgress(128);
+        t.setText("Out White");
+        return true;
+    }
+    public boolean onBar5Setup(SeekBar b, TextView t) {
+        b.setMax(128);
+        b.setProgress(128);
+        t.setText("Out White");
+        return true;
+    }
+
+    public void onBar1Changed(int progress) {
+        mSaturation = (float)progress / 50.0f;
+        setSaturation();
+    }
+    public void onBar2Changed(int progress) {
+        mInBlack = (float)progress;
+        setLevels();
+    }
+    public void onBar3Changed(int progress) {
+        mOutBlack = (float)progress;
+        setLevels();
+    }
+    public void onBar4Changed(int progress) {
+        mInWhite = (float)progress + 127.0f;
+        setLevels();
+    }
+    public void onBar5Changed(int progress) {
+        mOutWhite = (float)progress + 127.0f;
+        setLevels();
+    }
+
+    public void createTest(android.content.res.Resources res) {
+        mScriptR = new ScriptC_levels_relaxed(mRS, res, R.raw.levels_relaxed);
+        mScriptF = new ScriptC_levels_full(mRS, res, R.raw.levels_full);
+        setSaturation();
+        setLevels();
+    }
+
+    public void runTest() {
+        if (mUseFull) {
+            if (mUseV4) {
+                mScriptF.forEach_root4(mInPixelsAllocation, mOutPixelsAllocation);
+            } else {
+                mScriptF.forEach_root(mInPixelsAllocation, mOutPixelsAllocation);
+            }
+        } else {
+            if (mUseV4) {
+                mScriptR.forEach_root4(mInPixelsAllocation, mOutPixelsAllocation);
+            } else {
+                mScriptR.forEach_root(mInPixelsAllocation, mOutPixelsAllocation);
+            }
+        }
+    }
+
+}
+
diff --git a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/TestBase.java b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/TestBase.java
new file mode 100644
index 0000000..3a6241d
--- /dev/null
+++ b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/TestBase.java
@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) 2012 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.app.Activity;
+import android.content.Context;
+import android.os.Bundle;
+import android.graphics.BitmapFactory;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.renderscript.ScriptC;
+import android.renderscript.RenderScript;
+import android.renderscript.Type;
+import android.renderscript.Allocation;
+import android.renderscript.Element;
+import android.renderscript.Script;
+import android.view.SurfaceView;
+import android.view.SurfaceHolder;
+import android.widget.ImageView;
+import android.widget.SeekBar;
+import android.widget.TextView;
+import android.view.View;
+import android.util.Log;
+import java.lang.Math;
+
+public class TestBase  {
+    protected final String TAG = "Img";
+
+    protected RenderScript mRS;
+    protected Allocation mInPixelsAllocation;
+    protected Allocation mOutPixelsAllocation;
+
+    // Override to use UI elements
+    public void onBar1Changed(int progress) {
+    }
+    public void onBar2Changed(int progress) {
+    }
+    public void onBar3Changed(int progress) {
+    }
+    public void onBar4Changed(int progress) {
+    }
+    public void onBar5Changed(int progress) {
+    }
+
+    // Override to use UI elements
+    // Unused bars will be hidden.
+    public boolean onBar1Setup(SeekBar b, TextView t) {
+        b.setVisibility(View.INVISIBLE);
+        t.setVisibility(View.INVISIBLE);
+        return false;
+    }
+    public boolean onBar2Setup(SeekBar b, TextView t) {
+        b.setVisibility(View.INVISIBLE);
+        t.setVisibility(View.INVISIBLE);
+        return false;
+    }
+    public boolean onBar3Setup(SeekBar b, TextView t) {
+        b.setVisibility(View.INVISIBLE);
+        t.setVisibility(View.INVISIBLE);
+        return false;
+    }
+    public boolean onBar4Setup(SeekBar b, TextView t) {
+        b.setVisibility(View.INVISIBLE);
+        t.setVisibility(View.INVISIBLE);
+        return false;
+    }
+    public boolean onBar5Setup(SeekBar b, TextView t) {
+        b.setVisibility(View.INVISIBLE);
+        t.setVisibility(View.INVISIBLE);
+        return false;
+    }
+
+    public final void createBaseTest(ImageProcessingActivity act, Bitmap b) {
+        mRS = RenderScript.create(act);
+        mInPixelsAllocation = Allocation.createFromBitmap(mRS, b,
+                                                          Allocation.MipmapControl.MIPMAP_NONE,
+                                                          Allocation.USAGE_SCRIPT);
+        mOutPixelsAllocation = Allocation.createFromBitmap(mRS, b,
+                                                           Allocation.MipmapControl.MIPMAP_NONE,
+                                                           Allocation.USAGE_SCRIPT);
+        createTest(act.getResources());
+    }
+
+    // Must override
+    public void createTest(android.content.res.Resources res) {
+        android.util.Log.e("img", "implement createTest");
+    }
+
+    // Must override
+    public void runTest() {
+    }
+
+    public void finish() {
+        mRS.finish();
+    }
+
+    public void updateBitmap(Bitmap b) {
+        mOutPixelsAllocation.copyTo(b);
+    }
+
+    // Override to configure specific benchmark config.
+    public void setupBenchmark() {
+    }
+
+    // Override to reset after benchmark.
+    public void exitBenchmark() {
+    }
+}
diff --git a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/greyscale.rs b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/greyscale.rs
new file mode 100644
index 0000000..c420cac
--- /dev/null
+++ b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/greyscale.rs
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2012 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.
+ */
+
+#pragma version(1)
+#pragma rs java_package_name(com.android.rs.image)
+#pragma rs_fp_relaxed
+
+const static float3 gMonoMult = {0.299f, 0.587f, 0.114f};
+
+void root(const uchar4 *v_in, uchar4 *v_out) {
+    float4 f4 = rsUnpackColor8888(*v_in);
+
+    float3 mono = dot(f4.rgb, gMonoMult);
+    *v_out = rsPackColorTo8888(mono);
+}
+
+
diff --git a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/levels.rsh b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/levels.rsh
new file mode 100644
index 0000000..7c5d930
--- /dev/null
+++ b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/levels.rsh
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2012 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.
+ */
+
+float inBlack;
+float outBlack;
+float inWMinInB;
+float outWMinOutB;
+float overInWMinInB;
+rs_matrix3x3 colorMat;
+
+void root(const uchar4 *in, uchar4 *out, uint32_t x, uint32_t y) {
+    float3 pixel = convert_float4(in[0]).rgb;
+    pixel = rsMatrixMultiply(&colorMat, pixel);
+    pixel = clamp(pixel, 0.f, 255.f);
+    pixel = (pixel - inBlack) * overInWMinInB;
+    pixel = pixel * outWMinOutB + outBlack;
+    pixel = clamp(pixel, 0.f, 255.f);
+    out->xyz = convert_uchar3(pixel);
+    out->w = 0xff;
+}
+
+void root4(const uchar4 *in, uchar4 *out, uint32_t x, uint32_t y) {
+    float4 pixel = convert_float4(in[0]);
+    pixel.rgb = rsMatrixMultiply(&colorMat, pixel.rgb);
+    pixel = clamp(pixel, 0.f, 255.f);
+    pixel = (pixel - inBlack) * overInWMinInB;
+    pixel = pixel * outWMinOutB + outBlack;
+    pixel = clamp(pixel, 0.f, 255.f);
+    out->xyzw = convert_uchar4(pixel);
+}
+
diff --git a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/levels_full.rs b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/levels_full.rs
new file mode 100644
index 0000000..da6a291
--- /dev/null
+++ b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/levels_full.rs
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2012 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.
+ */
+
+#pragma version(1)
+#pragma rs java_package_name(com.android.rs.image)
+
+#include "levels.rsh"
+
diff --git a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/levels_relaxed.rs b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/levels_relaxed.rs
new file mode 100644
index 0000000..b115445
--- /dev/null
+++ b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/levels_relaxed.rs
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2012 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.
+ */
+
+#pragma version(1)
+#pragma rs java_package_name(com.android.rs.image)
+#pragma rs_fp_relaxed
+
+#include "levels.rsh"
+
diff --git a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/threshold.rs b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/threshold.rs
index d93238c..77cd5be 100644
--- a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/threshold.rs
+++ b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/threshold.rs
@@ -88,6 +88,6 @@
 
     fs.ain = rsGetAllocation(ScratchPixel2);
     rsForEach(vBlurScript, fs.ain, rsGetAllocation(OutPixel), &fs, sizeof(fs));
-    rsSendToClientBlocking(CMD_FINISHED);
+    //rsSendToClientBlocking(CMD_FINISHED);
 }
 
diff --git a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/vertical_blur.rs b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/vertical_blur.rs
index a6da192..60fd71b 100644
--- a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/vertical_blur.rs
+++ b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/vertical_blur.rs
@@ -3,29 +3,9 @@
 
 #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;
 
-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;
 
@@ -52,10 +32,6 @@
     rsMatrixSet(&colorMat, 2, 2, oneMinusS * bWeight + saturation);
 }
 
-void setGamma(float g) {
-    gamma = (float3)g;
-}
-
 void root(uchar4 *out, const void *usrData, uint32_t x, uint32_t y) {
     const FilterStruct *fs = (const FilterStruct *)usrData;
     float3 blurredPixel = 0;
@@ -76,12 +52,8 @@
     }
 
     float3 temp = rsMatrixMultiply(&colorMat, blurredPixel);
-    temp = (clamp(temp, 0.f, 255.f) - inBlack) * overInWMinInB;
-    if (gamma.x != 1.0f)
-        temp = pow(temp, (float3)gamma);
-    temp = clamp(temp * outWMinOutB + outBlack, 0.f, 255.f);
-
+    temp = clamp(temp, 0.f, 255.f);
     out->xyz = convert_uchar3(temp);
-    //output->w = input->w;
+    out->w = 0xff;
 }