Merge "Allow data uris to be data sources"
diff --git a/api/current.txt b/api/current.txt
index 680c492..9610853 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -17435,6 +17435,7 @@
     method public static boolean putString(android.content.ContentResolver, java.lang.String, java.lang.String);
     method public static final void setLocationProviderEnabled(android.content.ContentResolver, java.lang.String, boolean);
     field public static final java.lang.String ACCESSIBILITY_ENABLED = "accessibility_enabled";
+    field public static final java.lang.String ACCESSIBILITY_SPEAK_PASSWORD = "speak_password";
     field public static final java.lang.String ADB_ENABLED = "adb_enabled";
     field public static final java.lang.String ALLOWED_GEOLOCATION_ORIGINS = "allowed_geolocation_origins";
     field public static final java.lang.String ALLOW_MOCK_LOCATION = "mock_location";
diff --git a/cmds/input/src/com/android/commands/input/Input.java b/cmds/input/src/com/android/commands/input/Input.java
index df1d0bf..c4c3b8a 100755
--- a/cmds/input/src/com/android/commands/input/Input.java
+++ b/cmds/input/src/com/android/commands/input/Input.java
@@ -23,6 +23,7 @@
 import android.view.IWindowManager;
 import android.view.KeyCharacterMap;
 import android.view.KeyEvent;
+import android.view.MotionEvent;
 
 /**
  * Command that sends key events to the device, either by their keycode, or by
@@ -30,6 +31,9 @@
  */
 
 public class Input {
+    private static final String TAG = "Input";
+
+    private IWindowManager mWindowManager;
 
     /**
      * Command-line entry point.
@@ -40,6 +44,13 @@
         (new Input()).run(args);
     }
 
+    private IWindowManager getWindowManager() {
+        if (mWindowManager == null) {
+            mWindowManager = (IWindowManager.Stub.asInterface(ServiceManager.getService("window")));
+        }
+        return mWindowManager;
+    }
+
     private void run(String[] args) {
         if (args.length < 1) {
             showUsage();
@@ -48,19 +59,37 @@
 
         String command = args[0];
 
-        if (command.equals("text")) {
-            sendText(args[1]);
-        } else if (command.equals("keyevent")) {
-            sendKeyEvent(args[1]);
-        } else if (command.equals("motionevent")) {
-            System.err.println("Error: motionevent not yet supported.");
-            return;
+        try {
+            if (command.equals("text")) {
+                if (args.length == 2) {
+                    sendText(args[1]);
+                    return;
+                }
+            } else if (command.equals("keyevent")) {
+                if (args.length == 2) {
+                    sendKeyEvent(Integer.parseInt(args[1]));
+                    return;
+                }
+            } else if (command.equals("tap")) {
+                if (args.length == 3) {
+                    sendTap(Float.parseFloat(args[1]), Float.parseFloat(args[2]));
+                    return;
+                }
+            } else if (command.equals("swipe")) {
+                if (args.length == 5) {
+                    sendSwipe(Float.parseFloat(args[1]), Float.parseFloat(args[2]),
+                            Float.parseFloat(args[3]), Float.parseFloat(args[4]));
+                    return;
+                }
+            } else {
+                System.err.println("Error: Unknown command: " + command);
+                showUsage();
+                return;
+            }
+        } catch (NumberFormatException ex) {
         }
-        else {
-            System.err.println("Error: Unknown command: " + command);
-            showUsage();
-            return;
-        }
+        System.err.println("Error: Invalid arguments for command: " + command);
+        showUsage();
     }
 
     /**
@@ -69,7 +98,6 @@
      *
      * @param text is a string of characters you want to input to the device.
      */
-
     private void sendText(String text) {
 
         StringBuffer buff = new StringBuffer(text);
@@ -90,55 +118,66 @@
 
         char[] chars = buff.toString().toCharArray();
 
-        KeyCharacterMap mKeyCharacterMap = KeyCharacterMap.
-            load(KeyCharacterMap.VIRTUAL_KEYBOARD);
-
-        KeyEvent[] events = mKeyCharacterMap.getEvents(chars);
-
+        KeyCharacterMap kcm = KeyCharacterMap.load(KeyCharacterMap.VIRTUAL_KEYBOARD);
+        KeyEvent[] events = kcm.getEvents(chars);
         for(int i = 0; i < events.length; i++) {
-            KeyEvent event = events[i];
-            Log.i("SendKeyEvent", Integer.toString(event.getKeyCode()));
-            try {
-                (IWindowManager.Stub
-                    .asInterface(ServiceManager.getService("window")))
-                    .injectKeyEvent(event, true);
-            } catch (RemoteException e) {
-                Log.i("Input", "DeadOjbectException");
-            }
+            injectKeyEvent(events[i]);
         }
     }
 
-    /**
-     * Send a single key event.
-     *
-     * @param event is a string representing the keycode of the key event you
-     * want to execute.
-     */
-    private void sendKeyEvent(String event) {
-        int eventCode = Integer.parseInt(event);
+    private void sendKeyEvent(int keyCode) {
         long now = SystemClock.uptimeMillis();
-        Log.i("SendKeyEvent", event);
+        injectKeyEvent(new KeyEvent(now, now, KeyEvent.ACTION_DOWN, keyCode, 0));
+        injectKeyEvent(new KeyEvent(now, now, KeyEvent.ACTION_UP, keyCode, 0));
+    }
+
+    private void sendTap(float x, float y) {
+        long now = SystemClock.uptimeMillis();
+        injectPointerEvent(MotionEvent.obtain(now, now, MotionEvent.ACTION_DOWN, x, y, 0));
+        injectPointerEvent(MotionEvent.obtain(now, now, MotionEvent.ACTION_UP, x, y, 0));
+    }
+
+    private void sendSwipe(float x1, float y1, float x2, float y2) {
+        final int NUM_STEPS = 11;
+        long now = SystemClock.uptimeMillis();
+        injectPointerEvent(MotionEvent.obtain(now, now, MotionEvent.ACTION_DOWN, x1, y1, 0));
+        for (int i = 1; i < NUM_STEPS; i++) {
+            float alpha = (float)i / NUM_STEPS;
+            injectPointerEvent(MotionEvent.obtain(now, now, MotionEvent.ACTION_MOVE,
+                    lerp(x1, x2, alpha), lerp(y1, y2, alpha), 0));
+        }
+        injectPointerEvent(MotionEvent.obtain(now, now, MotionEvent.ACTION_UP, x2, y2, 0));
+    }
+
+    private void injectKeyEvent(KeyEvent event) {
         try {
-            KeyEvent down = new KeyEvent(now, now, KeyEvent.ACTION_DOWN, eventCode, 0);
-            KeyEvent up = new KeyEvent(now, now, KeyEvent.ACTION_UP, eventCode, 0);
-            (IWindowManager.Stub
-                .asInterface(ServiceManager.getService("window")))
-                .injectKeyEvent(down, true);
-            (IWindowManager.Stub
-                .asInterface(ServiceManager.getService("window")))
-                .injectKeyEvent(up, true);
-        } catch (RemoteException e) {
-            Log.i("Input", "DeadOjbectException");
+            Log.i(TAG, "InjectKeyEvent: " + event);
+            getWindowManager().injectKeyEvent(event, true);
+        } catch (RemoteException ex) {
+            Log.i(TAG, "RemoteException", ex);
         }
     }
 
-    private void sendMotionEvent(long downTime, int action, float x, float y, 
-            float pressure, float size) {
+    private void injectPointerEvent(MotionEvent event) {
+        try {
+            Log.i("Input", "InjectPointerEvent: " + event);
+            getWindowManager().injectPointerEvent(event, true);
+        } catch (RemoteException ex) {
+            Log.i(TAG, "RemoteException", ex);
+        } finally {
+            event.recycle();
+        }
+    }
+
+    private static final float lerp(float a, float b, float alpha) {
+        return (b - a) * alpha + a;
     }
 
     private void showUsage() {
         System.err.println("usage: input [text|keyevent]");
         System.err.println("       input text <string>");
-        System.err.println("       input keyevent <event_code>");
+        System.err.println("       input keyevent <key code>");
+        System.err.println("       input tap <x> <y>");
+        System.err.println("       input swipe <x1> <y1> <x2> <y2>");
     }
 }
diff --git a/core/java/android/app/StatusBarManager.java b/core/java/android/app/StatusBarManager.java
index 5b8addf..dd9f337 100644
--- a/core/java/android/app/StatusBarManager.java
+++ b/core/java/android/app/StatusBarManager.java
@@ -56,6 +56,11 @@
             | DISABLE_NOTIFICATION_ALERTS | DISABLE_NOTIFICATION_TICKER
             | DISABLE_SYSTEM_INFO | DISABLE_RECENT | DISABLE_HOME | DISABLE_BACK | DISABLE_CLOCK;
 
+    public static final int NAVIGATION_HINT_BACK_NOP      = 1 << 0;
+    public static final int NAVIGATION_HINT_HOME_NOP      = 1 << 1;
+    public static final int NAVIGATION_HINT_RECENT_NOP    = 1 << 2;
+    public static final int NAVIGATION_HINT_BACK_ALT      = 1 << 3;
+
     private Context mContext;
     private IStatusBarService mService;
     private IBinder mToken = new Binder();
diff --git a/core/java/android/inputmethodservice/KeyboardView.java b/core/java/android/inputmethodservice/KeyboardView.java
index 5143f7f..7257521 100644
--- a/core/java/android/inputmethodservice/KeyboardView.java
+++ b/core/java/android/inputmethodservice/KeyboardView.java
@@ -31,6 +31,7 @@
 import android.media.AudioManager;
 import android.os.Handler;
 import android.os.Message;
+import android.provider.Settings;
 import android.util.AttributeSet;
 import android.util.TypedValue;
 import android.view.GestureDetector;
@@ -967,8 +968,13 @@
             AccessibilityEvent event = AccessibilityEvent.obtain(eventType);
             onInitializeAccessibilityEvent(event);
             String text = null;
-            // Add text only if headset is used to avoid leaking passwords.
-            if (mAudioManager.isBluetoothA2dpOn() || mAudioManager.isWiredHeadsetOn()) {
+            // This is very efficient since the properties are cached.
+            final boolean speakPassword = Settings.Secure.getInt(mContext.getContentResolver(),
+                    Settings.Secure.ACCESSIBILITY_SPEAK_PASSWORD, 0) != 0;
+            // Add text only if password announcement is enabled or if headset is
+            // used to avoid leaking passwords.
+            if (speakPassword || mAudioManager.isBluetoothA2dpOn()
+                    || mAudioManager.isWiredHeadsetOn()) {
                 switch (code) {
                     case Keyboard.KEYCODE_ALT:
                         text = mContext.getString(R.string.keyboardview_keycode_alt);
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 1b5d73e..caff53b 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -2774,6 +2774,11 @@
             "enabled_accessibility_services";
 
         /**
+         * Whether to speak passwords while in accessibility mode.
+         */
+        public static final String ACCESSIBILITY_SPEAK_PASSWORD = "speak_password";
+
+        /**
          * If injection of accessibility enhancing JavaScript scripts
          * is enabled.
          * <p>
@@ -3127,6 +3132,14 @@
                 "wifi_watchdog_blacklist_followup_interval_ms";
 
         /**
+         * Setting to turn off poor network avoidance on Wi-Fi. Feature is disabled by default and
+         * the setting needs to be set to 1 to enable it.
+         * @hide
+         */
+        public static final String WIFI_WATCHDOG_POOR_NETWORK_TEST_ENABLED =
+                "wifi_watchdog_poor_network_test_enabled";
+
+        /**
          * Setting to turn off walled garden test on Wi-Fi. Feature is enabled by default and
          * the setting needs to be set to 0 to disable it.
          * @hide
@@ -4121,6 +4134,7 @@
             ENABLED_ACCESSIBILITY_SERVICES,
             TOUCH_EXPLORATION_ENABLED,
             ACCESSIBILITY_ENABLED,
+            ACCESSIBILITY_SPEAK_PASSWORD,
             TTS_USE_DEFAULTS,
             TTS_DEFAULT_RATE,
             TTS_DEFAULT_PITCH,
diff --git a/core/java/android/view/Choreographer.java b/core/java/android/view/Choreographer.java
index 0fdd105..63de128 100644
--- a/core/java/android/view/Choreographer.java
+++ b/core/java/android/view/Choreographer.java
@@ -66,9 +66,11 @@
 
     // System property to enable/disable the use of the vsync / animation timer
     // for drawing rather than drawing immediately.
-    // Enabled by default.
+    // Temporarily disabled by default because postponing performTraversals() violates
+    // assumptions about traversals happening in-order relative to other posted messages.
+    // Bug: 5721047
     private static final boolean USE_ANIMATION_TIMER_FOR_DRAW = SystemProperties.getBoolean(
-            "debug.choreographer.animdraw", true);
+            "debug.choreographer.animdraw", false);
 
     private static final int MSG_DO_ANIMATION = 0;
     private static final int MSG_DO_DRAW = 1;
diff --git a/core/java/android/view/GLES20Canvas.java b/core/java/android/view/GLES20Canvas.java
index aa0bfd2..43a451d 100644
--- a/core/java/android/view/GLES20Canvas.java
+++ b/core/java/android/view/GLES20Canvas.java
@@ -154,6 +154,7 @@
     static native void nSetTextureLayerTransform(int layerId, int matrix);
     static native void nDestroyLayer(int layerId);
     static native void nDestroyLayerDeferred(int layerId);
+    static native void nFlushLayer(int layerId);
     static native boolean nCopyLayer(int layerId, int bitmap);
 
     ///////////////////////////////////////////////////////////////////////////
diff --git a/core/java/android/view/GLES20Layer.java b/core/java/android/view/GLES20Layer.java
index fd3b9e5..4f25792 100644
--- a/core/java/android/view/GLES20Layer.java
+++ b/core/java/android/view/GLES20Layer.java
@@ -60,6 +60,13 @@
         }
         mLayer = 0;
     }
+    
+    @Override
+    void flush() {
+        if (mLayer != 0) {
+            GLES20Canvas.nFlushLayer(mLayer);
+        }
+    }
 
     static class Finalizer {
         private int mLayerId;
diff --git a/core/java/android/view/HardwareLayer.java b/core/java/android/view/HardwareLayer.java
index 28389ab..d5666f3 100644
--- a/core/java/android/view/HardwareLayer.java
+++ b/core/java/android/view/HardwareLayer.java
@@ -116,6 +116,11 @@
     abstract void destroy();
 
     /**
+     * Flush the render queue associated with this layer.
+     */
+    abstract void flush();
+
+    /**
      * This must be invoked before drawing onto this layer.
      * @param currentCanvas
      */
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 304a9a1..af8f8cb 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -10207,6 +10207,13 @@
                 break;
         }
     }
+    
+    // Make sure the HardwareRenderer.validate() was invoked before calling this method
+    void flushLayer() {
+        if (mLayerType == LAYER_TYPE_HARDWARE && mHardwareLayer != null) {
+            mHardwareLayer.flush();
+        }
+    }
 
     /**
      * <p>Returns a hardware layer that can be used to draw this view again
@@ -10219,6 +10226,8 @@
                 !mAttachInfo.mHardwareRenderer.isEnabled()) {
             return null;
         }
+        
+        if (!mAttachInfo.mHardwareRenderer.validate()) return null;
 
         final int width = mRight - mLeft;
         final int height = mBottom - mTop;
@@ -10293,12 +10302,15 @@
      */
     boolean destroyLayer() {
         if (mHardwareLayer != null) {
-            mHardwareLayer.destroy();
-            mHardwareLayer = null;
+            AttachInfo info = mAttachInfo;
+            if (info != null && info.mHardwareRenderer != null &&
+                    info.mHardwareRenderer.isEnabled() && info.mHardwareRenderer.validate()) {
+                mHardwareLayer.destroy();
+                mHardwareLayer = null;
 
-            invalidate(true);
-            invalidateParentCaches();
-
+                invalidate(true);
+                invalidateParentCaches();
+            }
             return true;
         }
         return false;
diff --git a/core/java/android/view/ViewConfiguration.java b/core/java/android/view/ViewConfiguration.java
index d824e36..05c5daa 100644
--- a/core/java/android/view/ViewConfiguration.java
+++ b/core/java/android/view/ViewConfiguration.java
@@ -139,9 +139,17 @@
     private static final int EDGE_SLOP = 12;
     
     /**
-     * Distance a touch can wander before we think the user is scrolling in dips
+     * Distance a touch can wander before we think the user is scrolling in dips.
+     * Note that this value defined here is only used as a fallback by legacy/misbehaving
+     * applications that do not provide a Context for determining density/configuration-dependent
+     * values.
+     *
+     * To alter this value, see the configuration resource config_viewConfigurationTouchSlop
+     * in frameworks/base/core/res/res/values/config.xml or the appropriate device resource overlay.
+     * It may be appropriate to tweak this on a device-specific basis in an overlay based on
+     * the characteristics of the touch panel and firmware.
      */
-    private static final int TOUCH_SLOP = 16;
+    private static final int TOUCH_SLOP = 4;
     
     /**
      * Distance the first touch can wander before we stop considering this event a double tap
@@ -152,6 +160,14 @@
     /**
      * Distance a touch can wander before we think the user is attempting a paged scroll
      * (in dips)
+     *
+     * Note that this value defined here is only used as a fallback by legacy/misbehaving
+     * applications that do not provide a Context for determining density/configuration-dependent
+     * values.
+     *
+     * See the note above on {@link #TOUCH_SLOP} regarding the dimen resource
+     * config_viewConfigurationTouchSlop. ViewConfiguration will report a paging touch slop of
+     * config_viewConfigurationTouchSlop * 2 when provided with a Context.
      */
     private static final int PAGING_TOUCH_SLOP = TOUCH_SLOP * 2;
     
@@ -285,9 +301,6 @@
         mMinimumFlingVelocity = (int) (density * MINIMUM_FLING_VELOCITY + 0.5f);
         mMaximumFlingVelocity = (int) (density * MAXIMUM_FLING_VELOCITY + 0.5f);
         mScrollbarSize = (int) (density * SCROLL_BAR_SIZE + 0.5f);
-        mTouchSlop = (int) (sizeAndDensity * TOUCH_SLOP + 0.5f);
-        mDoubleTapTouchSlop = (int) (sizeAndDensity * DOUBLE_TAP_TOUCH_SLOP + 0.5f);
-        mPagingTouchSlop = (int) (sizeAndDensity * PAGING_TOUCH_SLOP + 0.5f);
         mDoubleTapSlop = (int) (sizeAndDensity * DOUBLE_TAP_SLOP + 0.5f);
         mScaledTouchExplorationTapSlop = (int) (density * TOUCH_EXPLORATION_TAP_SLOP + 0.5f);
         mWindowTouchSlop = (int) (sizeAndDensity * WINDOW_TOUCH_SLOP + 0.5f);
@@ -310,6 +323,11 @@
 
         mFadingMarqueeEnabled = res.getBoolean(
                 com.android.internal.R.bool.config_ui_enableFadingMarquee);
+        mTouchSlop = res.getDimensionPixelSize(
+                com.android.internal.R.dimen.config_viewConfigurationTouchSlop);
+        mPagingTouchSlop = mTouchSlop * 2;
+
+        mDoubleTapTouchSlop = mTouchSlop;
     }
 
     /**
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index 2a041f7..5035cae 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -2958,6 +2958,17 @@
             mDrawLayers = enabled;
             invalidate(true);
 
+            boolean flushLayers = !enabled;
+            AttachInfo info = mAttachInfo;
+            if (info != null && info.mHardwareRenderer != null &&
+                    info.mHardwareRenderer.isEnabled()) {
+                if (!info.mHardwareRenderer.validate()) {
+                    flushLayers = false;
+                }
+            } else {
+                flushLayers = false;
+            }
+
             // We need to invalidate any child with a layer. For instance,
             // if a child is backed by a hardware layer and we disable layers
             // the child is marked as not dirty (flags cleared the last time
@@ -2968,6 +2979,7 @@
             for (int i = 0; i < mChildrenCount; i++) {
                 View child = mChildren[i];
                 if (child.mLayerType != LAYER_TYPE_NONE) {
+                    if (flushLayers) child.flushLayer();
                     child.invalidate(true);
                 }
             }
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 2dd7ddf..7a9d82c 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -2389,8 +2389,6 @@
     public final static int RESIZED_REPORT = 1003;
     public final static int WINDOW_FOCUS_CHANGED = 1004;
     public final static int DISPATCH_KEY = 1005;
-    public final static int DISPATCH_POINTER = 1006;
-    public final static int DISPATCH_TRACKBALL = 1007;
     public final static int DISPATCH_APP_VISIBILITY = 1008;
     public final static int DISPATCH_GET_NEW_SURFACE = 1009;
     public final static int IME_FINISHED_EVENT = 1010;
@@ -2422,10 +2420,6 @@
                 return "WINDOW_FOCUS_CHANGED";
             case DISPATCH_KEY:
                 return "DISPATCH_KEY";
-            case DISPATCH_POINTER:
-                return "DISPATCH_POINTER";
-            case DISPATCH_TRACKBALL:
-                return "DISPATCH_TRACKBALL";
             case DISPATCH_APP_VISIBILITY:
                 return "DISPATCH_APP_VISIBILITY";
             case DISPATCH_GET_NEW_SURFACE:
@@ -2591,6 +2585,10 @@
         case DIE:
             doDie();
             break;
+        case DISPATCH_KEY: {
+            KeyEvent event = (KeyEvent)msg.obj;
+            enqueueInputEvent(event, null, 0);
+        } break;
         case DISPATCH_KEY_FROM_IME: {
             if (LOCAL_LOGV) Log.v(
                 TAG, "Dispatching key "
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 4958d3c..b68dec9 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -4250,6 +4250,9 @@
 
     @Override
     protected void onDraw(Canvas canvas) {
+        if (inFullScreenMode()) {
+            return; // no need to draw anything if we aren't visible.
+        }
         // if mNativeClass is 0, the WebView is either destroyed or not
         // initialized. In either case, just draw the background color and return
         if (mNativeClass == 0) {
@@ -5833,7 +5836,8 @@
         }
         calcOurContentVisibleRectF(mVisibleContentRect);
         nativeUpdateDrawGLFunction(mGLViewportEmpty ? null : mGLRectViewport,
-                mGLViewportEmpty ? null : mViewRectViewport, mVisibleContentRect);
+                mGLViewportEmpty ? null : mViewRectViewport,
+                mVisibleContentRect);
     }
 
     /**
@@ -5980,6 +5984,7 @@
         if (inFullScreenMode()) {
             mFullScreenHolder.hide();
             mFullScreenHolder = null;
+            invalidate();
         }
     }
 
@@ -8655,6 +8660,7 @@
                     mFullScreenHolder = new PluginFullScreenHolder(WebView.this, orientation, npp);
                     mFullScreenHolder.setContentView(view);
                     mFullScreenHolder.show();
+                    invalidate();
 
                     break;
                 }
diff --git a/core/java/android/widget/SpellChecker.java b/core/java/android/widget/SpellChecker.java
index d03db10..4bd7165 100644
--- a/core/java/android/widget/SpellChecker.java
+++ b/core/java/android/widget/SpellChecker.java
@@ -272,9 +272,11 @@
                             ((attributes & SuggestionsInfo.RESULT_ATTR_LOOKS_LIKE_TYPO) > 0);
 
                     SpellCheckSpan spellCheckSpan = mSpellCheckSpans[j];
+
                     if (!isInDictionary && looksLikeTypo) {
                         createMisspelledSuggestionSpan(editable, suggestionsInfo, spellCheckSpan);
                     }
+
                     editable.removeSpan(spellCheckSpan);
                     break;
                 }
@@ -295,20 +297,21 @@
         }, SPELL_PAUSE_DURATION);
     }
 
-    private void createMisspelledSuggestionSpan(Editable editable,
-            SuggestionsInfo suggestionsInfo, SpellCheckSpan spellCheckSpan) {
+    private void createMisspelledSuggestionSpan(Editable editable, SuggestionsInfo suggestionsInfo,
+            SpellCheckSpan spellCheckSpan) {
         final int start = editable.getSpanStart(spellCheckSpan);
         final int end = editable.getSpanEnd(spellCheckSpan);
-        if (start < 0 || end < 0) return; // span was removed in the meantime
+        if (start < 0 || end <= start) return; // span was removed in the meantime
 
         // Other suggestion spans may exist on that region, with identical suggestions, filter
-        // them out to avoid duplicates. First, filter suggestion spans on that exact region.
+        // them out to avoid duplicates.
         SuggestionSpan[] suggestionSpans = editable.getSpans(start, end, SuggestionSpan.class);
         final int length = suggestionSpans.length;
         for (int i = 0; i < length; i++) {
             final int spanStart = editable.getSpanStart(suggestionSpans[i]);
             final int spanEnd = editable.getSpanEnd(suggestionSpans[i]);
             if (spanStart != start || spanEnd != end) {
+                // Nulled (to avoid new array allocation) if not on that exact same region
                 suggestionSpans[i] = null;
             }
         }
@@ -355,6 +358,8 @@
         SuggestionSpan suggestionSpan = new SuggestionSpan(mTextView.getContext(), suggestions,
                 SuggestionSpan.FLAG_EASY_CORRECT | SuggestionSpan.FLAG_MISSPELLED);
         editable.setSpan(suggestionSpan, start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
+
+        mTextView.invalidateRegion(start, end);
     }
 
     private class SpellParser {
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 1fab1ca..82bcd3e 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -4326,15 +4326,24 @@
     }
 
     private void invalidateCursor(int a, int b, int c) {
+        if (a >= 0 || b >= 0 || c >= 0) {
+            int start = Math.min(Math.min(a, b), c);
+            int end = Math.max(Math.max(a, b), c);
+            invalidateRegion(start, end);
+        }
+    }
+
+    /**
+     * Invalidates the region of text enclosed between the start and end text offsets.
+     *
+     * @hide
+     */
+    void invalidateRegion(int start, int end) {
         if (mLayout == null) {
             invalidate();
         } else {
-            if (a >= 0 || b >= 0 || c >= 0) {
-                int first = Math.min(Math.min(a, b), c);
-                int last = Math.max(Math.max(a, b), c);
-
-                int line = mLayout.getLineForOffset(first);
-                int top = mLayout.getLineTop(line);
+                int lineStart = mLayout.getLineForOffset(start);
+                int top = mLayout.getLineTop(lineStart);
 
                 // This is ridiculous, but the descent from the line above
                 // can hang down into the line we really want to redraw,
@@ -4342,36 +4351,36 @@
                 // sure everything that needs to be redrawn really is.
                 // (But not the whole line above, because that would cause
                 // the same problem with the descenders on the line above it!)
-                if (line > 0) {
-                    top -= mLayout.getLineDescent(line - 1);
+                if (lineStart > 0) {
+                    top -= mLayout.getLineDescent(lineStart - 1);
                 }
 
-                int line2;
+                int lineEnd;
 
-                if (first == last)
-                    line2 = line;
+                if (start == end)
+                    lineEnd = lineStart;
                 else
-                    line2 = mLayout.getLineForOffset(last);
+                    lineEnd = mLayout.getLineForOffset(end);
 
-                int bottom = mLayout.getLineTop(line2 + 1);
+                int bottom = mLayout.getLineBottom(lineEnd);
 
-                final int horizontalPadding = getCompoundPaddingLeft();
+                final int compoundPaddingLeft = getCompoundPaddingLeft();
                 final int verticalPadding = getExtendedPaddingTop() + getVerticalOffset(true);
-                
-                // If used, the cursor drawables can have an arbitrary dimension that can go beyond
-                // the invalidated lines specified above.
-                for (int i = 0; i < mCursorCount; i++) {
-                    Rect bounds = mCursorDrawable[i].getBounds();
-                    top = Math.min(top, bounds.top);
-                    bottom = Math.max(bottom, bounds.bottom);
-                    // Horizontal bounds are already full width, no need to update
+
+                int left, right;
+                if (lineStart == lineEnd) {
+                    left = (int) mLayout.getPrimaryHorizontal(start);
+                    right = (int) (mLayout.getPrimaryHorizontal(end) + 1.0);
+                    left += compoundPaddingLeft;
+                    right += compoundPaddingLeft;
+                } else {
+                    // Rectangle bounding box when the region spans several lines
+                    left = compoundPaddingLeft;
+                    right = getWidth() - getCompoundPaddingRight();
                 }
 
-                invalidate(horizontalPadding + mScrollX, top + verticalPadding,
-                        horizontalPadding + mScrollX + getWidth() -
-                        getCompoundPaddingLeft() - getCompoundPaddingRight(),
-                        bottom + verticalPadding);
-            }
+                invalidate(mScrollX + left, verticalPadding + top,
+                        mScrollX + right, verticalPadding + bottom);
         }
     }
 
@@ -5904,10 +5913,10 @@
                 if (cursorOffsetVertical != 0) {
                     canvas.translate(0, -cursorOffsetVertical);
                 }
-                invalidate(true);
+                invalidate(true); // TODO invalidate cursor region only
             } else {
                 stopAnimation();
-                invalidate(false);
+                invalidate(false); // TODO invalidate cursor region only
             }
         }
 
@@ -7729,10 +7738,8 @@
                 onSelectionChanged(newSelStart, newSelEnd);
             }
         }
-        
-        if (what instanceof UpdateAppearance || what instanceof ParagraphStyle
-                || (what instanceof SuggestionSpan && (((SuggestionSpan)what).getFlags()
-                        & SuggestionSpan.FLAG_AUTO_CORRECTION) != 0)) {
+
+        if (what instanceof UpdateAppearance || what instanceof ParagraphStyle) {
             if (ims == null || ims.mBatchEditNesting == 0) {
                 invalidate();
                 mHighlightPathBogus = true;
diff --git a/core/jni/android_view_GLES20Canvas.cpp b/core/jni/android_view_GLES20Canvas.cpp
index 426f4f7..9c7b108 100644
--- a/core/jni/android_view_GLES20Canvas.cpp
+++ b/core/jni/android_view_GLES20Canvas.cpp
@@ -719,6 +719,10 @@
     LayerRenderer::destroyLayerDeferred(layer);
 }
 
+static void android_view_GLES20Canvas_flushLayer(JNIEnv* env, jobject clazz, Layer* layer) {
+    LayerRenderer::flushLayer(layer);
+}
+
 static void android_view_GLES20Canvas_drawLayer(JNIEnv* env, jobject clazz,
         OpenGLRenderer* renderer, Layer* layer, jfloat x, jfloat y, SkPaint* paint) {
     renderer->drawLayer(layer, x, y, paint);
@@ -869,6 +873,7 @@
     { "nSetTextureLayerTransform", "(II)V",    (void*) android_view_GLES20Canvas_setTextureLayerTransform },
     { "nDestroyLayer",           "(I)V",       (void*) android_view_GLES20Canvas_destroyLayer },
     { "nDestroyLayerDeferred",   "(I)V",       (void*) android_view_GLES20Canvas_destroyLayerDeferred },
+    { "nFlushLayer",             "(I)V",       (void*) android_view_GLES20Canvas_flushLayer },
     { "nDrawLayer",              "(IIFFI)V",   (void*) android_view_GLES20Canvas_drawLayer },
     { "nCopyLayer",              "(II)Z",      (void*) android_view_GLES20Canvas_copyLayer },
 
diff --git a/packages/SystemUI/res/drawable/ic_sysbar_back_ime.xml b/core/res/res/drawable/silent_mode_indicator.xml
similarity index 74%
rename from packages/SystemUI/res/drawable/ic_sysbar_back_ime.xml
rename to core/res/res/drawable/silent_mode_indicator.xml
index 248496d..c4e129f 100644
--- a/packages/SystemUI/res/drawable/ic_sysbar_back_ime.xml
+++ b/core/res/res/drawable/silent_mode_indicator.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2008 The Android Open Source Project
+<!-- 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.
@@ -15,7 +15,6 @@
 -->
 
 <selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:state_pressed="true" android:drawable="@drawable/ic_sysbar_back_ime_pressed" />
-    <item android:drawable="@drawable/ic_sysbar_back_ime_default" />
+    <item android:state_selected="false" android:drawable="@android:color/transparent" />
+    <item android:state_selected="true"  android:drawable="@drawable/tab_selected_holo" />
 </selector>
-
diff --git a/core/res/res/layout/global_actions_item.xml b/core/res/res/layout/global_actions_item.xml
index 13ab985..694301e 100644
--- a/core/res/res/layout/global_actions_item.xml
+++ b/core/res/res/layout/global_actions_item.xml
@@ -22,7 +22,7 @@
     android:minHeight="?android:attr/listPreferredItemHeight"
     android:orientation="horizontal"
 
-    android:paddingLeft="11dip"
+    android:paddingLeft="16dip"
     android:paddingTop="6dip"
     android:paddingBottom="6dip"
     >
@@ -30,7 +30,7 @@
         android:layout_width="wrap_content"
         android:layout_height="match_parent"
         android:layout_gravity="center"
-        android:layout_marginRight="9dip"
+        android:layout_marginRight="16dip"
         />
 
     <LinearLayout
diff --git a/core/res/res/layout/global_actions_silent_mode.xml b/core/res/res/layout/global_actions_silent_mode.xml
new file mode 100644
index 0000000..09b4341
--- /dev/null
+++ b/core/res/res/layout/global_actions_silent_mode.xml
@@ -0,0 +1,97 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="wrap_content"
+    android:layout_height="wrap_content"
+    android:minHeight="?android:attr/listPreferredItemHeight"
+    android:orientation="horizontal"
+    >
+
+    <LinearLayout
+        android:id="@+id/option1"
+        android:layout_width="64dp"
+        android:layout_height="match_parent"
+        android:background="?android:attr/actionBarItemBackground"
+        >
+        <ImageView
+            android:layout_width="48dp"
+            android:layout_height="match_parent"
+            android:layout_gravity="center"
+            android:layout_marginLeft="8dp"
+            android:layout_marginRight="8dp"
+            android:layout_marginTop="6dp"
+            android:layout_marginBottom="6dp"
+            android:src="@drawable/ic_audio_vol_mute"
+            android:scaleType="center"
+            android:duplicateParentState="true"
+            android:background="@drawable/silent_mode_indicator"
+            />
+    </LinearLayout>
+    <!-- Spacer -->
+    <View android:layout_width="0dp"
+        android:layout_height="match_parent"
+        android:layout_weight="1"
+        android:visibility="invisible"/>
+
+    <LinearLayout
+        android:id="@+id/option2"
+        android:layout_width="64dp"
+        android:layout_height="match_parent"
+        android:background="?android:attr/actionBarItemBackground"
+        >
+        <ImageView
+            android:layout_width="48dp"
+            android:layout_height="match_parent"
+            android:layout_gravity="center"
+            android:layout_marginLeft="8dp"
+            android:layout_marginRight="8dp"
+            android:layout_marginTop="6dp"
+            android:layout_marginBottom="6dp"
+            android:src="@drawable/ic_audio_ring_notif_vibrate"
+            android:scaleType="center"
+            android:duplicateParentState="true"
+            android:background="@drawable/silent_mode_indicator"
+            />
+    </LinearLayout>
+
+    <!-- Spacer -->
+    <View android:layout_width="0dp"
+        android:layout_height="match_parent"
+        android:layout_weight="1"
+        android:visibility="invisible"/>
+
+    <LinearLayout
+        android:id="@+id/option3"
+        android:layout_width="64dp"
+        android:layout_height="match_parent"
+        android:background="?android:attr/actionBarItemBackground"
+        >
+        <ImageView
+            android:layout_width="48dp"
+            android:layout_height="match_parent"
+            android:layout_gravity="center"
+            android:layout_marginLeft="8dp"
+            android:layout_marginRight="8dp"
+            android:layout_marginTop="6dp"
+            android:layout_marginBottom="6dp"
+            android:src="@drawable/ic_audio_vol"
+            android:scaleType="center"
+            android:duplicateParentState="true"
+            android:background="@drawable/silent_mode_indicator"
+            />
+    </LinearLayout>
+</LinearLayout>
\ No newline at end of file
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 326f186..c342c20 100755
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -747,4 +747,9 @@
 
     <!-- Name of screensaver components to look for if none has been chosen by the user -->
     <string name="config_defaultDreamComponent">com.google.android.deskclock/com.android.deskclock.Screensaver</string>
+
+    <!-- Base "touch slop" value used by ViewConfiguration as a
+         movement threshold where scrolling should begin. -->
+    <dimen name="config_viewConfigurationTouchSlop">4dp</dimen>
+
 </resources>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 5219fcc..7ad1d53 100755
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -143,15 +143,15 @@
     <!-- Displayed to tell the user that normal service is blocked by access control. -->
     <string name="RestrictedOnNormal">Voice service is blocked.</string>
     <!-- Displayed to tell the user that all emergency and normal voice services are blocked by access control. -->
-    <string name="RestrictedOnAllVoice">All Voice services are blocked.</string>
+    <string name="RestrictedOnAllVoice">All voice services are blocked.</string>
     <!-- Displayed to tell the user that sms service is blocked by access control. -->
     <string name="RestrictedOnSms">SMS service is blocked.</string>
     <!-- Displayed to tell the user that voice/data service is blocked by access control. -->
-    <string name="RestrictedOnVoiceData">Voice/Data services are blocked.</string>
+    <string name="RestrictedOnVoiceData">Voice/data services are blocked.</string>
     <!-- Displayed to tell the user that voice and sms service are blocked by access control. -->
     <string name="RestrictedOnVoiceSms">Voice/SMS services are blocked.</string>
     <!-- Displayed to tell the user that all service is blocked by access control. -->
-    <string name="RestrictedOnAll">All Voice/Data/SMS services are blocked.</string>
+    <string name="RestrictedOnAll">All voice/data/SMS services are blocked.</string>
 
     <!-- Mappings between TS 27.007 +CFCC/+CLCK "service classes" and human-readable strings--> <skip />
     <!-- Example: Service was enabled for: Voice, Data -->
@@ -217,19 +217,19 @@
     <!-- Displayed when a web request was successful. -->
     <string name="httpErrorOk">OK</string>
     <!-- Displayed when a web request failed with a generic network error. -->
-    <string name="httpError">A network error occurred.</string>
+    <string name="httpError">There was a network error.</string>
     <!-- Displayed when a web request failed because the URL could not be found. -->
-    <string name="httpErrorLookup">The URL could not be found.</string>
+    <string name="httpErrorLookup">Couldn\'t find the URL.</string>
     <!-- Displayed when a web request failed because the site's authentication scheme is not supported by us. -->
     <string name="httpErrorUnsupportedAuthScheme">The site authentication scheme isn\'t supported.</string>
     <!-- Displayed when a web request failed because the authentication failed. -->
-    <string name="httpErrorAuth">Authentication was unsuccessful.</string>
+    <string name="httpErrorAuth">Couldn\'t authenticate.</string>
     <!-- Displayed when a web request failed because the authentication with the proxy failed. -->
     <string name="httpErrorProxyAuth">Authentication via the proxy server was unsuccessful.</string>
     <!-- Displayed when a web request failed because there was a connection error. -->
-    <string name="httpErrorConnect">The connection to the server was unsuccessful.</string>
+    <string name="httpErrorConnect">Couldn\'t connect to the server.</string>
     <!-- Displayed when a web request failed because there was an input or output error. -->
-    <string name="httpErrorIO">The server couldn\'t communicate. Try again later.</string>
+    <string name="httpErrorIO">Couldn\'t communicate with the server. Try again later.</string>
     <!-- Displayed when a web request failed because the request timed out -->
     <string name="httpErrorTimeout">The connection to the server timed out.</string>
     <!-- Displayed when a web request failed because the site tried to redirect us one too many times -->
@@ -237,13 +237,13 @@
     <!-- Displayed when a web request failed because the protocol of the server is not supported. -->
     <string name="httpErrorUnsupportedScheme">The protocol isn\'t supported.</string>
     <!-- Displayed when a web request failed because the a secure connection couldn't be made to the server.-->
-    <string name="httpErrorFailedSslHandshake">A secure connection could not be established.</string>
+    <string name="httpErrorFailedSslHandshake">Couldn\'t establish a secure connection.</string>
     <!-- Displayed when a web request failed because the URL isn't in a valid form. -->
-    <string name="httpErrorBadUrl">The page could not be opened because the URL is invalid.</string>
+    <string name="httpErrorBadUrl">Couldn\'t open the page because the URL is invalid.</string>
     <!-- Displayed when a request failed because we failed to open the file. -->
-    <string name="httpErrorFile">The file could not be accessed.</string>
+    <string name="httpErrorFile">Couldn\'t access the file.</string>
     <!-- Displayed when a request failed because the file wasn't found. -->
-    <string name="httpErrorFileNotFound">The requested file was not found.</string>
+    <string name="httpErrorFileNotFound">Couldn\'t find the requested file.</string>
     <!-- Displayed when a request failed because there are too many requests right now. -->
     <string name="httpErrorTooManyRequests">Too many requests are being processed. Try again later.</string>
 
@@ -252,7 +252,7 @@
     supply an auth token without prompting the user to re-enter the
     password.  This is the text that will scroll through the
     notification bar (will be seen by the user as he uses another application). -->
-    <string name="notification_title">Sign-in error for <xliff:g id="account" example="foo@gmail.com">%1$s</xliff:g></string>
+    <string name="notification_title">Signin error for <xliff:g id="account" example="foo@gmail.com">%1$s</xliff:g></string>
 
     <!-- Sync notifications --> <skip />
     <!-- A notification is shown when there is a sync error.  This is the text that will scroll through the notification bar (will be seen by the user as he uses another application). -->
@@ -263,9 +263,9 @@
     <string name="contentServiceTooManyDeletesNotificationDesc">Too many <xliff:g id="content_type">%s</xliff:g> deletes.</string>
 
     <!-- If MMS discovers there isn't much space left on the device, it will show a toast with this message. -->
-    <string name="low_memory" product="tablet">Tablet storage is full! Delete some files to free space.</string>
+    <string name="low_memory" product="tablet">Tablet storage is full. Delete some files to free space.</string>
     <!-- If MMS discovers there isn't much space left on the device, it will show a toast with this message. -->
-    <string name="low_memory" product="default">Phone storage is full! Delete some files to free space.</string>
+    <string name="low_memory" product="default">Phone storage is full. Delete some files to free space.</string>
 
 
     <!-- Display name for any time a piece of data refers to the owner of the phone. For example, this could be used in place of the phone's phone number. -->
@@ -359,8 +359,7 @@
     <!-- Title of a category of application permissions, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permgrouplab_costMoney">Services that cost you money</string>
     <!-- Description of a category of application permissions, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permgroupdesc_costMoney">Allow apps to do things
-        that can cost you money.</string>
+    <string name="permgroupdesc_costMoney">Do things that can cost you money.</string>
 
     <!-- Title of a category of application permissions, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permgrouplab_messages">Your messages</string>
@@ -379,12 +378,12 @@
     <!-- Title of a category of application permissions, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permgrouplab_location">Your location</string>
     <!-- Description of a category of application permissions, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permgroupdesc_location">Monitor your physical location</string>
+    <string name="permgroupdesc_location">Monitor your physical location.</string>
 
     <!-- Title of a category of application permissions, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permgrouplab_network">Network communication</string>
     <!-- Description of a category of application permissions, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permgroupdesc_network">Allow apps to access various network features.</string>
+    <string name="permgroupdesc_network">Access various network features.</string>
 
     <!-- Title of a category of application permissions, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permgrouplab_accounts">Your accounts</string>
@@ -433,8 +432,7 @@
     <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_expandStatusBar">expand/collapse status bar</string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_expandStatusBar">Allows the app to
-        expand or collapse the status bar.</string>
+    <string name="permdesc_expandStatusBar">Allows the app to expand or collapse the status bar.</string>
 
     <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_processOutgoingCalls">intercept outgoing calls</string>
@@ -524,21 +522,21 @@
     <!-- Title of an application permission, allowing an application to remove/kill tasks -->
     <string name="permlab_removeTasks">stop running apps</string>
     <!-- Description of an application permission, allowing an application to remove/kill tasks -->
-    <string name="permdesc_removeTasks">Allows an app to remove
+    <string name="permdesc_removeTasks">Allows the app to remove
         tasks and kill their apps. Malicious apps may disrupt
         the behavior of other apps.</string>
 
     <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_setDebugApp">enable app debugging</string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_setDebugApp">Allows an app to turn
+    <string name="permdesc_setDebugApp">Allows the app to turn
         on debugging for another app. Malicious apps may use this
         to kill other apps.</string>
 
     <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_changeConfiguration">change your UI settings</string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_changeConfiguration">Allows an app to
+    <string name="permdesc_changeConfiguration">Allows the app to
         change the current configuration, such as the locale or overall font
         size.</string>
 
@@ -659,7 +657,7 @@
     <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_internalSystemWindow">display unauthorized windows</string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_internalSystemWindow">Allows an app to create 
+    <string name="permdesc_internalSystemWindow">Allows the app to create
         windows that are intended to be used by the internal system
         user interface. Not for use by normal apps.</string>
 
@@ -673,7 +671,7 @@
     <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_setAnimationScale">modify global animation speed</string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_setAnimationScale">Allows an app to change
+    <string name="permdesc_setAnimationScale">Allows the app to change
         the global animation speed (faster or slower animations) at any time.</string>
 
     <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
@@ -824,7 +822,7 @@
     <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_anyCodecForPlayback">use any media decoder for playback</string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_anyCodecForPlayback">Allows an application to use any installed
+    <string name="permdesc_anyCodecForPlayback">Allows the app to use any installed
         media decoder to decode for playback.</string>
 
     <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
@@ -1017,26 +1015,22 @@
     <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_accessSurfaceFlinger">access SurfaceFlinger</string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_accessSurfaceFlinger">Allows the app to use
-        SurfaceFlinger low-level features.</string>
+    <string name="permdesc_accessSurfaceFlinger">Allows the app to use SurfaceFlinger low-level features.</string>
 
     <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_readFrameBuffer">read frame buffer</string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_readFrameBuffer">Allows the app to
-        read the content of the frame buffer.</string>
+    <string name="permdesc_readFrameBuffer">Allows the app to read the content of the frame buffer.</string>
 
     <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_modifyAudioSettings">change your audio settings</string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_modifyAudioSettings">Allows the app to modify
-        global audio settings such as volume and routing.</string>
+    <string name="permdesc_modifyAudioSettings">Allows the app to modify global audio settings such as volume and routing.</string>
 
     <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_recordAudio">record audio</string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_recordAudio">Allows the app to access
-        the audio record path.</string>
+    <string name="permdesc_recordAudio">Allows the app to access the audio record path.</string>
 
     <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_camera">take pictures and videos</string>
@@ -1061,11 +1055,9 @@
     <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_reboot" product="default">force phone reboot</string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_reboot" product="tablet">Allows the app to
-        force the tablet to reboot.</string>
+    <string name="permdesc_reboot" product="tablet">Allows the app to force the tablet to reboot.</string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_reboot" product="default">Allows the app to
-        force the phone to reboot.</string>
+    <string name="permdesc_reboot" product="default">Allows the app to force the phone to reboot.</string>
 
     <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_mount_unmount_filesystems">mount and unmount filesystems</string>
@@ -1106,14 +1098,12 @@
     <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_vibrate">control vibrator</string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_vibrate">Allows the app to control
-        the vibrator.</string>
+    <string name="permdesc_vibrate">Allows the app to control the vibrator.</string>
 
     <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_flashlight">control flashlight</string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_flashlight">Allows the app to control
-        the flashlight.</string>
+    <string name="permdesc_flashlight">Allows the app to control the flashlight.</string>
 
     <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_manageUsb">manage preferences and permissions for USB devices</string>
@@ -1197,11 +1187,9 @@
     <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_wakeLock" product="default">prevent phone from sleeping</string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_wakeLock" product="tablet">Allows the app to prevent
-        the tablet from going to sleep.</string>
+    <string name="permdesc_wakeLock" product="tablet">Allows the app to prevent the tablet from going to sleep.</string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_wakeLock" product="default">Allows the app to prevent
-        the phone from going to sleep.</string>
+    <string name="permdesc_wakeLock" product="default">Allows the app to prevent the phone from going to sleep.</string>
 
     <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_devicePower" product="tablet">power tablet on or off</string>
@@ -1211,8 +1199,7 @@
     <string name="permdesc_devicePower" product="tablet">Allows the app to turn the
         tablet on or off.</string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_devicePower" product="default">Allows the app to turn the
-        phone on or off.</string>
+    <string name="permdesc_devicePower" product="default">Allows the app to turn the phone on or off.</string>
 
     <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_factoryTest">run in factory test mode</string>
@@ -1259,16 +1246,14 @@
     <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_accountManagerService">act as the AccountManagerService</string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_accountManagerService">Allows an app to make calls to AccountAuthenticators.</string>
+    <string name="permdesc_accountManagerService">Allows the app to make calls to AccountAuthenticators.</string>
 
     <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_getAccounts">discover known accounts</string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_getAccounts" product="tablet">Allows the app to get
-      the list of accounts known by the tablet.</string>
+    <string name="permdesc_getAccounts" product="tablet">Allows the app to get the list of accounts known by the tablet.</string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_getAccounts" product="default">Allows the app to get
-      the list of accounts known by the phone.</string>
+    <string name="permdesc_getAccounts" product="default">Allows the app to get the list of accounts known by the phone.</string>
 
     <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_authenticateAccounts">act as an account authenticator</string>
@@ -1352,11 +1337,9 @@
       the local Bluetooth phone, and to discover and pair with remote devices.</string>
 
     <string name="permlab_accessWimaxState">View WiMAX state</string>
-    <string name="permdesc_accessWimaxState">Allows an application to view
-      the information about the state of WiMAX.</string>
+    <string name="permdesc_accessWimaxState">Allows the app to view the information about the state of WiMAX.</string>
     <string name="permlab_changeWimaxState">Change WiMAX state</string>
-    <string name="permdesc_changeWimaxState">Allows an application to connect
-      to and disconnect from WiMAX network.</string>
+    <string name="permdesc_changeWimaxState">Allows the app to connect to and disconnect from WiMAX network.</string>
 
     <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_bluetooth">create Bluetooth connections</string>
@@ -1461,14 +1444,14 @@
     <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_modifyNetworkAccounting">modify network usage accounting</string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_modifyNetworkAccounting">Allows an app to modify how network usage is accounted against apps. Not for use by normal apps.</string>
+    <string name="permdesc_modifyNetworkAccounting">Allows the app to modify how network usage is accounted against apps. Not for use by normal apps.</string>
 
     <!-- Policy administration -->
 
     <!-- Title of policy access to limiting the user's password choices -->
     <string name="policylab_limitPassword">Set password rules</string>
     <!-- Description of policy access to limiting the user's password choices -->
-    <string name="policydesc_limitPassword">Control the length and the characters allowed in screen-unlock passwords</string>
+    <string name="policydesc_limitPassword">Control the length and the characters allowed in screen-unlock passwords.</string>
     <!-- Title of policy access to watch user login attempts -->
     <string name="policylab_watchLogin">Monitor screen-unlock attempts</string>
     <!-- Description of policy access to watch user login attempts -->
@@ -1482,19 +1465,17 @@
     <!-- Title of policy access to reset user's password -->
     <string name="policylab_resetPassword">Change the screen-unlock password</string>
     <!-- Description of policy access to reset user's password -->
-    <string name="policydesc_resetPassword">Change the screen-unlock password</string>
+    <string name="policydesc_resetPassword">Change the screen-unlock password.</string>
     <!-- Title of policy access to force lock the device -->
     <string name="policylab_forceLock">Lock the screen</string>
     <!-- Description of policy access to limiting the user's password choices -->
-    <string name="policydesc_forceLock">Control how and when the screen locks</string>
+    <string name="policydesc_forceLock">Control how and when the screen locks.</string>
     <!-- Title of policy access to wipe the user's data -->
     <string name="policylab_wipeData">Erase all data</string>
     <!-- Description of policy access to wipe the user's data -->
-    <string name="policydesc_wipeData" product="tablet">Erase the tablet\'s data without warning,
-    by performing a factory data reset</string>
+    <string name="policydesc_wipeData" product="tablet">Erase the tablet\'s data without warning by performing a factory data reset.</string>
     <!-- Description of policy access to wipe the user's data -->
-    <string name="policydesc_wipeData" product="default">Erase the phone\'s data without warning,
-    by performing a factory data reset</string>
+    <string name="policydesc_wipeData" product="default">Erase the phone\'s data without warning by performing a factory data reset.</string>
     <string name="policylab_setGlobalProxy">Set the device global proxy</string>
     <!-- Description of policy access to wipe the user's data -->
     <string name="policydesc_setGlobalProxy">Set the device global proxy
@@ -1503,17 +1484,15 @@
     <!-- Title of policy access to enforce password expiration [CHAR LIMIT=30]-->
     <string name="policylab_expirePassword">Set lock-screen password expiration</string>
     <!-- Description of policy access to enforce password expiration [CHAR LIMIT=110]-->
-    <string name="policydesc_expirePassword">Control how frequently the lock-screen password must be
-  changed</string>
+    <string name="policydesc_expirePassword">Control how frequently the lock-screen password must be changed.</string>
     <!-- Title of policy access to require encrypted storage [CHAR LIMIT=30]-->
     <string name="policylab_encryptedStorage">Set storage encryption</string>
     <!-- Description of policy access to require encrypted storage [CHAR LIMIT=110]-->
-    <string name="policydesc_encryptedStorage">Require that stored app data be encrypted
-        </string>
+    <string name="policydesc_encryptedStorage">Require that stored app data be encrypted.</string>
     <!-- Title of policy access to disable all device cameras [CHAR LIMIT=30]-->
     <string name="policylab_disableCamera">Disable cameras</string>
     <!-- Description of policy access to disable all device cameras [CHAR LIMIT=110]-->
-    <string name="policydesc_disableCamera">Prevent use of all device cameras</string>
+    <string name="policydesc_disableCamera">Prevent use of all device cameras.</string>
 
     <!-- The order of these is important, don't reorder without changing Contacts.java --> <skip />
     <!-- Phone number types from android.provider.Contacts. This could be used when adding a new phone number for a contact, for example. -->
@@ -1751,7 +1730,7 @@
 
     <!-- Instructions telling the user that they entered the wrong pin while trying
          to unlock the keyguard.  Displayed in one line in a large font.  -->
-    <string name="keyguard_password_wrong_pin_code">Incorrect PIN code!</string>
+    <string name="keyguard_password_wrong_pin_code">Incorrect PIN code.</string>
 
     <!-- Instructions telling the user how to unlock the phone. -->
     <string name="keyguard_label_text">To unlock, press Menu then 0.</string>
@@ -1932,9 +1911,9 @@
     <string name="lockscreen_glogin_forgot_pattern">Account unlock</string>
     <!-- Title of the unlock screen that uses your Google login and password when the user attempted
          too many patterns and we are forcing them to use their account instead. -->
-    <string name="lockscreen_glogin_too_many_attempts">Too many pattern attempts!</string>
+    <string name="lockscreen_glogin_too_many_attempts">Too many pattern attempts</string>
     <!-- In the unlock screen, message telling the user that they need to use their Google login and password to unlock the phone -->
-    <string name="lockscreen_glogin_instructions">To unlock, sign in with your Google account</string>
+    <string name="lockscreen_glogin_instructions">To unlock, sign in with your Google account.</string>
     <!-- Hint caption for the username field when unlocking the phone using login and password -->
     <string name="lockscreen_glogin_username_hint">Username (email)</string>
     <!-- Hint caption for the password field when unlocking the phone using login and password -->
@@ -1944,10 +1923,10 @@
     <!-- Displayed to the user when unlocking the phone with a username and password fails. -->
     <string name="lockscreen_glogin_invalid_input">Invalid username or password.</string>
     <!-- Hint displayed on account unlock screen to advise the user on how to recover the account. -->
-    <string name="lockscreen_glogin_account_recovery_hint">Forgot your username or password\?\nVisit <b>google.com/accounts/recovery</b></string>
+    <string name="lockscreen_glogin_account_recovery_hint">Forgot your username or password\?\nVisit <b>google.com/accounts/recovery</b>.</string>
 
     <!-- Displayed in a progress dialog while a username and password are being checked. -->
-    <string name="lockscreen_glogin_checking_password">Checking...</string>
+    <string name="lockscreen_glogin_checking_password">Checking\u2026</string>
     <!-- Displayed on lock screen's left tab - unlock -->
     <string name="lockscreen_unlock_label">Unlock</string>
     <!-- Displayed on lock screen's right tab - turn sound on -->
@@ -1996,7 +1975,7 @@
     <string name="web_user_agent_target_content" translatable="false">"Mobile "</string>
 
     <!-- Title for a JavaScript dialog. "The page at <url of current page> says:" -->
-    <string name="js_dialog_title">The page at \'<xliff:g id="title">%s</xliff:g>\' says:</string>
+    <string name="js_dialog_title">The page at \"<xliff:g id="title">%s</xliff:g>\" says:</string>
     <!-- Default title for a javascript dialog -->
     <string name="js_dialog_title_default">JavaScript</string>
     <!-- Message in a javascript dialog asking if the user wishes to leave the
@@ -2010,9 +1989,9 @@
     <string name="double_tap_toast">Tip: Double-touch to zoom in and out.</string>
 
     <!-- Text to show in the auto complete drop down list on a text view when the WebView can auto fill the entire form, and the user has configured an AutoFill profile [CHAR-LIMIT=8] -->
-    <string name="autofill_this_form">AutoFill</string>
+    <string name="autofill_this_form">Autofill</string>
     <!-- Text to show in the auto complete drop down list on a text view when the WebView can auto fill the entire form but the user has not configured an AutoFill profile [CHAR-LIMIT=16] -->
-    <string name="setup_autofill">Setup AutoFill</string>
+    <string name="setup_autofill">Set up Autofill</string>
 
     <!-- String used to separate FirstName and LastName when writing out a local name
          e.g. John<separator>Smith [CHAR-LIMIT=NONE]-->
@@ -2439,11 +2418,11 @@
 
 
     <!-- Title for error alert when a video cannot be played.  it can be used by any app. -->
-    <string name="VideoView_error_title">Can\'t play video</string>
+    <string name="VideoView_error_title">Video problem</string>
     <!-- Text for error alert when a video container is not valid for progressive download/playback. -->
     <string name="VideoView_error_text_invalid_progressive_playback">This video isn\'t valid for streaming to this device.</string>
     <!-- Text for error alert when a video cannot be played. it can be used by any app. -->
-    <string name="VideoView_error_text_unknown">This video can\'t be played.</string>
+    <string name="VideoView_error_text_unknown">Can\'t play this video.</string>
     <!-- Button to close error alert when a video cannot be played -->
     <string name="VideoView_error_button">OK</string>
 
@@ -2554,7 +2533,7 @@
     <!-- Text displayed when the user selects the check box for setting default application.  See the "Use by default for this action" check box. -->
     <string name="clearDefaultHintMsg">Clear default in System settings &gt; Apps &gt; Downloaded.</string>
     <!-- Default title for the activity chooser, when one is not given. Android allows multiple activities to perform an action.  for example, there may be many ringtone pickers installed.  A dialog is shown to the user allowing him to pick which activity should be used.  This is the title. -->
-    <string name="chooseActivity">Select an action</string>
+    <string name="chooseActivity">Choose an action</string>
     <!-- title for the USB activity chooser. -->
     <string name="chooseUsbActivity">Choose an app for the USB device</string>
     <!-- Text to display when there are no activities found to display in the
@@ -2640,7 +2619,7 @@
          is to be sent to another application. For example, I can send
          text through SMS or IM.  A dialog with those choices would be shown,
          and this would be the title. -->
-    <string name="sendText">Select an action for text</string>
+    <string name="sendText">Choose an action for text</string>
 
     <!-- Title of the dialog where the user is adjusting the phone ringer volume -->
     <string name="volume_ringtone">Ringer volume</string>
@@ -2649,7 +2628,7 @@
     <!-- Hint shown in the volume toast to inform the user that the media audio is playing through Bluetooth. -->
     <string name="volume_music_hint_playing_through_bluetooth">Playing through Bluetooth</string>
     <!-- Hint shown in the volume toast to inform the user that the current ringtone is the silent ringtone. -->
-    <string name="volume_music_hint_silent_ringtone_selected">Silent ringtone selected</string>
+    <string name="volume_music_hint_silent_ringtone_selected">Silent ringtone set</string>
     <!-- Title of the dialog where the user is adjusting the phone call volume -->
     <string name="volume_call">In-call volume</string>
     <!-- Title of the dialog where the user is adjusting the phone call volume when connected on bluetooth-->
@@ -2696,7 +2675,7 @@
     </plurals>
 
     <!-- A notification is shown when a captive portal network is detected.  This is the notification's title. -->
-    <string name="wifi_available_sign_in">Sign in to Wi-Fi network</string>
+    <string name="wifi_available_sign_in">Sign into Wi-Fi network</string>
 
     <!-- A notification is shown when a captive portal network is detected.  This is the notification's message. -->
     <string name="wifi_available_sign_in_detailed"><xliff:g id="wifi_network_ssid">%1$s</xliff:g></string>
@@ -2704,15 +2683,15 @@
      <!-- A notification is shown when a user's selected SSID is later disabled due to connectivity problems.  This is the notification's title / ticker. -->
      <string name="wifi_watchdog_network_disabled">Couldn\'t connect to Wi-Fi</string>
      <!-- A notification is shown when a user's selected SSID is later disabled due to connectivity problems.  The complete alert msg is: <hotspot name> + this string, i.e. "Linksys has a poor internet connection" -->
-    <string name="wifi_watchdog_network_disabled_detailed">\u0020has a poor internet connection.</string>
+    <string name="wifi_watchdog_network_disabled_detailed">\u0020has a poor Internet connection.</string>
 
     <!-- Do not translate. Default access point SSID used for tethering -->
     <string name="wifi_tether_configure_ssid_default" translatable="false">AndroidAP</string>
 
     <!-- Wi-Fi p2p dialog title-->
     <string name="wifi_p2p_dialog_title">Wi-Fi Direct</string>
-    <string name="wifi_p2p_turnon_message">Start Wi-Fi Direct operation. This will turn off Wi-Fi client/hotspot operation.</string>
-    <string name="wifi_p2p_failed_message">Couldn\'t start Wi-Fi Direct</string>
+    <string name="wifi_p2p_turnon_message">Start Wi-Fi Direct. This will turn off Wi-Fi client/hotspot.</string>
+    <string name="wifi_p2p_failed_message">Couldn\'t start Wi-Fi Direct.</string>
 
     <string name="accept">Accept</string>
     <string name="decline">Decline</string>
@@ -2721,7 +2700,7 @@
 
     <string name="wifi_p2p_from_message">From: </string>
     <string name="wifi_p2p_to_message">To: </string>
-    <string name="wifi_p2p_enter_pin_message">Enter the required PIN: </string>
+    <string name="wifi_p2p_enter_pin_message">Type the required PIN: </string>
     <string name="wifi_p2p_show_pin_message">PIN: </string>
 
     <string name="wifi_p2p_enabled_notification_title">Wi-Fi Direct is on</string>
@@ -2752,7 +2731,7 @@
     <!-- See SIM_ADDED_DIALOG.  This is the title of that dialog. -->
     <string name="sim_added_title">SIM card added</string>
     <!-- See SIM_ADDED_DIALOG.  This is the message of that dialog. -->
-    <string name="sim_added_message">You must restart your device to access the mobile network.</string>
+    <string name="sim_added_message">Restart your device to access the mobile network.</string>
     <!-- See SIM_ADDED_DIALOG.  This is the button of that dialog. -->
     <string name="sim_restart_button">Restart</string>
 
@@ -2779,47 +2758,47 @@
 
     <!-- USB storage dialog strings -->
     <!-- This is the title for the activity's window. -->
-    <string name="usb_storage_activity_title">USB Mass Storage</string>
+    <string name="usb_storage_activity_title">USB mass storage</string>
 
     <!-- See USB_STORAGE.  USB_STORAGE_DIALOG:  After the user selects the notification, a dialog is shown asking if he wants to mount.  This is the title. -->
     <string name="usb_storage_title">USB connected</string>
     <!-- See USB_STORAGE.    This is the message. [CHAR LIMIT=NONE] -->
-    <string name="usb_storage_message" product="nosdcard">You have connected to your computer via USB. Touch the button below if you want to copy files between your computer and your Android\u2018s USB storage.</string>
+    <string name="usb_storage_message" product="nosdcard">You\'ve connected to your computer via USB. Touch the button below if you want to copy files between your computer and your Android\'s USB storage.</string>
     <!-- See USB_STORAGE.    This is the message. [CHAR LIMIT=NONE] -->
-    <string name="usb_storage_message" product="default">You have connected to your computer via USB. Touch the button below if you want to copy files between your computer and your Android\u2018s SD card.</string>
+    <string name="usb_storage_message" product="default">You\'ve connected to your computer via USB. Touch the button below if you want to copy files between your computer and your Android\'s SD card.</string>
     <!-- See USB_STORAGE.    This is the button text to mount the phone on the computer. -->
     <string name="usb_storage_button_mount">Turn on USB storage</string>
     <!-- See USB_STORAGE_DIALOG.  If there was an error mounting, this is the text. [CHAR LIMIT=NONE] -->
-    <string name="usb_storage_error_message" product="nosdcard">There is a problem using your USB storage for USB mass storage.</string>
+    <string name="usb_storage_error_message" product="nosdcard">There\'s a problem using your USB storage for USB mass storage.</string>
     <!-- See USB_STORAGE_DIALOG.  If there was an error mounting, this is the text. -->
-    <string name="usb_storage_error_message" product="default">There is a problem using your SD card for USB mass storage.</string>
+    <string name="usb_storage_error_message" product="default">There\'s a problem using your SD card for USB mass storage.</string>
     <!-- USB_STORAGE: When the user connects the phone to a computer via USB, we show a notification asking if he wants to share files across.  This is the title -->
     <string name="usb_storage_notification_title">USB connected</string>
     <!-- See USB_STORAGE. This is the message. -->
-    <string name="usb_storage_notification_message">Select to copy files to/from your computer.</string>
+    <string name="usb_storage_notification_message">Touch to copy files to/from your computer.</string>
 
     <!-- USB_STORAGE_STOP: While USB storage is enabled, we show a notification dialog asking if he wants to stop. This is the title -->
     <string name="usb_storage_stop_notification_title">Turn off USB storage</string>
     <!-- See USB_STORAGE. This is the message. -->
-    <string name="usb_storage_stop_notification_message">Select to turn off USB storage.</string>
+    <string name="usb_storage_stop_notification_message">Touch to turn off USB storage.</string>
 
     <!-- USB storage stop dialog strings -->
     <!-- This is the label for the activity, and should never be visible to the user. -->
     <!-- See USB_STORAGE_STOP.  USB_STORAGE_STOP_DIALOG:  After the user selects the notification, a dialog is shown asking if he wants to stop usb storage.  This is the title. -->
     <string name="usb_storage_stop_title">USB storage in use</string>
     <!-- See USB_STORAGE_STOP.    This is the message. [CHAR LIMIT=NONE] -->
-    <string name="usb_storage_stop_message" product="nosdcard">Before turning off USB storage, make sure you have unmounted (\u201cejected\u201d) your Android\u2018s USB storage from your computer.</string>
+    <string name="usb_storage_stop_message" product="nosdcard">Before turning off USB storage, unmount (\"eject\") your Android\'s USB storage from your computer.</string>
     <!-- See USB_STORAGE_STOP.    This is the message. -->
-    <string name="usb_storage_stop_message" product="default">Before turning off USB storage, make sure you have unmounted (\u201cejected\u201d) your Android\u2018s SD card from your computer.</string>
+    <string name="usb_storage_stop_message" product="default">Before turning off USB storage, unmount (\"eject\") your Android\'s SD card from your computer.</string>
     <!-- See USB_STORAGE_STOP.    This is the button text to stop usb storage. -->
     <string name="usb_storage_stop_button_mount">Turn off USB storage</string>
     <!-- See USB_STORAGE_STOP_DIALOG.  If there was an error stopping, this is the text. -->
-    <string name="usb_storage_stop_error_message">There was a problem turning off USB storage. Check to make sure you have unmounted the USB host, then try again.</string>
+    <string name="usb_storage_stop_error_message">There was a problem turning off USB storage. Check that you\'ve unmounted the USB host, then try again.</string>
 
     <!-- USB_STORAGE_KILL_STORAGE_USERS dialog  -->
     <string name="dlg_confirm_kill_storage_users_title">Turn on USB storage</string>
     <!-- USB_STORAGE_KILL_STORAGE_USERS dialog message text -->
-    <string name="dlg_confirm_kill_storage_users_text">If you turn on USB storage, some apps you are using will stop and may be unavailable until you turn off USB storage.</string>
+    <string name="dlg_confirm_kill_storage_users_text">If you turn on USB storage, some apps you\'re using will stop and may be unavailable until you turn off USB storage.</string>
     <!-- USB_STORAGE_ERROR dialog  dialog-->
     <string name="dlg_error_title">USB operation unsuccessful</string>
     <!-- USB_STORAGE_ERROR dialog  ok button-->
@@ -2834,7 +2813,7 @@
     <!-- USB_PREFERENCES: Notification for when a USB accessory is attached.  This is the title -->
     <string name="usb_accessory_notification_title">Connected to a USB accessory</string>
     <!-- See USB_PREFERENCES. This is the message. -->
-    <string name="usb_notification_message">Touch for other USB options</string>
+    <string name="usb_notification_message">Touch for other USB options.</string>
 
     <!-- External media format dialog strings -->
     <!-- This is the label for the activity, and should never be visible to the user. -->
@@ -2883,16 +2862,16 @@
     <!-- Shown when external media is blank (or unsupported filesystem) -->
     <string name="ext_media_nofs_notification_title" product="default">Blank SD card</string>
     <!-- Shown when USB storage cannot be read.  [CHAR LIMIT=NONE] -->
-    <string name="ext_media_nofs_notification_message" product="nosdcard">USB storage blank or has unsupported filesystem.</string>
-    <string name="ext_media_nofs_notification_message" product="default">SD card blank or has unsupported filesystem.</string>
+    <string name="ext_media_nofs_notification_message" product="nosdcard">USB storage is blank or has unsupported filesystem.</string>
+    <string name="ext_media_nofs_notification_message" product="default">SD card is blank or has unsupported filesystem.</string>
 
     <!-- Shown when external media is unmountable (corrupt)) [CHAR LIMIT=30] -->
     <string name="ext_media_unmountable_notification_title" product="nosdcard">Damaged USB storage</string>
     <!-- Shown when external media is unmountable (corrupt)) -->
     <string name="ext_media_unmountable_notification_title" product="default">Damaged SD card</string>
     <!-- Shown when USB storage cannot be read.  [CHAR LIMIT=NONE] -->
-    <string name="ext_media_unmountable_notification_message" product="nosdcard">USB storage damaged. You may have to reformat it.</string>
-    <string name="ext_media_unmountable_notification_message" product="default">SD card damaged. You may have to reformat it.</string>
+    <string name="ext_media_unmountable_notification_message" product="nosdcard">USB storage is damaged. Try reformatting it.</string>
+    <string name="ext_media_unmountable_notification_message" product="default">SD card is damaged. Try reformatting it.</string>
 
     <!-- Shown when external media is unsafely removed [CHAR LIMIT=30] -->
     <string name="ext_media_badremoval_notification_title" product="nosdcard">USB storage unexpectedly removed</string>
@@ -2919,7 +2898,7 @@
     <string name="ext_media_nomedia_notification_message" product="default">SD card removed. Insert a new one.</string>
 
     <!-- Shown in LauncherActivity when the requested target Intent didn't return any matching Activities, leaving the list empty. -->
-    <string name="activity_list_empty">No matching activities found</string>
+    <string name="activity_list_empty">No matching activities found.</string>
 
     <!-- permission attributes related to package usage statistics -->
     <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
@@ -2939,7 +2918,7 @@
 
     <!-- Shown in gadget hosts (e.g. the home screen) when there was an error inflating
     the gadget. -->
-    <string name="gadget_host_error_inflating">Error inflating widget</string>
+    <string name="gadget_host_error_inflating">Couldn\'t add widget.</string>
 
     <!-- Long label for a button on a full-screen input method for the "Go" action. -->
     <string name="ime_action_go">Go</string>
@@ -2981,11 +2960,11 @@
 
     <string name="grant_credentials_permission_message_header">The following one or more apps request permission to access your account, now and in the future.</string>
     <string name="grant_credentials_permission_message_footer">Do you want to allow this request?</string>
-    <string name="grant_permissions_header_text">Access Request</string>
+    <string name="grant_permissions_header_text">Access request</string>
     <string name="allow">Allow</string>
     <string name="deny">Deny</string>
-    <string name="permission_request_notification_title">Permission Requested</string>
-    <string name="permission_request_notification_with_subtitle">Permission Requested\nfor account <xliff:g id="account" example="foo@gmail.com">%s</xliff:g></string>
+    <string name="permission_request_notification_title">Permission requested</string>
+    <string name="permission_request_notification_with_subtitle">Permission requested\nfor account <xliff:g id="account" example="foo@gmail.com">%s</xliff:g>.</string>
 
     <!-- Label to show for a service that is running because it is an input method. -->
     <string name="input_method_binding_label">Input method</string>
@@ -3002,13 +2981,13 @@
     <string name="alternate_eri_file">/data/eri.xml</string>
 
     <!-- The title of the notification when VPN is active. -->
-    <string name="vpn_title">VPN is activated.</string>
+    <string name="vpn_title">VPN activated</string>
     <!-- The title of the notification when VPN is active with an application name. -->
     <string name="vpn_title_long">VPN is activated by <xliff:g id="app" example="FooVPN client">%s</xliff:g></string>
     <!-- The text of the notification when VPN is active. -->
-    <string name="vpn_text">Tap to manage the network.</string>
+    <string name="vpn_text">Touch to manage the network.</string>
     <!-- The text of the notification when VPN is active with a session name. -->
-    <string name="vpn_text_long">Connected to <xliff:g id="session" example="office">%s</xliff:g>. Tap to manage the network.</string>
+    <string name="vpn_text_long">Connected to <xliff:g id="session" example="office">%s</xliff:g>. Touch to manage the network.</string>
 
     <!-- Localized strings for WebView -->
     <!-- Label for button in a WebView that will open a chooser to choose a file to upload -->
@@ -3023,12 +3002,12 @@
     <!-- Strings for car mode notification -->
     <!-- Shown when car mode is enabled -->
     <string name="car_mode_disable_notification_title">Car mode enabled</string>
-    <string name="car_mode_disable_notification_message">Select to exit car mode.</string>
+    <string name="car_mode_disable_notification_message">Touch to exit car mode.</string>
 
     <!-- Strings for tethered notification -->
     <!-- Shown when the device is tethered -->
     <string name="tethered_notification_title">Tethering or hotspot active</string>
-    <string name="tethered_notification_message">Touch to configure</string>
+    <string name="tethered_notification_message">Touch to set up.</string>
 
     <!--  Strings for possible PreferenceActivity Back/Next buttons -->
     <string name="back_button_label">Back</string>
@@ -3040,12 +3019,12 @@
     <!-- Strings for throttling notification -->
     <!-- Shown when the user is in danger of being throttled -->
     <string name="throttle_warning_notification_title">High mobile data use</string>
-    <string name="throttle_warning_notification_message">Touch to learn more about mobile data use</string>
+    <string name="throttle_warning_notification_message">Touch to learn more about mobile data use.</string>
 
     <!-- Strings for throttling notification -->
     <!-- Shown when the users bandwidth is reduced because of excessive data use -->
     <string name="throttled_notification_title">Mobile data limit exceeded</string>
-    <string name="throttled_notification_message">Touch to learn more about mobile data use</string>
+    <string name="throttled_notification_message">Touch to learn more about mobile data use.</string>
 
     <!-- Displayed on the Find dialog when there are no matches [CHAR LIMIT=NONE]-->
     <string name="no_matches">No matches</string>
@@ -3067,13 +3046,13 @@
 
     <!-- Strings for ExternalStorageFormatter service. -->
     <!-- Text for progress dialog while unmounting USB storage volume [CHAR LIMIT=NONE] -->
-    <string name="progress_unmounting" product="nosdcard">Unmounting USB storage...</string>
+    <string name="progress_unmounting" product="nosdcard">Unmounting USB storage\u2026</string>
     <!-- Text for progress dialog while unmounting SD card [CHAR LIMIT=NONE] -->
-    <string name="progress_unmounting" product="default">Unmounting SD card...</string>
+    <string name="progress_unmounting" product="default">Unmounting SD card\u2026</string>
     <!-- Text for progress dialog while erasing USB storage volume [CHAR LIMIT=NONE] -->
-    <string name="progress_erasing" product="nosdcard">Erasing USB storage...</string>
+    <string name="progress_erasing" product="nosdcard">Erasing USB storage\u2026</string>
     <!-- Text for progress dialog while erasing SD card [CHAR LIMIT=NONE] -->
-    <string name="progress_erasing" product="default">Erasing SD card...</string>
+    <string name="progress_erasing" product="default">Erasing SD card\u2026</string>
     <!-- Text for message to user that an error happened when formatting USB storage [CHAR LIMIT=NONE] -->
     <string name="format_error" product="nosdcard">Couldn\'t erase USB storage.</string>
     <!-- Text for message to user that an error happened when formatting SD card [CHAR LIMIT=NONE] -->
@@ -3120,19 +3099,19 @@
     <!-- Error message when the sync tried to delete too many things -->
     <string name="sync_too_many_deletes">Delete limit exceeded</string>
     <!-- Dialog message for when there are too many deletes that would take place and we want user confirmation -->
-    <string name="sync_too_many_deletes_desc">There are <xliff:g id="number_of_deleted_items">%1$d</xliff:g> deleted items for <xliff:g id="type_of_sync">%2$s</xliff:g>, account <xliff:g id="account_name">%3$s</xliff:g>. What would you like to do?</string>
+    <string name="sync_too_many_deletes_desc">There are <xliff:g id="number_of_deleted_items">%1$d</xliff:g> deleted items for <xliff:g id="type_of_sync">%2$s</xliff:g>, account <xliff:g id="account_name">%3$s</xliff:g>. What do you want to do?</string>
     <!-- Dialog action for when there are too many deletes that would take place and we want user confirmation, and the user wants to delete the items -->
-    <string name="sync_really_delete">Delete the items.</string>
+    <string name="sync_really_delete">Delete the items</string>
     <!-- Dialog action for when there are too many deletes that would take place and we want user confirmation, and the user wants to undo the deletions -->
-    <string name="sync_undo_deletes">Undo the deletes.</string>
+    <string name="sync_undo_deletes">Undo the deletes</string>
     <!-- Dialog action for when there are too many deletes that would take place and we want user confirmation, and the user wants to do nothing for now -->
-    <string name="sync_do_nothing">Do nothing for now.</string>
+    <string name="sync_do_nothing">Do nothing for now</string>
 
     <!-- Choose Account Activity label -->
     <string name="choose_account_label">Choose an account</string>
 
     <string name="add_account_label">"Add an account"</string>
-    <string name="choose_account_text">"Which account would you like to use?"</string>
+    <string name="choose_account_text">"Which account do you want to use?"</string>
 
     <!-- Button label to add an account [CHAR LIMIT=20] -->
     <string name="add_account_button_label">Add account</string>
@@ -3143,7 +3122,7 @@
     <!-- Description of the button to decrement the NumberPicker value. [CHAR LIMIT=NONE] -->
     <string name="number_picker_decrement_button">Decrement</string>
     <!-- Description of the tap and hold action to get into scroll mode in NumberPicker. [CHAR LIMIT=NONE] -->
-    <string name="number_picker_increment_scroll_mode"><xliff:g id="value" example="3">%s</xliff:g> tap and hold.</string>
+    <string name="number_picker_increment_scroll_mode"><xliff:g id="value" example="3">%s</xliff:g> touch and hold.</string>
     <!-- Description of the scrolling action in NumberPicker. [CHAR LIMIT=NONE] -->
     <string name="number_picker_increment_scroll_action">Slide up to increment and down to decrement.</string>
 
@@ -3252,7 +3231,7 @@
     <string name="description_target_unlock_tablet">Swipe to unlock.</string>
 
     <!-- Announce that a headset is required to hear keyboard keys while typing a password. [CHAR LIMIT=NONE] -->
-    <string name="keyboard_headset_required_to_hear_password">Plug in a headset to hear password keys spoken aloud.</string>
+    <string name="keyboard_headset_required_to_hear_password">Plug in a headset to hear password keys spoken.</string>
     <!-- The value of a keyboard key announced when accessibility is enabled and no headsed is used. [CHAR LIMIT=NONE] -->
     <string name="keyboard_password_character_no_headset">Dot.</string>
 
@@ -3264,21 +3243,21 @@
     <string name="action_menu_overflow_description">More options</string>
 
     <!-- Storage description for internal storage. [CHAR LIMIT=NONE] -->
-    <string name="storage_internal">Internal Storage</string>
+    <string name="storage_internal">Internal storage</string>
 
     <!-- Storage description for the SD card. [CHAR LIMIT=NONE] -->
-    <string name="storage_sd_card">SD Card</string>
+    <string name="storage_sd_card">SD card</string>
 
     <!-- Storage description for USB storage. [CHAR LIMIT=NONE] -->
     <string name="storage_usb">USB storage</string>
 
     <!-- Button text for the edit menu in input method extract mode. [CHAR LIMIT=16] -->
-    <string name="extract_edit_menu_button">Edit...</string>
+    <string name="extract_edit_menu_button">Edit</string>
 
     <!-- Notification title when data usage has exceeded warning threshold. [CHAR LIMIT=32] -->
     <string name="data_usage_warning_title">Data usage warning</string>
     <!-- Notification body when data usage has exceeded warning threshold. [CHAR LIMIT=32] -->
-    <string name="data_usage_warning_body">Touch to view usage and settings</string>
+    <string name="data_usage_warning_body">Touch to view usage and settings.</string>
 
     <!-- Notification title when 2G-3G data usage has exceeded limit threshold, and has been disabled. [CHAR LIMIT=32] -->
     <string name="data_usage_3g_limit_title">2G-3G data disabled</string>
@@ -3289,7 +3268,7 @@
     <!-- Notification title when Wi-Fi data usage has exceeded limit threshold, and has been disabled. [CHAR LIMIT=32] -->
     <string name="data_usage_wifi_limit_title">Wi-Fi data disabled</string>
     <!-- Notification body when data usage has exceeded limit threshold, and has been disabled. [CHAR LIMIT=32] -->
-    <string name="data_usage_limit_body">Touch to enable</string>
+    <string name="data_usage_limit_body">Touch to enable.</string>
 
     <!-- Notification title when 2G-3G data usage has exceeded limit threshold. [CHAR LIMIT=32] -->
     <string name="data_usage_3g_limit_snoozed_title">2G-3G data limit exceeded</string>
@@ -3300,12 +3279,12 @@
     <!-- Notification title when Wi-Fi data usage has exceeded limit threshold. [CHAR LIMIT=32] -->
     <string name="data_usage_wifi_limit_snoozed_title">Wi-Fi data limit exceeded</string>
     <!-- Notification body when data usage has exceeded limit threshold. [CHAR LIMIT=32] -->
-    <string name="data_usage_limit_snoozed_body"><xliff:g id="size" example="3.8GB">%s</xliff:g> over specified limit</string>
+    <string name="data_usage_limit_snoozed_body"><xliff:g id="size" example="3.8GB">%s</xliff:g> over specified limit.</string>
 
     <!-- Notification title when background data usage is limited. [CHAR LIMIT=32] -->
     <string name="data_usage_restricted_title">Background data restricted</string>
     <!-- Notification body when background data usage is limited. [CHAR LIMIT=32] -->
-    <string name="data_usage_restricted_body">Touch to remove restriction</string>
+    <string name="data_usage_restricted_body">Touch to remove restriction.</string>
 
     <!-- SSL Certificate dialogs -->
     <!-- Title for an SSL Certificate dialog -->
@@ -3354,12 +3333,12 @@
     <string name="list_delimeter">", "</string>
 
     <!-- STK sending DTMF, SMS, USSD, SS -->
-    <string name="sending">Sending...</string>
+    <string name="sending">Sending\u2026</string>
 
     <!-- STK launch Browser -->
     <string name="launchBrowserDefault">Launch Browser?</string>
 
     <!-- STK setup Call -->
-    <string name="SetupCallDefault">Accept Call?</string>
+    <string name="SetupCallDefault">Accept call?</string>
 
 </resources>
diff --git a/docs/html/guide/topics/graphics/2d-graphics.jd b/docs/html/guide/topics/graphics/2d-graphics.jd
index 5abffb3..5cf1a59 100644
--- a/docs/html/guide/topics/graphics/2d-graphics.jd
+++ b/docs/html/guide/topics/graphics/2d-graphics.jd
@@ -130,9 +130,8 @@
 <p class="note"><strong>Note: </strong> In order to request an invalidate from a thread other than your main
 Activity's thread, you must call <code>{@link android.view.View#postInvalidate()}</code>.</p>
 
-<p>Also read <a href="{@docRoot}guide/topics/ui/custom-components.html">Building Custom Components</a>
-for a guide to extending a View class, and <a href="2d-graphics.html">2D Graphics: Drawables</a> for
-information on using Drawable objects like images from your resources and other primitive shapes.</p>
+<p>For information about extending the {@link android.view.View} class, read
+<a href="{@docRoot}guide/topics/ui/custom-components.html">Building Custom Components</a>.</p>
 
 <p>For a sample application, see the Snake game, in the SDK samples folder:
 <code>&lt;your-sdk-directory>/samples/Snake/</code>.</p>
@@ -188,7 +187,7 @@
 
 <p>This document discusses the basics of using Drawable objects to draw graphics and how to use a
 couple subclasses of the Drawable class. For information on using Drawables to do frame-by-frame
-animation, see <a href="{@docRoot}guide/topics/animation/drawable-animation.html">Drawable
+animation, see <a href="{@docRoot}guide/topics/graphics/drawable-animation.html">Drawable
 Animation</a>.</p>
 
 <p>A {@link android.graphics.drawable.Drawable} is a general abstraction for "something that can be
diff --git a/libs/hwui/Android.mk b/libs/hwui/Android.mk
index 9bfc94c..95e0a18 100644
--- a/libs/hwui/Android.mk
+++ b/libs/hwui/Android.mk
@@ -38,7 +38,7 @@
 		external/skia/src/ports \
 		external/skia/include/utils
 
-	LOCAL_CFLAGS += -DUSE_OPENGL_RENDERER
+	LOCAL_CFLAGS += -DUSE_OPENGL_RENDERER -DGL_GLEXT_PROTOTYPES
 	LOCAL_CFLAGS += -fvisibility=hidden
 	LOCAL_MODULE_CLASS := SHARED_LIBRARIES
 	LOCAL_SHARED_LIBRARIES := libcutils libutils libGLESv2 libskia libui
diff --git a/libs/hwui/Extensions.h b/libs/hwui/Extensions.h
index 38d1130..48e4247 100644
--- a/libs/hwui/Extensions.h
+++ b/libs/hwui/Extensions.h
@@ -66,6 +66,7 @@
 
         mHasNPot = hasExtension("GL_OES_texture_npot");
         mHasFramebufferFetch = hasExtension("GL_NV_shader_framebuffer_fetch");
+        mHasDiscardFramebuffer = hasExtension("GL_EXT_discard_framebuffer");
 
         const char* vendor = (const char*) glGetString(GL_VENDOR);
         EXT_LOGD("Vendor: %s", vendor);
@@ -80,6 +81,7 @@
     inline bool hasNPot() const { return mHasNPot; }
     inline bool hasFramebufferFetch() const { return mHasFramebufferFetch; }
     inline bool needsHighpTexCoords() const { return mNeedsHighpTexCoords; }
+    inline bool hasDiscardFramebuffer() const { return mHasDiscardFramebuffer; }
 
     bool hasExtension(const char* extension) const {
         const String8 s(extension);
@@ -98,6 +100,7 @@
     bool mHasNPot;
     bool mNeedsHighpTexCoords;
     bool mHasFramebufferFetch;
+    bool mHasDiscardFramebuffer;
 }; // class Extensions
 
 }; // namespace uirenderer
diff --git a/libs/hwui/LayerRenderer.cpp b/libs/hwui/LayerRenderer.cpp
index 6bf6004..e2d9ea3 100644
--- a/libs/hwui/LayerRenderer.cpp
+++ b/libs/hwui/LayerRenderer.cpp
@@ -305,8 +305,10 @@
         LAYER_RENDERER_LOGD("Recycling layer, %dx%d fbo = %d",
                 layer->getWidth(), layer->getHeight(), layer->getFbo());
 
-        if (layer->getFbo()) {
-            Caches::getInstance().fboCache.put(layer->getFbo());
+        GLuint fbo = layer->getFbo();
+        if (fbo) {
+            flushLayer(layer);
+            Caches::getInstance().fboCache.put(fbo);
         }
 
         if (!Caches::getInstance().layerCache.put(layer)) {
@@ -331,6 +333,26 @@
     }
 }
 
+void LayerRenderer::flushLayer(Layer* layer) {
+#ifdef GL_EXT_discard_framebuffer
+    GLuint fbo = layer->getFbo();
+    if (layer && fbo) {
+        // If possible, discard any enqueud operations on deferred
+        // rendering architectures
+        if (Caches::getInstance().extensions.hasDiscardFramebuffer()) {
+            GLuint previousFbo;
+            glGetIntegerv(GL_FRAMEBUFFER_BINDING, (GLint*) &previousFbo);
+
+            GLenum attachments = GL_COLOR_ATTACHMENT0;
+            if (fbo != previousFbo) glBindFramebuffer(GL_FRAMEBUFFER, fbo);
+            glDiscardFramebufferEXT(GL_FRAMEBUFFER, 1, &attachments);
+
+            if (fbo != previousFbo) glBindFramebuffer(GL_FRAMEBUFFER, previousFbo);
+        }
+    }
+#endif
+}
+
 bool LayerRenderer::copyLayer(Layer* layer, SkBitmap* bitmap) {
     Caches& caches = Caches::getInstance();
     if (layer && layer->isTextureLayer() && bitmap->width() <= caches.maxTextureSize &&
diff --git a/libs/hwui/LayerRenderer.h b/libs/hwui/LayerRenderer.h
index 6104301..72d8d81 100644
--- a/libs/hwui/LayerRenderer.h
+++ b/libs/hwui/LayerRenderer.h
@@ -61,6 +61,7 @@
             bool isOpaque, GLenum renderTarget, float* transform);
     ANDROID_API static void destroyLayer(Layer* layer);
     ANDROID_API static void destroyLayerDeferred(Layer* layer);
+    ANDROID_API static void flushLayer(Layer* layer);
     ANDROID_API static bool copyLayer(Layer* layer, SkBitmap* bitmap);
 
 private:
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index 81c053e..1d7b99d 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -615,6 +615,11 @@
     }
 
     if (fboLayer) {
+        // Note: No need to use glDiscardFramebufferEXT() since we never
+        //       create/compose layers that are not on screen with this
+        //       code path
+        // See LayerRenderer::destroyLayer(Layer*)
+
         // Detach the texture from the FBO
         glBindFramebuffer(GL_FRAMEBUFFER, current->fbo);
         glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0);
diff --git a/libs/rs/scriptc/rs_types.rsh b/libs/rs/scriptc/rs_types.rsh
index e9c3c5e..84bca9c 100644
--- a/libs/rs/scriptc/rs_types.rsh
+++ b/libs/rs/scriptc/rs_types.rsh
@@ -364,7 +364,7 @@
 typedef float4 rs_quaternion;
 
 #define RS_PACKED __attribute__((packed, aligned(4)))
-#define NULL ((const void *)0)
+#define NULL ((void *)0)
 
 #if (defined(RS_VERSION) && (RS_VERSION >= 14))
 
diff --git a/media/java/android/media/AudioService.java b/media/java/android/media/AudioService.java
index 3b55246..c201417 100644
--- a/media/java/android/media/AudioService.java
+++ b/media/java/android/media/AudioService.java
@@ -21,6 +21,7 @@
 import static android.media.AudioManager.RINGER_MODE_VIBRATE;
 
 import android.app.ActivityManagerNative;
+import android.app.KeyguardManager;
 import android.app.PendingIntent;
 import android.app.PendingIntent.CanceledException;
 import android.bluetooth.BluetoothA2dp;
@@ -319,6 +320,8 @@
     private static final int NOTIFICATION_VOLUME_DELAY_MS = 5000;
     // previous volume adjustment direction received by checkForRingerModeChange()
     private int mPrevVolDirection = AudioManager.ADJUST_SAME;
+    // Keyguard manager proxy
+    private KeyguardManager mKeyguardManager;
 
     ///////////////////////////////////////////////////////////////////////////
     // Construction
@@ -503,9 +506,10 @@
             streamType = getActiveStreamType(suggestedStreamType);
         }
 
-        // Play sounds on STREAM_RING only.
+        // Play sounds on STREAM_RING only and if lock screen is not on.
         if ((flags & AudioManager.FLAG_PLAY_SOUND) != 0 &&
-                ((STREAM_VOLUME_ALIAS[streamType] != AudioSystem.STREAM_RING))) {
+                ((STREAM_VOLUME_ALIAS[streamType] != AudioSystem.STREAM_RING)
+                 || (mKeyguardManager != null && mKeyguardManager.isKeyguardLocked()))) {
             flags &= ~AudioManager.FLAG_PLAY_SOUND;
         }
 
@@ -2659,6 +2663,8 @@
                 sendMsg(mAudioHandler, MSG_LOAD_SOUND_EFFECTS, SHARED_MSG, SENDMSG_NOOP,
                         0, 0, null, 0);
 
+                mKeyguardManager =
+                        (KeyguardManager) mContext.getSystemService(Context.KEYGUARD_SERVICE);
                 mScoConnectionState = AudioManager.SCO_AUDIO_STATE_ERROR;
                 resetBluetoothSco();
                 getBluetoothHeadset();
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/videoeditor/VideoEditorPreviewTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/videoeditor/VideoEditorPreviewTest.java
index 3c08138..4181903 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/videoeditor/VideoEditorPreviewTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/videoeditor/VideoEditorPreviewTest.java
@@ -709,7 +709,7 @@
 
 
         blockTillPreviewCompletes.acquire();
-                    final String fileName = mVideoEditor.getPath() + "\test.3gp";
+                    final String fileName = mVideoEditor.getPath() + "/test.3gp";
                     final int height = MediaProperties.HEIGHT_480;
                     final int bitrate = MediaProperties.BITRATE_512K;
 
diff --git a/packages/SettingsProvider/res/values/defaults.xml b/packages/SettingsProvider/res/values/defaults.xml
index 7a98615..1ebed1f 100644
--- a/packages/SettingsProvider/res/values/defaults.xml
+++ b/packages/SettingsProvider/res/values/defaults.xml
@@ -80,6 +80,9 @@
     <!-- Default for Settings.Secure.ACCESSIBILITY_SCRIPT_INJECTION -->
     <bool name="def_accessibility_script_injection">false</bool>
 
+    <!-- Default for Settings.Secure.ACCESSIBILITY_SPEAK_PASSWORD -->
+    <bool name="def_accessibility_speak_password">false</bool>
+
     <!-- Default for Settings.Secure.ACCESSIBILITY_WEB_CONTENT_KEY_BINDINGS -->
     <string name="def_accessibility_web_content_key_bindings" translatable="false">
             <!-- DPAD/Trackball UP - traverse previous on current axis and send an event. -->
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
index ac2369a..1fbe08d 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
@@ -63,7 +63,7 @@
     // database gets upgraded properly. At a minimum, please confirm that 'upgradeVersion'
     // is properly propagated through your change.  Not doing so will result in a loss of user
     // settings.
-    private static final int DATABASE_VERSION = 71;
+    private static final int DATABASE_VERSION = 73;
 
     private Context mContext;
 
@@ -952,6 +952,40 @@
             upgradeVersion = 71;
         }
 
+        if (upgradeVersion == 71) {
+             // New setting to specify whether to speak passwords in accessibility mode.
+            db.beginTransaction();
+            SQLiteStatement stmt = null;
+            try {
+                stmt = db.compileStatement("INSERT INTO secure(name,value)"
+                        + " VALUES(?,?);");
+                loadBooleanSetting(stmt, Settings.Secure.ACCESSIBILITY_SPEAK_PASSWORD,
+                        R.bool.def_accessibility_speak_password);
+                db.setTransactionSuccessful();
+            } finally {
+                db.endTransaction();
+                if (stmt != null) stmt.close();
+            }
+            upgradeVersion = 72;
+        }
+
+        if (upgradeVersion == 72) {
+            // update vibration settings
+            db.beginTransaction();
+            SQLiteStatement stmt = null;
+            try {
+                stmt = db.compileStatement("INSERT OR REPLACE INTO system(name,value)"
+                        + " VALUES(?,?);");
+                loadBooleanSetting(stmt, Settings.System.VIBRATE_IN_SILENT,
+                        R.bool.def_vibrate_in_silent);
+                db.setTransactionSuccessful();
+            } finally {
+                db.endTransaction();
+                if (stmt != null) stmt.close();
+            }
+            upgradeVersion = 73;
+        }
+
         // *** Remember to update DATABASE_VERSION above!
 
         if (upgradeVersion != currentVersion) {
@@ -1489,6 +1523,9 @@
 
             loadBooleanSetting(stmt, Settings.Secure.TOUCH_EXPLORATION_ENABLED,
                     R.bool.def_touch_exploration_enabled);
+
+            loadBooleanSetting(stmt, Settings.Secure.ACCESSIBILITY_SPEAK_PASSWORD,
+                    R.bool.def_accessibility_speak_password);
         } finally {
             if (stmt != null) stmt.close();
         }
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back_ime_default.png b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back_ime.png
similarity index 100%
rename from packages/SystemUI/res/drawable-hdpi/ic_sysbar_back_ime_default.png
rename to packages/SystemUI/res/drawable-hdpi/ic_sysbar_back_ime.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back_ime_pressed.png b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back_ime_pressed.png
deleted file mode 100644
index 4757125..0000000
--- a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back_ime_pressed.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back_ime_default.png b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back_ime.png
similarity index 100%
rename from packages/SystemUI/res/drawable-mdpi/ic_sysbar_back_ime_default.png
rename to packages/SystemUI/res/drawable-mdpi/ic_sysbar_back_ime.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back_ime_pressed.png b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back_ime_pressed.png
deleted file mode 100644
index 0cd05a3..0000000
--- a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back_ime_pressed.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back_ime_default.png b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back_ime.png
similarity index 100%
rename from packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back_ime_default.png
rename to packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back_ime.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back_ime_pressed.png b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back_ime_pressed.png
deleted file mode 100644
index 3e59c8d..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back_ime_pressed.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/layout-sw600dp/status_bar_recent_panel.xml b/packages/SystemUI/res/layout-sw600dp/status_bar_recent_panel.xml
index 111f9a4..8e231d0 100644
--- a/packages/SystemUI/res/layout-sw600dp/status_bar_recent_panel.xml
+++ b/packages/SystemUI/res/layout-sw600dp/status_bar_recent_panel.xml
@@ -32,7 +32,7 @@
         android:layout_width="wrap_content"
         android:layout_height="match_parent"
         android:layout_alignParentBottom="true"
-        android:paddingBottom="@*android:dimen/status_bar_height"
+        android:layout_marginBottom="@*android:dimen/status_bar_height"
         android:clipToPadding="false"
         android:clipChildren="false">
 
@@ -69,13 +69,12 @@
 
     </FrameLayout>
 
-    <View android:id="@+id/recents_dismiss_button"
-        android:layout_width="80px"
+    <com.android.systemui.recent.StatusBarTouchProxy
+        android:id="@+id/status_bar_touch_proxy"
+        android:layout_width="match_parent"
         android:layout_height="@*android:dimen/status_bar_height"
         android:layout_alignParentBottom="true"
         android:layout_alignParentLeft="true"
-        android:background="@drawable/ic_sysbar_back_ime"
-        android:contentDescription="@string/status_bar_accessibility_dismiss_recents"
     />
 
 
diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java b/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java
index 8bfd711..4aec22c 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java
@@ -68,10 +68,11 @@
     private View mRecentsScrim;
     private View mRecentsNoApps;
     private ViewGroup mRecentsContainer;
+    private StatusBarTouchProxy mStatusBarTouchProxy;
 
     private boolean mShowing;
     private Choreographer mChoreo;
-    private View mRecentsDismissButton;
+    OnRecentsPanelVisibilityChangedListener mVisibilityChangedListener;
 
     private RecentTasksLoader mRecentTasksLoader;
     private ArrayList<TaskDescription> mRecentTaskDescriptions;
@@ -81,8 +82,8 @@
     private int mThumbnailWidth;
     private boolean mFitThumbnailToXY;
 
-    public void setRecentTasksLoader(RecentTasksLoader loader) {
-        mRecentTasksLoader = loader;
+    public static interface OnRecentsPanelVisibilityChangedListener {
+        public void onRecentsPanelVisibilityChanged(boolean visible);
     }
 
     private final class OnLongClickDelegate implements View.OnLongClickListener {
@@ -171,15 +172,18 @@
         return super.onKeyUp(keyCode, event);
     }
 
-    public boolean isInContentArea(int x, int y) {
-        // use mRecentsContainer's exact bounds to determine horizontal position
-        final int l = mRecentsContainer.getLeft();
-        final int r = mRecentsContainer.getRight();
-        final int t = mRecentsContainer.getTop();
-        final int b = mRecentsContainer.getBottom();
+    private boolean pointInside(int x, int y, View v) {
+        final int l = v.getLeft();
+        final int r = v.getRight();
+        final int t = v.getTop();
+        final int b = v.getBottom();
         return x >= l && x < r && y >= t && y < b;
     }
 
+    public boolean isInContentArea(int x, int y) {
+        return pointInside(x, y, mRecentsContainer) || pointInside(x, y, mStatusBarTouchProxy);
+    }
+
     public void show(boolean show, boolean animate) {
         show(show, animate, null);
     }
@@ -278,7 +282,6 @@
     public void onAnimationStart(Animator animation) {
     }
 
-
     /**
      * We need to be aligned at the bottom.  LinearLayout can't do this, so instead,
      * let LinearLayout do all the hard work, and then shift everything down to the bottom.
@@ -312,6 +315,29 @@
 
     public void setBar(StatusBar bar) {
         mBar = bar;
+
+    }
+
+    public void setStatusBarView(View statusBarView) {
+        if (mStatusBarTouchProxy != null) {
+            mStatusBarTouchProxy.setStatusBar(statusBarView);
+        }
+    }
+
+    public void setRecentTasksLoader(RecentTasksLoader loader) {
+        mRecentTasksLoader = loader;
+    }
+
+    public void setOnVisibilityChangedListener(OnRecentsPanelVisibilityChangedListener l) {
+        mVisibilityChangedListener = l;
+
+    }
+
+    public void setVisibility(int visibility) {
+        if (mVisibilityChangedListener != null) {
+            mVisibilityChangedListener.onRecentsPanelVisibilityChanged(visibility == VISIBLE);
+        }
+        super.setVisibility(visibility);
     }
 
     public RecentsPanelView(Context context, AttributeSet attrs) {
@@ -335,6 +361,7 @@
         super.onFinishInflate();
         mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
         mRecentsContainer = (ViewGroup) findViewById(R.id.recents_container);
+        mStatusBarTouchProxy = (StatusBarTouchProxy) findViewById(R.id.status_bar_touch_proxy);
         mListAdapter = new TaskDescriptionAdapter(mContext);
         if (mRecentsContainer instanceof RecentsHorizontalScrollView){
             RecentsHorizontalScrollView scrollView
@@ -355,14 +382,6 @@
         mRecentsScrim = findViewById(R.id.recents_bg_protect);
         mRecentsNoApps = findViewById(R.id.recents_no_apps);
         mChoreo = new Choreographer(this, mRecentsScrim, mRecentsContainer, mRecentsNoApps, this);
-        mRecentsDismissButton = findViewById(R.id.recents_dismiss_button);
-        if (mRecentsDismissButton != null) {
-            mRecentsDismissButton.setOnClickListener(new OnClickListener() {
-                public void onClick(View v) {
-                    hide(true);
-                }
-            });
-        }
 
         // In order to save space, we make the background texture repeat in the Y direction
         if (mRecentsScrim != null && mRecentsScrim.getBackground() instanceof BitmapDrawable) {
diff --git a/packages/SystemUI/src/com/android/systemui/recent/StatusBarTouchProxy.java b/packages/SystemUI/src/com/android/systemui/recent/StatusBarTouchProxy.java
new file mode 100644
index 0000000..ded114f
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/recent/StatusBarTouchProxy.java
@@ -0,0 +1,40 @@
+/*
+ * 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.systemui.recent;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.MotionEvent;
+import android.view.View;
+import android.widget.FrameLayout;
+
+public class StatusBarTouchProxy extends FrameLayout {
+
+    private View mStatusBar;
+
+    public StatusBarTouchProxy(Context context, AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    public void setStatusBar(View statusBar) {
+        mStatusBar = statusBar;
+    }
+
+    public boolean onTouchEvent (MotionEvent event) {
+        return mStatusBar.dispatchTouchEvent(event);
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
index bf2d5e8..f8dfa8f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
@@ -62,6 +62,8 @@
     
     private static final int MSG_TOGGLE_RECENT_APPS       = 11 << MSG_SHIFT;
 
+    private static final int MSG_SET_NAVIGATION_ICON_HINTS = 13 << MSG_SHIFT;
+
     private StatusBarIconList mList;
     private Callbacks mCallbacks;
     private Handler mHandler = new H();
@@ -90,6 +92,7 @@
         public void setImeWindowStatus(IBinder token, int vis, int backDisposition);
         public void setHardKeyboardStatus(boolean available, boolean enabled);
         public void toggleRecentApps();
+        public void setNavigationIconHints(int hints);
     }
 
     public CommandQueue(Callbacks callbacks, StatusBarIconList list) {
@@ -196,6 +199,13 @@
         }
     }
 
+    public void setNavigationIconHints(int hints) {
+        synchronized (mList) {
+            mHandler.removeMessages(MSG_SET_NAVIGATION_ICON_HINTS);
+            mHandler.obtainMessage(MSG_SET_NAVIGATION_ICON_HINTS, hints, 0, null).sendToTarget();
+        }
+    }
+
     private final class H extends Handler {
         public void handleMessage(Message msg) {
             final int what = msg.what & MSG_MASK;
@@ -265,6 +275,9 @@
                 case MSG_TOGGLE_RECENT_APPS:
                     mCallbacks.toggleRecentApps();
                     break;
+                case MSG_SET_NAVIGATION_ICON_HINTS:
+                    mCallbacks.setNavigationIconHints(msg.arg1);
+                    break;
             }
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
index 97a1855..69a247d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
@@ -18,6 +18,8 @@
 
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
+import android.animation.ObjectAnimator;
+import android.app.StatusBarManager;
 import android.content.Context;
 import android.content.res.Resources;
 import android.graphics.Rect;
@@ -31,6 +33,7 @@
 import android.view.ViewGroup;
 import android.view.Surface;
 import android.view.WindowManager;
+import android.widget.ImageView;
 import android.widget.LinearLayout;
 
 import java.io.FileDescriptor;
@@ -61,6 +64,7 @@
 
     boolean mHidden, mLowProfile, mShowMenu;
     int mDisabledFlags = 0;
+    int mNavigationIconHints = 0;
 
     public View getRecentsButton() {
         return mCurrentView.findViewById(R.id.recent_apps);
@@ -112,6 +116,34 @@
         }
     };
 
+    public void setNavigationIconHints(int hints) {
+        setNavigationIconHints(hints, false);
+    }
+
+    public void setNavigationIconHints(int hints, boolean force) {
+        if (!force && hints == mNavigationIconHints) return;
+
+        if (DEBUG) {
+            android.widget.Toast.makeText(mContext,
+                "Navigation icon hints = " + hints,
+                500).show();
+        }
+
+        mNavigationIconHints = hints;
+
+        getBackButton().setAlpha(
+            (0 != (hints & StatusBarManager.NAVIGATION_HINT_BACK_NOP)) ? 0.5f : 1.0f);
+        getHomeButton().setAlpha(
+            (0 != (hints & StatusBarManager.NAVIGATION_HINT_HOME_NOP)) ? 0.5f : 1.0f);
+        getRecentsButton().setAlpha(
+            (0 != (hints & StatusBarManager.NAVIGATION_HINT_RECENT_NOP)) ? 0.5f : 1.0f);
+
+        ((ImageView)getBackButton()).setImageResource(
+            (0 != (hints & StatusBarManager.NAVIGATION_HINT_BACK_ALT))
+                ? R.drawable.ic_sysbar_back_ime
+                : R.drawable.ic_sysbar_back);
+    }
+
     public void setDisabledFlags(int disabledFlags) {
         setDisabledFlags(disabledFlags, false);
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
index 3d49624..5a1e3f4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -32,6 +32,7 @@
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.res.Resources;
 import android.content.res.Configuration;
+import android.inputmethodservice.InputMethodService;
 import android.graphics.PixelFormat;
 import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
@@ -136,7 +137,7 @@
     BatteryController mBatteryController;
     LocationController mLocationController;
     NetworkController mNetworkController;
-    
+
     int mNaturalBarHeight = -1;
     int mIconSize = -1;
     int mIconHPadding = -1;
@@ -168,7 +169,7 @@
 
     // drag bar
     CloseDragHandle mCloseView;
-    
+
     // all notifications
     NotificationData mNotificationData = new NotificationData();
     NotificationRowLayout mPile;
@@ -229,6 +230,8 @@
 
     DisplayMetrics mDisplayMetrics = new DisplayMetrics();
 
+    private int mNavigationIconHints = 0;
+
     private class ExpandedDialog extends Dialog {
         ExpandedDialog(Context context) {
             super(context, com.android.internal.R.style.Theme_Translucent_NoTitleBar);
@@ -298,7 +301,7 @@
         try {
             boolean showNav = mWindowManager.hasNavigationBar();
             if (showNav) {
-                mNavigationBarView = 
+                mNavigationBarView =
                     (NavigationBarView) View.inflate(context, R.layout.navigation_bar, null);
 
                 mNavigationBarView.setDisabledFlags(mDisabled);
@@ -352,11 +355,11 @@
         mBatteryController = new BatteryController(mContext);
         mBatteryController.addIconView((ImageView)sb.findViewById(R.id.battery));
         mNetworkController = new NetworkController(mContext);
-        final SignalClusterView signalCluster = 
+        final SignalClusterView signalCluster =
                 (SignalClusterView)sb.findViewById(R.id.signal_cluster);
         mNetworkController.addSignalCluster(signalCluster);
         signalCluster.setNetworkController(mNetworkController);
-//        final ImageView wimaxRSSI = 
+//        final ImageView wimaxRSSI =
 //                (ImageView)sb.findViewById(R.id.wimax_signal);
 //        if (wimaxRSSI != null) {
 //            mNetworkController.addWimaxIconView(wimaxRSSI);
@@ -1085,8 +1088,8 @@
             }
         }
 
-        if ((diff & (StatusBarManager.DISABLE_HOME 
-                        | StatusBarManager.DISABLE_RECENT 
+        if ((diff & (StatusBarManager.DISABLE_HOME
+                        | StatusBarManager.DISABLE_RECENT
                         | StatusBarManager.DISABLE_BACK)) != 0) {
             // the nav bar will take care of these
             if (mNavigationBarView != null) mNavigationBarView.setDisabledFlags(state);
@@ -1204,7 +1207,7 @@
     public void animateCollapse(boolean excludeRecents) {
         animateCollapse(excludeRecents, 1.0f);
     }
-    
+
     public void animateCollapse(boolean excludeRecents, float velocityMultiplier) {
         if (SPEW) {
             Slog.d(TAG, "animateCollapse(): mExpanded=" + mExpanded
@@ -1516,8 +1519,8 @@
                 }
 
                 if (CHATTY) {
-                    Slog.d(TAG, String.format("gesture: vraw=(%f,%f) vnorm=(%f,%f) vlinear=%f", 
-                        mVelocityTracker.getXVelocity(), 
+                    Slog.d(TAG, String.format("gesture: vraw=(%f,%f) vnorm=(%f,%f) vlinear=%f",
+                        mVelocityTracker.getXVelocity(),
                         mVelocityTracker.getYVelocity(),
                         xVel, yVel,
                         vel));
@@ -1541,6 +1544,17 @@
     }
 
     @Override // CommandQueue
+    public void setNavigationIconHints(int hints) {
+        if (hints == mNavigationIconHints) return;
+
+        mNavigationIconHints = hints;
+
+        if (mNavigationBarView != null) {
+            mNavigationBarView.setNavigationIconHints(hints);
+        }
+    }
+
+    @Override // CommandQueue
     public void setSystemUiVisibility(int vis) {
         final int old = mSystemUiVisibility;
         final int diff = vis ^ old;
@@ -1590,8 +1604,16 @@
         if (showMenu) setLightsOn(true);
     }
 
-    // Not supported
-    public void setImeWindowStatus(IBinder token, int vis, int backDisposition) { }
+    @Override
+    public void setImeWindowStatus(IBinder token, int vis, int backDisposition) {
+        boolean altBack = (backDisposition == InputMethodService.BACK_DISPOSITION_WILL_DISMISS)
+            || ((vis & InputMethodService.IME_VISIBLE) != 0);
+
+        mCommandQueue.setNavigationIconHints(
+                altBack ? (mNavigationIconHints | StatusBarManager.NAVIGATION_HINT_BACK_ALT)
+                        : (mNavigationIconHints & ~StatusBarManager.NAVIGATION_HINT_BACK_ALT));
+    }
+
     @Override
     public void setHardKeyboardStatus(boolean available, boolean enabled) { }
 
@@ -1795,7 +1817,7 @@
                 StatusBarIconView ic = (StatusBarIconView) mStatusIcons.getChildAt(i);
                 pw.println("    [" + i + "] icon=" + ic);
             }
-            
+
             if (false) {
                 pw.println("see the logcat for a dump of the views we have created.");
                 // must happen on ui thread
@@ -1970,10 +1992,10 @@
                         - (mTrackingParams.height-closePos) - contentsBottom;
 
                 if (SPEW) {
-                    Slog.d(PhoneStatusBar.TAG, 
+                    Slog.d(PhoneStatusBar.TAG,
                             "pos=" + pos +
                             " trackingHeight=" + mTrackingView.getHeight() +
-                            " (trackingParams.height - closePos)=" + 
+                            " (trackingParams.height - closePos)=" +
                                 (mTrackingParams.height - closePos) +
                             " contentsBottom=" + contentsBottom);
                 }
@@ -2048,7 +2070,7 @@
                 mExpandedDialog.getWindow().setAttributes(mExpandedParams);
             }
             if (DEBUG) {
-                Slog.d(TAG, "updateExpandedSize: height=" + mExpandedParams.height + " " + 
+                Slog.d(TAG, "updateExpandedSize: height=" + mExpandedParams.height + " " +
                     (mExpandedVisible ? "VISIBLE":"INVISIBLE"));
             }
         }
@@ -2188,6 +2210,11 @@
 
     private View.OnClickListener mSettingsButtonListener = new View.OnClickListener() {
         public void onClick(View v) {
+            try {
+                // Dismiss the lock screen when Settings starts.
+                ActivityManagerNative.getDefault().dismissKeyguardOnNextActivity();
+            } catch (RemoteException e) {
+            }
             v.getContext().startActivity(new Intent(Settings.ACTION_SETTINGS)
                     .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
             animateCollapse();
@@ -2237,7 +2264,7 @@
 
         loadDimens();
     }
-    
+
     protected void loadDimens() {
         final Resources res = mContext.getResources();
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java
index b919aec..490191a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java
@@ -88,7 +88,8 @@
 
 public class TabletStatusBar extends StatusBar implements
         HeightReceiver.OnBarHeightChangedListener,
-        InputMethodsPanel.OnHardKeyboardEnabledChangeListener {
+        InputMethodsPanel.OnHardKeyboardEnabledChangeListener,
+        RecentsPanelView.OnRecentsPanelVisibilityChangedListener {
     public static final boolean DEBUG = false;
     public static final boolean DEBUG_COMPAT_HELP = false;
     public static final String TAG = "TabletStatusBar";
@@ -143,6 +144,7 @@
     View mHomeButton;
     View mMenuButton;
     View mRecentButton;
+    private boolean mAltBackButtonEnabledForIme;
 
     ViewGroup mFeedbackIconArea; // notification icons, IME icon, compat icon
     InputMethodButton mInputMethodSwitchButton;
@@ -193,6 +195,8 @@
     // used to notify status bar for suppressing notification LED
     private boolean mPanelSlightlyVisible;
 
+    private int mNavigationIconHints = 0;
+
     public Context getContext() { return mContext; }
 
     protected void addPanelWindows() {
@@ -310,12 +314,11 @@
         mRecentsPanel = (RecentsPanelView) View.inflate(context,
                 R.layout.status_bar_recent_panel, null);
         mRecentsPanel.setVisibility(View.GONE);
-        mRecentsPanel.setSystemUiVisibility(View.STATUS_BAR_DISABLE_BACK);
         mRecentsPanel.setOnTouchListener(new TouchOutsideListener(MSG_CLOSE_RECENTS_PANEL,
                 mRecentsPanel));
+        mRecentsPanel.setOnVisibilityChangedListener(this);
         mRecentsPanel.setRecentTasksLoader(mRecentTasksLoader);
         mRecentTasksLoader.setRecentsPanel(mRecentsPanel);
-        mStatusBarView.setIgnoreChildren(2, mRecentButton, mRecentsPanel);
 
         lp = new WindowManager.LayoutParams(
                 (int) res.getDimension(R.dimen.status_bar_recents_width),
@@ -334,6 +337,7 @@
 
         WindowManagerImpl.getDefault().addView(mRecentsPanel, lp);
         mRecentsPanel.setBar(this);
+        mRecentsPanel.setStatusBarView(mStatusBarView);
 
         // Input methods Panel
         mInputMethodsPanel = (InputMethodsPanel) View.inflate(context,
@@ -342,7 +346,7 @@
         mInputMethodsPanel.setOnTouchListener(new TouchOutsideListener(
                 MSG_CLOSE_INPUT_METHODS_PANEL, mInputMethodsPanel));
         mInputMethodsPanel.setImeSwitchButton(mInputMethodSwitchButton);
-        mStatusBarView.setIgnoreChildren(3, mInputMethodSwitchButton, mInputMethodsPanel);
+        mStatusBarView.setIgnoreChildren(2, mInputMethodSwitchButton, mInputMethodsPanel);
         lp = new WindowManager.LayoutParams(
                 ViewGroup.LayoutParams.WRAP_CONTENT,
                 ViewGroup.LayoutParams.WRAP_CONTENT,
@@ -365,7 +369,7 @@
                 MSG_CLOSE_COMPAT_MODE_PANEL, mCompatModePanel));
         mCompatModePanel.setTrigger(mCompatModeButton);
         mCompatModePanel.setVisibility(View.GONE);
-        mStatusBarView.setIgnoreChildren(4, mCompatModeButton, mCompatModePanel);
+        mStatusBarView.setIgnoreChildren(3, mCompatModeButton, mCompatModePanel);
         lp = new WindowManager.LayoutParams(
                 250,
                 ViewGroup.LayoutParams.WRAP_CONTENT,
@@ -431,6 +435,10 @@
         }
     }
 
+    public View getStatusBarView() {
+        return mStatusBarView;
+    }
+
     protected View makeStatusBarView() {
         final Context context = mContext;
 
@@ -1082,6 +1090,31 @@
         }
     }
 
+    @Override // CommandQueue
+    public void setNavigationIconHints(int hints) {
+        if (hints == mNavigationIconHints) return;
+
+        if (DEBUG) {
+            android.widget.Toast.makeText(mContext,
+                "Navigation icon hints = " + hints,
+                500).show();
+        }
+
+        mNavigationIconHints = hints;
+
+        mBackButton.setAlpha(
+            (0 != (hints & StatusBarManager.NAVIGATION_HINT_BACK_NOP)) ? 0.5f : 1.0f);
+        mHomeButton.setAlpha(
+            (0 != (hints & StatusBarManager.NAVIGATION_HINT_HOME_NOP)) ? 0.5f : 1.0f);
+        mRecentButton.setAlpha(
+            (0 != (hints & StatusBarManager.NAVIGATION_HINT_RECENT_NOP)) ? 0.5f : 1.0f);
+
+        mBackButton.setImageResource(
+            (0 != (hints & StatusBarManager.NAVIGATION_HINT_BACK_ALT))
+                ? R.drawable.ic_sysbar_back_ime
+                : R.drawable.ic_sysbar_back);
+    }
+
     private void notifyUiVisibilityChanged() {
         try {
             mWindowManager.statusBarVisibilityChanged(mSystemUiVisibility);
@@ -1185,24 +1218,15 @@
                 (vis & InputMethodService.IME_ACTIVE) != 0);
         updateNotificationIcons();
         mInputMethodsPanel.setImeToken(token);
-        int res;
-        switch (backDisposition) {
-            case InputMethodService.BACK_DISPOSITION_WILL_NOT_DISMISS:
-                res = R.drawable.ic_sysbar_back;
-                break;
-            case InputMethodService.BACK_DISPOSITION_WILL_DISMISS:
-                res = R.drawable.ic_sysbar_back_ime;
-                break;
-            case InputMethodService.BACK_DISPOSITION_DEFAULT:
-            default:
-                if ((vis & InputMethodService.IME_VISIBLE) != 0) {
-                    res = R.drawable.ic_sysbar_back_ime;
-                } else {
-                    res = R.drawable.ic_sysbar_back;
-                }
-                break;
-        }
-        mBackButton.setImageResource(res);
+
+        boolean altBack = (backDisposition == InputMethodService.BACK_DISPOSITION_WILL_DISMISS)
+            || ((vis & InputMethodService.IME_VISIBLE) != 0);
+        mAltBackButtonEnabledForIme = altBack;
+
+        mCommandQueue.setNavigationIconHints(
+                altBack ? (mNavigationIconHints | StatusBarManager.NAVIGATION_HINT_BACK_ALT)
+                        : (mNavigationIconHints & ~StatusBarManager.NAVIGATION_HINT_BACK_ALT));
+
         if (FAKE_SPACE_BAR) {
             mFakeSpaceBar.setVisibility(((vis & InputMethodService.IME_VISIBLE) != 0)
                     ? View.VISIBLE : View.GONE);
@@ -1210,6 +1234,14 @@
     }
 
     @Override
+    public void onRecentsPanelVisibilityChanged(boolean visible) {
+        boolean altBack = visible || mAltBackButtonEnabledForIme;
+        mCommandQueue.setNavigationIconHints(
+                altBack ? (mNavigationIconHints | StatusBarManager.NAVIGATION_HINT_BACK_ALT)
+                        : (mNavigationIconHints & ~StatusBarManager.NAVIGATION_HINT_BACK_ALT));
+    }
+
+    @Override
     public void setHardKeyboardStatus(boolean available, boolean enabled) {
         if (DEBUG) {
             Slog.d(TAG, "Set hard keyboard status: available=" + available
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBarView.java
index 7d11251..877a40e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBarView.java
@@ -46,10 +46,11 @@
             if (TabletStatusBar.DEBUG) {
                 Slog.d(TabletStatusBar.TAG, "TabletStatusBarView intercepting touch event: " + ev);
             }
+            // do not close the recents panel here- the intended behavior is that recents is dismissed
+            // on touch up when clicking on status bar buttons
+            // TODO: should we be closing the notification panel and input methods panel?
             mHandler.removeMessages(TabletStatusBar.MSG_CLOSE_NOTIFICATION_PANEL);
             mHandler.sendEmptyMessage(TabletStatusBar.MSG_CLOSE_NOTIFICATION_PANEL);
-            mHandler.removeMessages(TabletStatusBar.MSG_CLOSE_RECENTS_PANEL);
-            mHandler.sendEmptyMessage(TabletStatusBar.MSG_CLOSE_RECENTS_PANEL);
             mHandler.removeMessages(TabletStatusBar.MSG_CLOSE_INPUT_METHODS_PANEL);
             mHandler.sendEmptyMessage(TabletStatusBar.MSG_CLOSE_INPUT_METHODS_PANEL);
             mHandler.removeMessages(TabletStatusBar.MSG_STOP_TICKER);
diff --git a/policy/src/com/android/internal/policy/impl/GlobalActions.java b/policy/src/com/android/internal/policy/impl/GlobalActions.java
index 3fc53aa..0e2d2a8 100644
--- a/policy/src/com/android/internal/policy/impl/GlobalActions.java
+++ b/policy/src/com/android/internal/policy/impl/GlobalActions.java
@@ -56,7 +56,7 @@
 
     private static final String TAG = "GlobalActions";
 
-    private static final boolean SHOW_SILENT_TOGGLE = false;
+    private static final boolean SHOW_SILENT_TOGGLE = true;
 
     private final Context mContext;
     private final AudioManager mAudioManager;
@@ -64,7 +64,7 @@
     private ArrayList<Action> mItems;
     private AlertDialog mDialog;
 
-    private ToggleAction mSilentModeToggle;
+    private SilentModeAction mSilentModeAction;
     private ToggleAction mAirplaneModeOn;
 
     private MyAdapter mAdapter;
@@ -115,39 +115,7 @@
      * @return A new dialog.
      */
     private AlertDialog createDialog() {
-        mSilentModeToggle = new ToggleAction(
-                R.drawable.ic_audio_vol_mute,
-                R.drawable.ic_audio_vol,
-                R.string.global_action_toggle_silent_mode,
-                R.string.global_action_silent_mode_on_status,
-                R.string.global_action_silent_mode_off_status) {
-
-            void willCreate() {
-                mEnabledIconResId =
-                    mAudioManager.getRingerMode() == AudioManager.RINGER_MODE_VIBRATE
-                    ? R.drawable.ic_audio_ring_notif_vibrate
-                    : R.drawable.ic_audio_vol_mute;
-            }
-
-            void onToggle(boolean on) {
-                if (on) {
-                    mAudioManager.setRingerMode((Settings.System.getInt(mContext.getContentResolver(),
-                        Settings.System.VIBRATE_IN_SILENT, 1) == 1)
-                        ? AudioManager.RINGER_MODE_VIBRATE
-                        : AudioManager.RINGER_MODE_SILENT);
-                } else {
-                    mAudioManager.setRingerMode(AudioManager.RINGER_MODE_NORMAL);
-                }
-            }
-
-            public boolean showDuringKeyguard() {
-                return true;
-            }
-
-            public boolean showBeforeProvisioning() {
-                return false;
-            }
-        };
+        mSilentModeAction = new SilentModeAction(mAudioManager, mHandler);
 
         mAirplaneModeOn = new ToggleAction(
                 R.drawable.ic_lock_airplane_mode,
@@ -191,15 +159,7 @@
 
         mItems = new ArrayList<Action>();
 
-        // silent mode
-        if (SHOW_SILENT_TOGGLE) {
-            mItems.add(mSilentModeToggle);
-        }
-
-        // next: airplane mode
-        mItems.add(mAirplaneModeOn);
-
-        // last: power off
+        // first: power off
         mItems.add(
             new SinglePressAction(
                     com.android.internal.R.drawable.ic_lock_power_off,
@@ -219,13 +179,20 @@
                 }
             });
 
+        // next: airplane mode
+        mItems.add(mAirplaneModeOn);
+
+        // last: silent mode
+        if (SHOW_SILENT_TOGGLE) {
+            mItems.add(mSilentModeAction);
+        }
+
         mAdapter = new MyAdapter();
 
         final AlertDialog.Builder ab = new AlertDialog.Builder(mContext);
 
         ab.setAdapter(mAdapter, this)
-                .setInverseBackgroundForced(true)
-                .setTitle(R.string.global_actions);
+                .setInverseBackgroundForced(true);
 
         final AlertDialog dialog = ab.create();
         dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG);
@@ -238,8 +205,6 @@
     private void prepareDialog() {
         final boolean silentModeOn =
                 mAudioManager.getRingerMode() != AudioManager.RINGER_MODE_NORMAL;
-        mSilentModeToggle.updateState(
-                silentModeOn ? ToggleAction.State.On : ToggleAction.State.Off);
         mAirplaneModeOn.updateState(mAirplaneState);
         mAdapter.notifyDataSetChanged();
         if (mKeyguardShowing) {
@@ -247,20 +212,28 @@
         } else {
             mDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG);
         }
+        if (SHOW_SILENT_TOGGLE) {
+            IntentFilter filter = new IntentFilter(AudioManager.RINGER_MODE_CHANGED_ACTION);
+            mContext.registerReceiver(mRingerModeReceiver, filter);
+        }
     }
 
 
     /** {@inheritDoc} */
     public void onDismiss(DialogInterface dialog) {
+        if (SHOW_SILENT_TOGGLE) {
+            mContext.unregisterReceiver(mRingerModeReceiver);
+        }
     }
 
     /** {@inheritDoc} */
     public void onClick(DialogInterface dialog, int which) {
-        dialog.dismiss();
+        if (!(mAdapter.getItem(which) instanceof SilentModeAction)) {
+            dialog.dismiss();
+        }
         mAdapter.getItem(which).onPress();
     }
 
-
     /**
      * The adapter used for the list within the global actions dialog, taking
      * into account whether the keyguard is showing via
@@ -381,9 +354,7 @@
 
         public View create(
                 Context context, View convertView, ViewGroup parent, LayoutInflater inflater) {
-            View v = (convertView != null) ?
-                    convertView :
-                    inflater.inflate(R.layout.global_actions_item, parent, false);
+            View v = inflater.inflate(R.layout.global_actions_item, parent, false);
 
             ImageView icon = (ImageView) v.findViewById(R.id.icon);
             TextView messageView = (TextView) v.findViewById(R.id.message);
@@ -460,27 +431,31 @@
                 LayoutInflater inflater) {
             willCreate();
 
-            View v = (convertView != null) ?
-                    convertView :
-                    inflater.inflate(R
+            View v = inflater.inflate(R
                             .layout.global_actions_item, parent, false);
 
             ImageView icon = (ImageView) v.findViewById(R.id.icon);
             TextView messageView = (TextView) v.findViewById(R.id.message);
             TextView statusView = (TextView) v.findViewById(R.id.status);
+            final boolean enabled = isEnabled();
 
-            messageView.setText(mMessageResId);
+            if (messageView != null) {
+                messageView.setText(mMessageResId);
+                messageView.setEnabled(enabled);
+            }
 
             boolean on = ((mState == State.On) || (mState == State.TurningOn));
-            icon.setImageDrawable(context.getResources().getDrawable(
-                    (on ? mEnabledIconResId : mDisabledIconResid)));
-            statusView.setText(on ? mEnabledStatusMessageResId : mDisabledStatusMessageResId);
-            statusView.setVisibility(View.VISIBLE);
+            if (icon != null) {
+                icon.setImageDrawable(context.getResources().getDrawable(
+                        (on ? mEnabledIconResId : mDisabledIconResid)));
+                icon.setEnabled(enabled);
+            }
 
-            final boolean enabled = isEnabled();
-            messageView.setEnabled(enabled);
-            statusView.setEnabled(enabled);
-            icon.setEnabled(enabled);
+            if (statusView != null) {
+                statusView.setText(on ? mEnabledStatusMessageResId : mDisabledStatusMessageResId);
+                statusView.setVisibility(View.VISIBLE);
+                statusView.setEnabled(enabled);
+            }
             v.setEnabled(enabled);
 
             return v;
@@ -518,6 +493,72 @@
         }
     }
 
+    private static class SilentModeAction implements Action, View.OnClickListener {
+
+        private final int[] ITEM_IDS = { R.id.option1, R.id.option2, R.id.option3 };
+
+        private final AudioManager mAudioManager;
+        private final Handler mHandler;
+
+        SilentModeAction(AudioManager audioManager, Handler handler) {
+            mAudioManager = audioManager;
+            mHandler = handler;
+        }
+
+        private int ringerModeToIndex(int ringerMode) {
+            // They just happen to coincide
+            return ringerMode;
+        }
+
+        private int indexToRingerMode(int index) {
+            // They just happen to coincide
+            return index;
+        }
+
+        public View create(Context context, View convertView, ViewGroup parent,
+                LayoutInflater inflater) {
+            View v = inflater.inflate(R.layout.global_actions_silent_mode, parent, false);
+            // Handle clicks outside the icons and ignore
+            v.setOnClickListener(this);
+
+            int selectedIndex = ringerModeToIndex(mAudioManager.getRingerMode());
+            for (int i = 0; i < 3; i++) {
+                View itemView = v.findViewById(ITEM_IDS[i]);
+                itemView.setSelected(selectedIndex == i);
+                // Set up click handler
+                itemView.setTag(i);
+                itemView.setOnClickListener(this);
+            }
+            return v;
+        }
+
+        public void onPress() {
+        }
+
+        public boolean showDuringKeyguard() {
+            return true;
+        }
+
+        public boolean showBeforeProvisioning() {
+            return false;
+        }
+
+        public boolean isEnabled() {
+            return true;
+        }
+
+        void willCreate() {
+        }
+
+        public void onClick(View v) {
+            if (!(v.getTag() instanceof Integer)) return;
+
+            int index = (Integer) v.getTag();
+            mAudioManager.setRingerMode(indexToRingerMode(index));
+            mHandler.sendEmptyMessageDelayed(MESSAGE_DISMISS, DIALOG_DISMISS_DELAY);
+        }
+    }
+
     private BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
         public void onReceive(Context context, Intent intent) {
             String action = intent.getAction();
@@ -549,13 +590,27 @@
         }
     };
 
+    private BroadcastReceiver mRingerModeReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            if (intent.getAction().equals(AudioManager.RINGER_MODE_CHANGED_ACTION)) {
+                mHandler.sendEmptyMessage(MESSAGE_REFRESH);
+            }
+        }
+    };
+
     private static final int MESSAGE_DISMISS = 0;
+    private static final int MESSAGE_REFRESH = 1;
+    private static final int DIALOG_DISMISS_DELAY = 300; // ms
+
     private Handler mHandler = new Handler() {
         public void handleMessage(Message msg) {
             if (msg.what == MESSAGE_DISMISS) {
                 if (mDialog != null) {
                     mDialog.dismiss();
                 }
+            } else if (msg.what == MESSAGE_REFRESH) {
+                mAdapter.notifyDataSetChanged();
             }
         }
     };
diff --git a/policy/src/com/android/internal/policy/impl/KeyguardViewBase.java b/policy/src/com/android/internal/policy/impl/KeyguardViewBase.java
index de7547b..f204070 100644
--- a/policy/src/com/android/internal/policy/impl/KeyguardViewBase.java
+++ b/policy/src/com/android/internal/policy/impl/KeyguardViewBase.java
@@ -49,7 +49,7 @@
     // Whether the volume keys should be handled by keyguard. If true, then
     // they will be handled here for specific media types such as music, otherwise
     // the audio service will bring up the volume dialog.
-    private static final boolean KEYGUARD_MANAGES_VOLUME = false;
+    private static final boolean KEYGUARD_MANAGES_VOLUME = true;
 
     // This is a faster way to draw the background on devices without hardware acceleration
     Drawable mBackgroundDrawable = new Drawable() {
diff --git a/policy/src/com/android/internal/policy/impl/LockPatternKeyguardView.java b/policy/src/com/android/internal/policy/impl/LockPatternKeyguardView.java
index 7e48357c..67a6855 100644
--- a/policy/src/com/android/internal/policy/impl/LockPatternKeyguardView.java
+++ b/policy/src/com/android/internal/policy/impl/LockPatternKeyguardView.java
@@ -366,14 +366,15 @@
 
             public void takeEmergencyCallAction() {
                 mHasOverlay = true;
-                // FaceLock must be stopped if it is running when emergency call is pressed
-                stopAndUnbindFromFaceLock();
 
                 // Continue showing FaceLock area until dialer comes up or call is resumed
                 if (usingFaceLock() && mFaceLockServiceRunning) {
                     showFaceLockAreaWithTimeout(FACELOCK_VIEW_AREA_EMERGENCY_DIALER_TIMEOUT);
                 }
 
+                // FaceLock must be stopped if it is running when emergency call is pressed
+                stopAndUnbindFromFaceLock();
+
                 pokeWakelock(EMERGENCY_CALL_TIMEOUT);
                 if (TelephonyManager.getDefault().getCallState()
                         == TelephonyManager.CALL_STATE_OFFHOOK) {
diff --git a/services/java/com/android/server/MountService.java b/services/java/com/android/server/MountService.java
index 022b13a..1dd6bca 100644
--- a/services/java/com/android/server/MountService.java
+++ b/services/java/com/android/server/MountService.java
@@ -20,6 +20,7 @@
 import com.android.internal.util.XmlUtils;
 import com.android.server.am.ActivityManagerService;
 import com.android.server.pm.PackageManagerService;
+import com.android.server.NativeDaemonConnector.Command;
 
 import android.Manifest;
 import android.content.BroadcastReceiver;
@@ -564,8 +565,7 @@
         }
 
         try {
-            mConnector.doCommand(String.format(
-                    "volume %sshare %s %s", (enable ? "" : "un"), path, method));
+            mConnector.execute("volume", enable ? "share" : "unshare", path, method);
         } catch (NativeDaemonConnectorException e) {
             Slog.e(TAG, "Failed to share/unshare", e);
         }
@@ -633,8 +633,9 @@
                  * Determine media state and UMS detection status
                  */
                 try {
-                    String[] vols = mConnector.doListCommand(
-                        "volume list", VoldResponseCode.VolumeListResult);
+                    final String[] vols = NativeDaemonEvent.filterMessageList(
+                            mConnector.executeForList("volume", "list"),
+                            VoldResponseCode.VolumeListResult);
                     for (String volstr : vols) {
                         String[] tok = volstr.split(" ");
                         // FMT: <label> <mountpoint> <state>
@@ -839,7 +840,7 @@
 
         if (DEBUG_EVENTS) Slog.i(TAG, "doMountVolume: Mouting " + path);
         try {
-            mConnector.doCommand(String.format("volume mount %s", path));
+            mConnector.execute("volume", "mount", path);
         } catch (NativeDaemonConnectorException e) {
             /*
              * Mount failed for some reason
@@ -909,10 +910,13 @@
         // Redundant probably. But no harm in updating state again.
         mPms.updateExternalMediaStatus(false, false);
         try {
-            String arg = removeEncryption
-                    ? " force_and_revert"
-                    : (force ? " force" : "");
-            mConnector.doCommand(String.format("volume unmount %s%s", path, arg));
+            final Command cmd = new Command("volume", "unmount", path);
+            if (removeEncryption) {
+                cmd.appendArg("force_and_revert");
+            } else if (force) {
+                cmd.appendArg("force");
+            }
+            mConnector.execute(cmd);
             // We unmounted the volume. None of the asec containers are available now.
             synchronized (mAsecMountSet) {
                 mAsecMountSet.clear();
@@ -934,8 +938,7 @@
 
     private int doFormatVolume(String path) {
         try {
-            String cmd = String.format("volume format %s", path);
-            mConnector.doCommand(cmd);
+            mConnector.execute("volume", "format", path);
             return StorageResultCode.OperationSucceeded;
         } catch (NativeDaemonConnectorException e) {
             int code = e.getCode();
@@ -950,39 +953,19 @@
     }
 
     private boolean doGetVolumeShared(String path, String method) {
-        String cmd = String.format("volume shared %s %s", path, method);
-        ArrayList<String> rsp;
-
+        final NativeDaemonEvent event;
         try {
-            rsp = mConnector.doCommand(cmd);
+            event = mConnector.execute("volume", "shared", path, method);
         } catch (NativeDaemonConnectorException ex) {
             Slog.e(TAG, "Failed to read response to volume shared " + path + " " + method);
             return false;
         }
 
-        for (String line : rsp) {
-            String[] tok = line.split(" ");
-            if (tok.length < 3) {
-                Slog.e(TAG, "Malformed response to volume shared " + path + " " + method + " command");
-                return false;
-            }
-
-            int code;
-            try {
-                code = Integer.parseInt(tok[0]);
-            } catch (NumberFormatException nfe) {
-                Slog.e(TAG, String.format("Error parsing code %s", tok[0]));
-                return false;
-            }
-            if (code == VoldResponseCode.ShareEnabledResult) {
-                return "enabled".equals(tok[2]);
-            } else {
-                Slog.e(TAG, String.format("Unexpected response code %d", code));
-                return false;
-            }
+        if (event.getCode() == VoldResponseCode.ShareEnabledResult) {
+            return event.getMessage().endsWith("enabled");
+        } else {
+            return false;
         }
-        Slog.e(TAG, "Got an empty response");
-        return false;
     }
 
     private void notifyShareAvailabilityChange(final boolean avail) {
@@ -1410,13 +1393,14 @@
         validatePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
         waitForReady();
         try {
-            String[] r = mConnector.doListCommand(
-                    String.format("storage users %s", path),
-                            VoldResponseCode.StorageUsersListResult);
+            final String[] r = NativeDaemonEvent.filterMessageList(
+                    mConnector.executeForList("storage", "users", path),
+                    VoldResponseCode.StorageUsersListResult);
+
             // FMT: <pid> <process name>
             int[] data = new int[r.length];
             for (int i = 0; i < r.length; i++) {
-                String []tok = r[i].split(" ");
+                String[] tok = r[i].split(" ");
                 try {
                     data[i] = Integer.parseInt(tok[0]);
                 } catch (NumberFormatException nfe) {
@@ -1443,7 +1427,8 @@
         warnOnNotMounted();
 
         try {
-            return mConnector.doListCommand("asec list", VoldResponseCode.AsecListResult);
+            return NativeDaemonEvent.filterMessageList(
+                    mConnector.executeForList("asec", "list"), VoldResponseCode.AsecListResult);
         } catch (NativeDaemonConnectorException e) {
             return new String[0];
         }
@@ -1456,9 +1441,8 @@
         warnOnNotMounted();
 
         int rc = StorageResultCode.OperationSucceeded;
-        String cmd = String.format("asec create %s %d %s %s %d", id, sizeMb, fstype, key, ownerUid);
         try {
-            mConnector.doCommand(cmd);
+            mConnector.execute("asec", "create", id, sizeMb, fstype, key, ownerUid);
         } catch (NativeDaemonConnectorException e) {
             rc = StorageResultCode.OperationFailedInternalError;
         }
@@ -1477,7 +1461,7 @@
 
         int rc = StorageResultCode.OperationSucceeded;
         try {
-            mConnector.doCommand(String.format("asec finalize %s", id));
+            mConnector.execute("asec", "finalize", id);
             /*
              * Finalization does a remount, so no need
              * to update mAsecMountSet
@@ -1503,7 +1487,11 @@
 
         int rc = StorageResultCode.OperationSucceeded;
         try {
-            mConnector.doCommand(String.format("asec destroy %s%s", id, (force ? " force" : "")));
+            final Command cmd = new Command("asec", "destroy", id);
+            if (force) {
+                cmd.appendArg("force");
+            }
+            mConnector.execute(cmd);
         } catch (NativeDaemonConnectorException e) {
             int code = e.getCode();
             if (code == VoldResponseCode.OpFailedStorageBusy) {
@@ -1536,9 +1524,8 @@
         }
 
         int rc = StorageResultCode.OperationSucceeded;
-        String cmd = String.format("asec mount %s %s %d", id, key, ownerUid);
         try {
-            mConnector.doCommand(cmd);
+            mConnector.execute("asec", "mount", id, key, ownerUid);
         } catch (NativeDaemonConnectorException e) {
             int code = e.getCode();
             if (code != VoldResponseCode.OpFailedStorageBusy) {
@@ -1574,9 +1561,12 @@
         Runtime.getRuntime().gc();
 
         int rc = StorageResultCode.OperationSucceeded;
-        String cmd = String.format("asec unmount %s%s", id, (force ? " force" : ""));
         try {
-            mConnector.doCommand(cmd);
+            final Command cmd = new Command("asec", "unmount", id);
+            if (force) {
+                cmd.appendArg("force");
+            }
+            mConnector.execute(cmd);
         } catch (NativeDaemonConnectorException e) {
             int code = e.getCode();
             if (code == VoldResponseCode.OpFailedStorageBusy) {
@@ -1620,9 +1610,8 @@
         }
 
         int rc = StorageResultCode.OperationSucceeded;
-        String cmd = String.format("asec rename %s %s", oldId, newId);
         try {
-            mConnector.doCommand(cmd);
+            mConnector.execute("asec", "rename", oldId, newId);
         } catch (NativeDaemonConnectorException e) {
             rc = StorageResultCode.OperationFailedInternalError;
         }
@@ -1635,14 +1624,11 @@
         waitForReady();
         warnOnNotMounted();
 
+        final NativeDaemonEvent event;
         try {
-            ArrayList<String> rsp = mConnector.doCommand(String.format("asec path %s", id));
-            String []tok = rsp.get(0).split(" ");
-            int code = Integer.parseInt(tok[0]);
-            if (code != VoldResponseCode.AsecPathResult) {
-                throw new IllegalStateException(String.format("Unexpected response code %d", code));
-            }
-            return tok[1];
+            event = mConnector.execute("asec", "path", id);
+            event.checkCode(VoldResponseCode.AsecPathResult);
+            return event.getMessage();
         } catch (NativeDaemonConnectorException e) {
             int code = e.getCode();
             if (code == VoldResponseCode.OpFailedStorageNotFound) {
@@ -1659,14 +1645,11 @@
         waitForReady();
         warnOnNotMounted();
 
+        final NativeDaemonEvent event;
         try {
-            ArrayList<String> rsp = mConnector.doCommand(String.format("asec fspath %s", id));
-            String []tok = rsp.get(0).split(" ");
-            int code = Integer.parseInt(tok[0]);
-            if (code != VoldResponseCode.AsecPathResult) {
-                throw new IllegalStateException(String.format("Unexpected response code %d", code));
-            }
-            return tok[1];
+            event = mConnector.execute("asec", "fspath", id);
+            event.checkCode(VoldResponseCode.AsecPathResult);
+            return event.getMessage();
         } catch (NativeDaemonConnectorException e) {
             int code = e.getCode();
             if (code == VoldResponseCode.OpFailedStorageNotFound) {
@@ -1709,14 +1692,11 @@
         waitForReady();
         warnOnNotMounted();
 
+        final NativeDaemonEvent event;
         try {
-            ArrayList<String> rsp = mConnector.doCommand(String.format("obb path %s", filename));
-            String []tok = rsp.get(0).split(" ");
-            int code = Integer.parseInt(tok[0]);
-            if (code != VoldResponseCode.AsecPathResult) {
-                throw new IllegalStateException(String.format("Unexpected response code %d", code));
-            }
-            return tok[1];
+            event = mConnector.execute("obb", "path", filename);
+            event.checkCode(VoldResponseCode.AsecPathResult);
+            return event.getMessage();
         } catch (NativeDaemonConnectorException e) {
             int code = e.getCode();
             if (code == VoldResponseCode.OpFailedStorageNotFound) {
@@ -1778,18 +1758,10 @@
 
         waitForReady();
 
+        final NativeDaemonEvent event;
         try {
-            ArrayList<String> rsp = mConnector.doCommand("cryptfs cryptocomplete");
-            String[] tokens = rsp.get(0).split(" ");
-
-            if (tokens == null || tokens.length != 2) {
-                // Unexpected.
-                Slog.w(TAG, "Unexpected result from cryptfs cryptocomplete");
-                return ENCRYPTION_STATE_ERROR_UNKNOWN;
-            }
-
-            return Integer.parseInt(tokens[1]);
-
+            event = mConnector.execute("cryptfs", "cryptocomplete");
+            return Integer.parseInt(event.getMessage());
         } catch (NumberFormatException e) {
             // Bad result - unexpected.
             Slog.w(TAG, "Unable to parse result from cryptfs cryptocomplete");
@@ -1816,23 +1788,18 @@
             Slog.i(TAG, "decrypting storage...");
         }
 
+        final NativeDaemonEvent event;
         try {
-            ArrayList<String> rsp = mConnector.doCommand("cryptfs checkpw " + password);
-            String[] tokens = rsp.get(0).split(" ");
+            event = mConnector.execute("cryptfs", "checkpw", password);
 
-            if (tokens == null || tokens.length != 2) {
-                return -1;
-            }
-
-            int code = Integer.parseInt(tokens[1]);
-
+            final int code = event.getCode();
             if (code == 0) {
                 // Decrypt was successful. Post a delayed message before restarting in order
                 // to let the UI to clear itself
                 mHandler.postDelayed(new Runnable() {
                     public void run() {
                         try {
-                            mConnector.doCommand(String.format("cryptfs restart"));
+                            mConnector.execute("cryptfs", "restart");
                         } catch (NativeDaemonConnectorException e) {
                             Slog.e(TAG, "problem executing in background", e);
                         }
@@ -1862,7 +1829,7 @@
         }
 
         try {
-            mConnector.doCommand(String.format("cryptfs enablecrypto inplace %s", password));
+            mConnector.execute("cryptfs", "enablecrypto", "inplace", password);
         } catch (NativeDaemonConnectorException e) {
             // Encryption failed
             return e.getCode();
@@ -1885,16 +1852,10 @@
             Slog.i(TAG, "changing encryption password...");
         }
 
+        final NativeDaemonEvent event;
         try {
-            ArrayList<String> response = mConnector.doCommand("cryptfs changepw " + password);
-
-            String[] tokens = response.get(0).split(" ");
-
-            if (tokens == null || tokens.length != 2) {
-                return -1;
-            }
-
-            return Integer.parseInt(tokens[1]);
+            event = mConnector.execute("cryptfs", "changepw", password);
+            return Integer.parseInt(event.getMessage());
         } catch (NativeDaemonConnectorException e) {
             // Encryption failed
             return e.getCode();
@@ -1924,24 +1885,11 @@
             Slog.i(TAG, "validating encryption password...");
         }
 
+        final NativeDaemonEvent event;
         try {
-            ArrayList<String> response = mConnector.doCommand("cryptfs verifypw " + password);
-            String[] tokens = response.get(0).split(" ");
-
-            if (tokens == null || tokens.length != 2) {
-                String msg = "Unexpected result from cryptfs verifypw: {";
-                if (tokens == null) msg += "null";
-                else for (int i = 0; i < tokens.length; i++) {
-                    if (i != 0) msg += ',';
-                    msg += tokens[i];
-                }
-                msg += '}';
-                Slog.e(TAG, msg);
-                return -1;
-            }
-
-            Slog.i(TAG, "cryptfs verifypw => " + tokens[1]);
-            return Integer.parseInt(tokens[1]);
+            event = mConnector.execute("cryptfs", "verifypw", password);
+            Slog.i(TAG, "cryptfs verifypw => " + event.getMessage());
+            return Integer.parseInt(event.getMessage());
         } catch (NativeDaemonConnectorException e) {
             // Encryption failed
             return e.getCode();
@@ -2300,10 +2248,9 @@
             }
 
             int rc = StorageResultCode.OperationSucceeded;
-            String cmd = String.format("obb mount %s %s %d", mObbState.filename, hashedKey,
-                    mObbState.callerUid);
             try {
-                mConnector.doCommand(cmd);
+                mConnector.execute(
+                        "obb", "mount", mObbState.filename, hashedKey, mObbState.callerUid);
             } catch (NativeDaemonConnectorException e) {
                 int code = e.getCode();
                 if (code != VoldResponseCode.OpFailedStorageBusy) {
@@ -2384,10 +2331,12 @@
             mObbState.filename = obbInfo.filename;
 
             int rc = StorageResultCode.OperationSucceeded;
-            String cmd = String.format("obb unmount %s%s", mObbState.filename,
-                    (mForceUnmount ? " force" : ""));
             try {
-                mConnector.doCommand(cmd);
+                final Command cmd = new Command("obb", "unmount", mObbState.filename);
+                if (mForceUnmount) {
+                    cmd.appendArg("force");
+                }
+                mConnector.execute(cmd);
             } catch (NativeDaemonConnectorException e) {
                 int code = e.getCode();
                 if (code == VoldResponseCode.OpFailedStorageBusy) {
diff --git a/tests/RenderScriptTests/ModelViewer/src/com/android/modelviewer/simplemodel.rs b/tests/RenderScriptTests/ModelViewer/src/com/android/modelviewer/simplemodel.rs
index 8cec409..de2a0a7 100644
--- a/tests/RenderScriptTests/ModelViewer/src/com/android/modelviewer/simplemodel.rs
+++ b/tests/RenderScriptTests/ModelViewer/src/com/android/modelviewer/simplemodel.rs
@@ -48,6 +48,14 @@
 static float gLastX;
 static float gLastY;
 
+static float3 toFloat3(float x, float y, float z) {
+    float3 f;
+    f.x = x;
+    f.y = y;
+    f.z = z;
+    return f;
+}
+
 void onActionDown(float x, float y) {
     gLastX = x;
     gLastY = y;
@@ -104,8 +112,8 @@
         rsgMeshComputeBoundingBox(info->mMesh,
                                   &minX, &minY, &minZ,
                                   &maxX, &maxY, &maxZ);
-        info->bBoxMin = (minX, minY, minZ);
-        info->bBoxMax = (maxX, maxY, maxZ);
+        info->bBoxMin = toFloat3(minX, minY, minZ);
+        info->bBoxMax = toFloat3(maxX, maxY, maxZ);
         gLookAt += (info->bBoxMin + info->bBoxMax)*0.5f;
     }
     gLookAt = gLookAt / (float)size;
diff --git a/tests/RenderScriptTests/ShadersTest/src/com/android/shaderstest/shaderstest.rs b/tests/RenderScriptTests/ShadersTest/src/com/android/shaderstest/shaderstest.rs
index 53f10f9..ae32e3a 100644
--- a/tests/RenderScriptTests/ShadersTest/src/com/android/shaderstest/shaderstest.rs
+++ b/tests/RenderScriptTests/ShadersTest/src/com/android/shaderstest/shaderstest.rs
@@ -57,6 +57,14 @@
 static float gLastX;
 static float gLastY;
 
+static float3 toFloat3(float x, float y, float z) {
+    float3 f;
+    f.x = x;
+    f.y = y;
+    f.z = z;
+    return f;
+}
+
 void onActionDown(float x, float y) {
     gLastX = x;
     gLastY = y;
@@ -112,8 +120,8 @@
         rsgMeshComputeBoundingBox(info->mMesh,
                                   &minX, &minY, &minZ,
                                   &maxX, &maxY, &maxZ);
-        info->bBoxMin = (minX, minY, minZ);
-        info->bBoxMax = (maxX, maxY, maxZ);
+        info->bBoxMin = toFloat3(minX, minY, minZ);
+        info->bBoxMax = toFloat3(maxX, maxY, maxZ);
         gLookAt += (info->bBoxMin + info->bBoxMax)*0.5f;
     }
     gLookAt = gLookAt / (float)size;
diff --git a/tools/layoutlib/create/.classpath b/tools/layoutlib/create/.classpath
index 0c60f6a..734ebdc 100644
--- a/tools/layoutlib/create/.classpath
+++ b/tools/layoutlib/create/.classpath
@@ -4,6 +4,6 @@
 	<classpathentry excluding="mock_android/" kind="src" path="tests"/>
 	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
 	<classpathentry kind="con" path="org.eclipse.jdt.junit.JUNIT_CONTAINER/4"/>
-	<classpathentry kind="var" path="ANDROID_SRC/prebuilt/common/asm/asm-3.1.jar"/>
+	<classpathentry kind="var" path="ANDROID_SRC/prebuilt/common/asm/asm-4.0.jar"/>
 	<classpathentry kind="output" path="bin"/>
 </classpath>
diff --git a/tools/layoutlib/create/Android.mk b/tools/layoutlib/create/Android.mk
index 310fae5..9bd48ab 100644
--- a/tools/layoutlib/create/Android.mk
+++ b/tools/layoutlib/create/Android.mk
@@ -20,7 +20,7 @@
 
 LOCAL_JAR_MANIFEST := manifest.txt
 LOCAL_STATIC_JAVA_LIBRARIES := \
-	asm-3.1
+	asm-4.0
 
 LOCAL_MODULE := layoutlib_create
 
diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/AsmAnalyzer.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/AsmAnalyzer.java
index b197ea7..412695f 100644
--- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/AsmAnalyzer.java
+++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/AsmAnalyzer.java
@@ -23,6 +23,7 @@
 import org.objectweb.asm.FieldVisitor;
 import org.objectweb.asm.Label;
 import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.Opcodes;
 import org.objectweb.asm.Type;
 import org.objectweb.asm.signature.SignatureReader;
 import org.objectweb.asm.signature.SignatureVisitor;
@@ -32,8 +33,8 @@
 import java.util.Enumeration;
 import java.util.List;
 import java.util.Map;
-import java.util.TreeMap;
 import java.util.Map.Entry;
+import java.util.TreeMap;
 import java.util.regex.Pattern;
 import java.util.zip.ZipEntry;
 import java.util.zip.ZipFile;
@@ -45,7 +46,7 @@
 public class AsmAnalyzer {
 
     // Note: a bunch of stuff has package-level access for unit tests. Consider it private.
-    
+
     /** Output logger. */
     private final Log mLog;
     /** The input source JAR to parse. */
@@ -59,11 +60,11 @@
 
     /**
      * Creates a new analyzer.
-     * 
+     *
      * @param log The log output.
      * @param osJarPath The input source JARs to parse.
      * @param gen The generator to fill with the class list and dependency list.
-     * @param deriveFrom Keep all classes that derive from these one (these included). 
+     * @param deriveFrom Keep all classes that derive from these one (these included).
      * @param includeGlobs Glob patterns of classes to keep, e.g. "com.foo.*"
      *        ("*" does not matches dots whilst "**" does, "." and "$" are interpreted as-is)
      */
@@ -83,14 +84,14 @@
     public void analyze() throws IOException, LogAbortException {
 
         AsmAnalyzer visitor = this;
-        
+
         Map<String, ClassReader> zipClasses = parseZip(mOsSourceJar);
         mLog.info("Found %d classes in input JAR%s.", zipClasses.size(),
                 mOsSourceJar.size() > 1 ? "s" : "");
-        
+
         Map<String, ClassReader> found = findIncludes(zipClasses);
         Map<String, ClassReader> deps = findDeps(zipClasses, found);
-        
+
         if (mGen != null) {
             mGen.setKeep(found);
             mGen.setDeps(deps);
@@ -117,10 +118,10 @@
                 }
             }
         }
-        
+
         return classes;
     }
-    
+
     /**
      * Utility that returns the fully qualified binary class name for a ClassReader.
      * E.g. it returns something like android.view.View.
@@ -132,7 +133,7 @@
             return classReader.getClassName().replace('/', '.');
         }
     }
-    
+
     /**
      * Utility that returns the fully qualified binary class name from a path-like FQCN.
      * E.g. it returns android.view.View from android/view/View.
@@ -144,7 +145,7 @@
             return className.replace('/', '.');
         }
     }
-    
+
     /**
      * Process the "includes" arrays.
      * <p/>
@@ -162,11 +163,11 @@
         for (String s : mDeriveFrom) {
             findClassesDerivingFrom(s, zipClasses, found);
         }
-        
+
         return found;
     }
 
-    
+
     /**
      * Uses ASM to find the class reader for the given FQCN class name.
      * If found, insert it in the in_out_found map.
@@ -215,7 +216,7 @@
         globPattern += "$";
 
         Pattern regexp = Pattern.compile(globPattern);
-        
+
         for (Entry<String, ClassReader> entry : zipClasses.entrySet()) {
             String class_name = entry.getKey();
             if (regexp.matcher(class_name).matches()) {
@@ -284,7 +285,7 @@
         for (ClassReader cr : inOutKeepClasses.values()) {
             cr.accept(visitor, 0 /* flags */);
         }
-        
+
         while (new_deps.size() > 0 || new_keep.size() > 0) {
             deps.putAll(new_deps);
             inOutKeepClasses.putAll(new_keep);
@@ -308,15 +309,14 @@
         return deps;
     }
 
-    
+
 
     // ----------------------------------
-    
+
     /**
-     * Visitor to collect all the type dependencies from a class. 
+     * Visitor to collect all the type dependencies from a class.
      */
-    public class DependencyVisitor
-        implements ClassVisitor, FieldVisitor, MethodVisitor, SignatureVisitor, AnnotationVisitor {
+    public class DependencyVisitor extends ClassVisitor {
 
         /** All classes found in the source JAR. */
         private final Map<String, ClassReader> mZipClasses;
@@ -333,7 +333,7 @@
          * Creates a new visitor that will find all the dependencies for the visited class.
          * Types which are already in the zipClasses, keepClasses or inDeps are not marked.
          * New dependencies are marked in outDeps.
-         * 
+         *
          * @param zipClasses All classes found in the source JAR.
          * @param inKeep Classes from which dependencies are to be found.
          * @param inDeps Dependencies already known.
@@ -344,13 +344,14 @@
                 Map<String, ClassReader> outKeep,
                 Map<String,ClassReader> inDeps,
                 Map<String,ClassReader> outDeps) {
+            super(Opcodes.ASM4);
             mZipClasses = zipClasses;
             mInKeep = inKeep;
             mOutKeep = outKeep;
             mInDeps = inDeps;
             mOutDeps = outDeps;
         }
-        
+
         /**
          * Considers the given class name as a dependency.
          * If it does, add to the mOutDeps map.
@@ -361,7 +362,7 @@
             }
 
             className = internalToBinaryClassName(className);
-            
+
             // exclude classes that have already been found
             if (mInKeep.containsKey(className) ||
                     mOutKeep.containsKey(className) ||
@@ -384,7 +385,7 @@
             } catch (ClassNotFoundException e) {
                 // ignore
             }
-            
+
             // accept this class:
             // - android classes are added to dependencies
             // - non-android classes are added to the list of classes to keep as-is (they don't need
@@ -395,7 +396,7 @@
                 mOutKeep.put(className, cr);
             }
         }
-        
+
         /**
          * Considers this array of names using considerName().
          */
@@ -416,7 +417,7 @@
                 SignatureReader sr = new SignatureReader(signature);
                 // SignatureReader.accept will call accessType so we don't really have
                 // to differentiate where the signature comes from.
-                sr.accept(this);
+                sr.accept(new MySignatureVisitor());
             }
         }
 
@@ -450,17 +451,18 @@
             }
         }
 
-        
+
         // ---------------------------------------------------
         // --- ClassVisitor, FieldVisitor
         // ---------------------------------------------------
 
         // Visits a class header
+        @Override
         public void visit(int version, int access, String name,
                 String signature, String superName, String[] interfaces) {
             // signature is the signature of this class. May be null if the class is not a generic
             // one, and does not extend or implement generic classes or interfaces.
-            
+
             if (signature != null) {
                 considerSignature(signature);
             }
@@ -468,27 +470,57 @@
             // superName is the internal of name of the super class (see getInternalName).
             // For interfaces, the super class is Object. May be null but only for the Object class.
             considerName(superName);
-            
+
             // interfaces is the internal names of the class's interfaces (see getInternalName).
             // May be null.
             considerNames(interfaces);
         }
 
+
+        @Override
         public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
             // desc is the class descriptor of the annotation class.
             considerDesc(desc);
-            return this; // return this to visit annotion values
+            return new MyAnnotationVisitor();
         }
 
+        @Override
         public void visitAttribute(Attribute attr) {
             // pass
         }
 
         // Visits the end of a class
+        @Override
         public void visitEnd() {
             // pass
         }
 
+        private class MyFieldVisitor extends FieldVisitor {
+
+            public MyFieldVisitor() {
+                super(Opcodes.ASM4);
+            }
+
+            @Override
+            public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
+                // desc is the class descriptor of the annotation class.
+                considerDesc(desc);
+                return new MyAnnotationVisitor();
+            }
+
+            @Override
+            public void visitAttribute(Attribute attr) {
+                // pass
+            }
+
+            // Visits the end of a class
+            @Override
+            public void visitEnd() {
+                // pass
+            }
+        }
+
+        @Override
         public FieldVisitor visitField(int access, String name, String desc,
                 String signature, Object value) {
             // desc is the field's descriptor (see Type).
@@ -498,14 +530,16 @@
             // generic types.
             considerSignature(signature);
 
-            return this; // a visitor to visit field annotations and attributes
+            return new MyFieldVisitor();
         }
 
+        @Override
         public void visitInnerClass(String name, String outerName, String innerName, int access) {
             // name is the internal name of an inner class (see getInternalName).
             considerName(name);
         }
 
+        @Override
         public MethodVisitor visitMethod(int access, String name, String desc,
                 String signature, String[] exceptions) {
             // desc is the method's descriptor (see Type).
@@ -513,239 +547,299 @@
             // signature is the method's signature. May be null if the method parameters, return
             // type and exceptions do not use generic types.
             considerSignature(signature);
-            
-            return this; // returns this to visit the method
+
+            return new MyMethodVisitor();
         }
 
+        @Override
         public void visitOuterClass(String owner, String name, String desc) {
             // pass
         }
 
+        @Override
         public void visitSource(String source, String debug) {
             // pass
         }
 
-        
+
         // ---------------------------------------------------
         // --- MethodVisitor
         // ---------------------------------------------------
 
-        public AnnotationVisitor visitAnnotationDefault() {
-            return this; // returns this to visit the default value
-        }
+        private class MyMethodVisitor extends MethodVisitor {
+
+            public MyMethodVisitor() {
+                super(Opcodes.ASM4);
+            }
 
 
-        public void visitCode() {
-            // pass
-        }
+            @Override
+            public AnnotationVisitor visitAnnotationDefault() {
+                return new MyAnnotationVisitor();
+            }
 
-        // field instruction
-        public void visitFieldInsn(int opcode, String owner, String name, String desc) {
-            // name is the field's name.
-            considerName(name);
-            // desc is the field's descriptor (see Type).
-            considerDesc(desc);
-        }
+            @Override
+            public void visitCode() {
+                // pass
+            }
 
-        public void visitFrame(int type, int local, Object[] local2, int stack, Object[] stack2) {
-            // pass
-        }
+            // field instruction
+            @Override
+            public void visitFieldInsn(int opcode, String owner, String name, String desc) {
+                // name is the field's name.
+                considerName(name);
+                // desc is the field's descriptor (see Type).
+                considerDesc(desc);
+            }
 
-        public void visitIincInsn(int var, int increment) {
-            // pass -- an IINC instruction
-        }
+            @Override
+            public void visitFrame(int type, int local, Object[] local2, int stack, Object[] stack2) {
+                // pass
+            }
 
-        public void visitInsn(int opcode) {
-            // pass -- a zero operand instruction
-        }
+            @Override
+            public void visitIincInsn(int var, int increment) {
+                // pass -- an IINC instruction
+            }
 
-        public void visitIntInsn(int opcode, int operand) {
-            // pass -- a single int operand instruction
-        }
+            @Override
+            public void visitInsn(int opcode) {
+                // pass -- a zero operand instruction
+            }
 
-        public void visitJumpInsn(int opcode, Label label) {
-            // pass -- a jump instruction
-        }
+            @Override
+            public void visitIntInsn(int opcode, int operand) {
+                // pass -- a single int operand instruction
+            }
 
-        public void visitLabel(Label label) {
-            // pass -- a label target
-        }
+            @Override
+            public void visitJumpInsn(int opcode, Label label) {
+                // pass -- a jump instruction
+            }
 
-        // instruction to load a constant from the stack
-        public void visitLdcInsn(Object cst) {
-            if (cst instanceof Type) {
-                considerType((Type) cst);
+            @Override
+            public void visitLabel(Label label) {
+                // pass -- a label target
+            }
+
+            // instruction to load a constant from the stack
+            @Override
+            public void visitLdcInsn(Object cst) {
+                if (cst instanceof Type) {
+                    considerType((Type) cst);
+                }
+            }
+
+            @Override
+            public void visitLineNumber(int line, Label start) {
+                // pass
+            }
+
+            @Override
+            public void visitLocalVariable(String name, String desc,
+                    String signature, Label start, Label end, int index) {
+                // desc is the type descriptor of this local variable.
+                considerDesc(desc);
+                // signature is the type signature of this local variable. May be null if the local
+                // variable type does not use generic types.
+                considerSignature(signature);
+            }
+
+            @Override
+            public void visitLookupSwitchInsn(Label dflt, int[] keys, Label[] labels) {
+                // pass -- a lookup switch instruction
+            }
+
+            @Override
+            public void visitMaxs(int maxStack, int maxLocals) {
+                // pass
+            }
+
+            // instruction that invokes a method
+            @Override
+            public void visitMethodInsn(int opcode, String owner, String name, String desc) {
+
+                // owner is the internal name of the method's owner class
+                considerName(owner);
+                // desc is the method's descriptor (see Type).
+                considerDesc(desc);
+            }
+
+            // instruction multianewarray, whatever that is
+            @Override
+            public void visitMultiANewArrayInsn(String desc, int dims) {
+
+                // desc an array type descriptor.
+                considerDesc(desc);
+            }
+
+            @Override
+            public AnnotationVisitor visitParameterAnnotation(int parameter, String desc,
+                    boolean visible) {
+                // desc is the class descriptor of the annotation class.
+                considerDesc(desc);
+                return new MyAnnotationVisitor();
+            }
+
+            @Override
+            public void visitTableSwitchInsn(int min, int max, Label dflt, Label[] labels) {
+                // pass -- table switch instruction
+
+            }
+
+            @Override
+            public void visitTryCatchBlock(Label start, Label end, Label handler, String type) {
+                // type is the internal name of the type of exceptions handled by the handler,
+                // or null to catch any exceptions (for "finally" blocks).
+                considerName(type);
+            }
+
+            // type instruction
+            @Override
+            public void visitTypeInsn(int opcode, String type) {
+                // type is the operand of the instruction to be visited. This operand must be the
+                // internal name of an object or array class.
+                considerName(type);
+            }
+
+            @Override
+            public void visitVarInsn(int opcode, int var) {
+                // pass -- local variable instruction
             }
         }
 
-        public void visitLineNumber(int line, Label start) {
-            // pass
-        }
+        private class MySignatureVisitor extends SignatureVisitor {
 
-        public void visitLocalVariable(String name, String desc,
-                String signature, Label start, Label end, int index) {
-            // desc is the type descriptor of this local variable.
-            considerDesc(desc);
-            // signature is the type signature of this local variable. May be null if the local
-            // variable type does not use generic types.
-            considerSignature(signature);
-        }
+            public MySignatureVisitor() {
+                super(Opcodes.ASM4);
+            }
 
-        public void visitLookupSwitchInsn(Label dflt, int[] keys, Label[] labels) {
-            // pass -- a lookup switch instruction
-        }
+            // ---------------------------------------------------
+            // --- SignatureVisitor
+            // ---------------------------------------------------
 
-        public void visitMaxs(int maxStack, int maxLocals) {
-            // pass
-        }
+            private String mCurrentSignatureClass = null;
 
-        // instruction that invokes a method
-        public void visitMethodInsn(int opcode, String owner, String name, String desc) {
-            
-            // owner is the internal name of the method's owner class
-            considerName(owner);
-            // desc is the method's descriptor (see Type).
-            considerDesc(desc);
-        }
+            // Starts the visit of a signature corresponding to a class or interface type
+            @Override
+            public void visitClassType(String name) {
+                mCurrentSignatureClass = name;
+                considerName(name);
+            }
 
-        // instruction multianewarray, whatever that is
-        public void visitMultiANewArrayInsn(String desc, int dims) {
-            
-            // desc an array type descriptor.
-            considerDesc(desc);
-        }
+            // Visits an inner class
+            @Override
+            public void visitInnerClassType(String name) {
+                if (mCurrentSignatureClass != null) {
+                    mCurrentSignatureClass += "$" + name;
+                    considerName(mCurrentSignatureClass);
+                }
+            }
 
-        public AnnotationVisitor visitParameterAnnotation(int parameter, String desc,
-                boolean visible) {
-            // desc is the class descriptor of the annotation class.
-            considerDesc(desc);
-            return this; // return this to visit annotation values
-        }
+            @Override
+            public SignatureVisitor visitArrayType() {
+                return new MySignatureVisitor();
+            }
 
-        public void visitTableSwitchInsn(int min, int max, Label dflt, Label[] labels) {
-            // pass -- table switch instruction
-            
-        }
+            @Override
+            public void visitBaseType(char descriptor) {
+                // pass -- a primitive type, ignored
+            }
 
-        public void visitTryCatchBlock(Label start, Label end, Label handler, String type) {
-            // type is the internal name of the type of exceptions handled by the handler,
-            // or null to catch any exceptions (for "finally" blocks).
-            considerName(type);
-        }
+            @Override
+            public SignatureVisitor visitClassBound() {
+                return new MySignatureVisitor();
+            }
 
-        // type instruction
-        public void visitTypeInsn(int opcode, String type) {
-            // type is the operand of the instruction to be visited. This operand must be the
-            // internal name of an object or array class.
-            considerName(type);
-        }
+            @Override
+            public SignatureVisitor visitExceptionType() {
+                return new MySignatureVisitor();
+            }
 
-        public void visitVarInsn(int opcode, int var) {
-            // pass -- local variable instruction 
-        }
+            @Override
+            public void visitFormalTypeParameter(String name) {
+                // pass
+            }
 
-        
-        // ---------------------------------------------------
-        // --- SignatureVisitor
-        // ---------------------------------------------------
+            @Override
+            public SignatureVisitor visitInterface() {
+                return new MySignatureVisitor();
+            }
 
-        private String mCurrentSignatureClass = null;
+            @Override
+            public SignatureVisitor visitInterfaceBound() {
+                return new MySignatureVisitor();
+            }
 
-        // Starts the visit of a signature corresponding to a class or interface type
-        public void visitClassType(String name) {
-            mCurrentSignatureClass = name;
-            considerName(name);
-        }
+            @Override
+            public SignatureVisitor visitParameterType() {
+                return new MySignatureVisitor();
+            }
 
-        // Visits an inner class
-        public void visitInnerClassType(String name) {
-            if (mCurrentSignatureClass != null) {
-                mCurrentSignatureClass += "$" + name;
-                considerName(mCurrentSignatureClass);
+            @Override
+            public SignatureVisitor visitReturnType() {
+                return new MySignatureVisitor();
+            }
+
+            @Override
+            public SignatureVisitor visitSuperclass() {
+                return new MySignatureVisitor();
+            }
+
+            @Override
+            public SignatureVisitor visitTypeArgument(char wildcard) {
+                return new MySignatureVisitor();
+            }
+
+            @Override
+            public void visitTypeVariable(String name) {
+                // pass
+            }
+
+            @Override
+            public void visitTypeArgument() {
+                // pass
             }
         }
 
-        public SignatureVisitor visitArrayType() {
-            return this; // returns this to visit the signature of the array element type
-        }
 
-        public void visitBaseType(char descriptor) {
-            // pass -- a primitive type, ignored
-        }
-
-        public SignatureVisitor visitClassBound() {
-            return this; // returns this to visit the signature of the class bound
-        }
-
-        public SignatureVisitor visitExceptionType() {
-            return this; // return this to visit the signature of the exception type.
-        }
-
-        public void visitFormalTypeParameter(String name) {
-            // pass
-        }
-
-        public SignatureVisitor visitInterface() {
-            return this; // returns this to visit the signature of the interface type
-        }
-
-        public SignatureVisitor visitInterfaceBound() {
-            return this; // returns this to visit the signature of the interface bound
-        }
-
-        public SignatureVisitor visitParameterType() {
-            return this; // returns this to visit the signature of the parameter type
-        }
-
-        public SignatureVisitor visitReturnType() {
-            return this; // returns this to visit the signature of the return type
-        }
-
-        public SignatureVisitor visitSuperclass() {
-            return this; // returns this to visit the signature of the super class type
-        }
-
-        public SignatureVisitor visitTypeArgument(char wildcard) {
-            return this; // returns this to visit the signature of the type argument
-        }
-
-        public void visitTypeVariable(String name) {
-            // pass
-        }
-
-        public void visitTypeArgument() {
-            // pass
-        }
-        
-        
         // ---------------------------------------------------
         // --- AnnotationVisitor
         // ---------------------------------------------------
 
+        private class MyAnnotationVisitor extends AnnotationVisitor {
 
-        // Visits a primitive value of an annotation
-        public void visit(String name, Object value) {
-            // value is the actual value, whose type must be Byte, Boolean, Character, Short,
-            // Integer, Long, Float, Double, String or Type
-            if (value instanceof Type) {
-                considerType((Type) value);
+            public MyAnnotationVisitor() {
+                super(Opcodes.ASM4);
+            }
+
+            // Visits a primitive value of an annotation
+            @Override
+            public void visit(String name, Object value) {
+                // value is the actual value, whose type must be Byte, Boolean, Character, Short,
+                // Integer, Long, Float, Double, String or Type
+                if (value instanceof Type) {
+                    considerType((Type) value);
+                }
+            }
+
+            @Override
+            public AnnotationVisitor visitAnnotation(String name, String desc) {
+                // desc is the class descriptor of the nested annotation class.
+                considerDesc(desc);
+                return new MyAnnotationVisitor();
+            }
+
+            @Override
+            public AnnotationVisitor visitArray(String name) {
+                return new MyAnnotationVisitor();
+            }
+
+            @Override
+            public void visitEnum(String name, String desc, String value) {
+                // desc is the class descriptor of the enumeration class.
+                considerDesc(desc);
             }
         }
-
-        public AnnotationVisitor visitAnnotation(String name, String desc) {
-            // desc is the class descriptor of the nested annotation class.
-            considerDesc(desc);
-            return this; // returns this to visit the actual nested annotation value
-        }
-
-        public AnnotationVisitor visitArray(String name) {
-            return this; // returns this to visit the actual array value elements
-        }
-
-        public void visitEnum(String name, String desc, String value) {
-            // desc is the class descriptor of the enumeration class.
-            considerDesc(desc);
-        }
-        
     }
 }
diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/ClassHasNativeVisitor.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/ClassHasNativeVisitor.java
index 722dce2..2c955fd 100644
--- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/ClassHasNativeVisitor.java
+++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/ClassHasNativeVisitor.java
@@ -29,7 +29,10 @@
 /**
  * Indicates if a class contains any native methods.
  */
-public class ClassHasNativeVisitor implements ClassVisitor {
+public class ClassHasNativeVisitor extends ClassVisitor {
+    public ClassHasNativeVisitor() {
+        super(Opcodes.ASM4);
+    }
 
     private boolean mHasNativeMethods = false;
 
@@ -42,35 +45,42 @@
         mHasNativeMethods = hasNativeMethods;
     }
 
+    @Override
     public void visit(int version, int access, String name, String signature,
             String superName, String[] interfaces) {
         // pass
     }
 
+    @Override
     public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
         // pass
         return null;
     }
 
+    @Override
     public void visitAttribute(Attribute attr) {
         // pass
     }
 
+    @Override
     public void visitEnd() {
         // pass
     }
 
+    @Override
     public FieldVisitor visitField(int access, String name, String desc,
             String signature, Object value) {
         // pass
         return null;
     }
 
+    @Override
     public void visitInnerClass(String name, String outerName,
             String innerName, int access) {
         // pass
     }
 
+    @Override
     public MethodVisitor visitMethod(int access, String name, String desc,
             String signature, String[] exceptions) {
         if ((access & Opcodes.ACC_NATIVE) != 0) {
@@ -79,10 +89,12 @@
         return null;
     }
 
+    @Override
     public void visitOuterClass(String owner, String name, String desc) {
         // pass
     }
 
+    @Override
     public void visitSource(String source, String debug) {
         // pass
     }
diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/DelegateClassAdapter.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/DelegateClassAdapter.java
index 0e24cc0..927be97 100644
--- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/DelegateClassAdapter.java
+++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/DelegateClassAdapter.java
@@ -16,7 +16,6 @@
 
 package com.android.tools.layoutlib.create;
 
-import org.objectweb.asm.ClassAdapter;
 import org.objectweb.asm.ClassVisitor;
 import org.objectweb.asm.MethodVisitor;
 import org.objectweb.asm.Opcodes;
@@ -29,7 +28,7 @@
  * <p/>
  * This is used to override specific methods and or all native methods in classes.
  */
-public class DelegateClassAdapter extends ClassAdapter {
+public class DelegateClassAdapter extends ClassVisitor {
 
     /** Suffix added to original methods. */
     private static final String ORIGINAL_SUFFIX = "_Original";
@@ -59,7 +58,7 @@
             ClassVisitor cv,
             String className,
             Set<String> delegateMethods) {
-        super(cv);
+        super(Opcodes.ASM4, cv);
         mLog = log;
         mClassName = className;
         mDelegateMethods = delegateMethods;
diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/DelegateMethodAdapter2.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/DelegateMethodAdapter2.java
index 89b53ab..0000b22 100644
--- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/DelegateMethodAdapter2.java
+++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/DelegateMethodAdapter2.java
@@ -71,7 +71,7 @@
  * Instances of this class are not re-usable.
  * The class adapter creates a new instance for each method.
  */
-class DelegateMethodAdapter2 implements MethodVisitor {
+class DelegateMethodAdapter2 extends MethodVisitor {
 
     /** Suffix added to delegate classes. */
     public static final String DELEGATE_SUFFIX = "_Delegate";
@@ -121,6 +121,7 @@
             String methodName,
             String desc,
             boolean isStatic) {
+        super(Opcodes.ASM4);
         mLog = log;
         mOrgWriter = mvOriginal;
         mDelWriter = mvDelegate;
@@ -265,6 +266,7 @@
     }
 
     /* Pass down to visitor writer. In this implementation, either do nothing. */
+    @Override
     public void visitCode() {
         if (mOrgWriter != null) {
             mOrgWriter.visitCode();
@@ -274,6 +276,7 @@
     /*
      * visitMaxs is called just before visitEnd if there was any code to rewrite.
      */
+    @Override
     public void visitMaxs(int maxStack, int maxLocals) {
         if (mOrgWriter != null) {
             mOrgWriter.visitMaxs(maxStack, maxLocals);
@@ -281,6 +284,7 @@
     }
 
     /** End of visiting. Generate the delegating code. */
+    @Override
     public void visitEnd() {
         if (mOrgWriter != null) {
             mOrgWriter.visitEnd();
@@ -289,6 +293,7 @@
     }
 
     /* Writes all annotation from the original method. */
+    @Override
     public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
         if (mOrgWriter != null) {
             return mOrgWriter.visitAnnotation(desc, visible);
@@ -298,6 +303,7 @@
     }
 
     /* Writes all annotation default values from the original method. */
+    @Override
     public AnnotationVisitor visitAnnotationDefault() {
         if (mOrgWriter != null) {
             return mOrgWriter.visitAnnotationDefault();
@@ -306,6 +312,7 @@
         }
     }
 
+    @Override
     public AnnotationVisitor visitParameterAnnotation(int parameter, String desc,
             boolean visible) {
         if (mOrgWriter != null) {
@@ -316,6 +323,7 @@
     }
 
     /* Writes all attributes from the original method. */
+    @Override
     public void visitAttribute(Attribute attr) {
         if (mOrgWriter != null) {
             mOrgWriter.visitAttribute(attr);
@@ -326,6 +334,7 @@
      * Only writes the first line number present in the original code so that source
      * viewers can direct to the correct method, even if the content doesn't match.
      */
+    @Override
     public void visitLineNumber(int line, Label start) {
         // Capture the first line values for the new delegate method
         if (mDelegateLineNumber == null) {
@@ -336,66 +345,77 @@
         }
     }
 
+    @Override
     public void visitInsn(int opcode) {
         if (mOrgWriter != null) {
             mOrgWriter.visitInsn(opcode);
         }
     }
 
+    @Override
     public void visitLabel(Label label) {
         if (mOrgWriter != null) {
             mOrgWriter.visitLabel(label);
         }
     }
 
+    @Override
     public void visitTryCatchBlock(Label start, Label end, Label handler, String type) {
         if (mOrgWriter != null) {
             mOrgWriter.visitTryCatchBlock(start, end, handler, type);
         }
     }
 
+    @Override
     public void visitMethodInsn(int opcode, String owner, String name, String desc) {
         if (mOrgWriter != null) {
             mOrgWriter.visitMethodInsn(opcode, owner, name, desc);
         }
     }
 
+    @Override
     public void visitFieldInsn(int opcode, String owner, String name, String desc) {
         if (mOrgWriter != null) {
             mOrgWriter.visitFieldInsn(opcode, owner, name, desc);
         }
     }
 
+    @Override
     public void visitFrame(int type, int nLocal, Object[] local, int nStack, Object[] stack) {
         if (mOrgWriter != null) {
             mOrgWriter.visitFrame(type, nLocal, local, nStack, stack);
         }
     }
 
+    @Override
     public void visitIincInsn(int var, int increment) {
         if (mOrgWriter != null) {
             mOrgWriter.visitIincInsn(var, increment);
         }
     }
 
+    @Override
     public void visitIntInsn(int opcode, int operand) {
         if (mOrgWriter != null) {
             mOrgWriter.visitIntInsn(opcode, operand);
         }
     }
 
+    @Override
     public void visitJumpInsn(int opcode, Label label) {
         if (mOrgWriter != null) {
             mOrgWriter.visitJumpInsn(opcode, label);
         }
     }
 
+    @Override
     public void visitLdcInsn(Object cst) {
         if (mOrgWriter != null) {
             mOrgWriter.visitLdcInsn(cst);
         }
     }
 
+    @Override
     public void visitLocalVariable(String name, String desc, String signature,
             Label start, Label end, int index) {
         if (mOrgWriter != null) {
@@ -403,30 +423,35 @@
         }
     }
 
+    @Override
     public void visitLookupSwitchInsn(Label dflt, int[] keys, Label[] labels) {
         if (mOrgWriter != null) {
             mOrgWriter.visitLookupSwitchInsn(dflt, keys, labels);
         }
     }
 
+    @Override
     public void visitMultiANewArrayInsn(String desc, int dims) {
         if (mOrgWriter != null) {
             mOrgWriter.visitMultiANewArrayInsn(desc, dims);
         }
     }
 
+    @Override
     public void visitTableSwitchInsn(int min, int max, Label dflt, Label[] labels) {
         if (mOrgWriter != null) {
             mOrgWriter.visitTableSwitchInsn(min, max, dflt, labels);
         }
     }
 
+    @Override
     public void visitTypeInsn(int opcode, String type) {
         if (mOrgWriter != null) {
             mOrgWriter.visitTypeInsn(opcode, type);
         }
     }
 
+    @Override
     public void visitVarInsn(int opcode, int var) {
         if (mOrgWriter != null) {
             mOrgWriter.visitVarInsn(opcode, var);
diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/RenameClassAdapter.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/RenameClassAdapter.java
index 0956b92..383cbb8 100644
--- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/RenameClassAdapter.java
+++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/RenameClassAdapter.java
@@ -17,12 +17,12 @@
 package com.android.tools.layoutlib.create;
 
 import org.objectweb.asm.AnnotationVisitor;
-import org.objectweb.asm.ClassAdapter;
+import org.objectweb.asm.ClassVisitor;
 import org.objectweb.asm.ClassWriter;
 import org.objectweb.asm.FieldVisitor;
 import org.objectweb.asm.Label;
-import org.objectweb.asm.MethodAdapter;
 import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.Opcodes;
 import org.objectweb.asm.Type;
 import org.objectweb.asm.signature.SignatureReader;
 import org.objectweb.asm.signature.SignatureVisitor;
@@ -32,13 +32,13 @@
  * This class visitor renames a class from a given old name to a given new name.
  * The class visitor will also rename all inner classes and references in the methods.
  * <p/>
- * 
+ *
  * For inner classes, this handles only the case where the outer class name changes.
- * The inner class name should remain the same. 
+ * The inner class name should remain the same.
  */
-public class RenameClassAdapter extends ClassAdapter {
+public class RenameClassAdapter extends ClassVisitor {
 
-    
+
     private final String mOldName;
     private final String mNewName;
     private String mOldBase;
@@ -50,10 +50,10 @@
      * The names must be full qualified internal ASM names (e.g. com/blah/MyClass$InnerClass).
      */
     public RenameClassAdapter(ClassWriter cv, String oldName, String newName) {
-        super(cv);
+        super(Opcodes.ASM4, cv);
         mOldBase = mOldName = oldName;
         mNewBase = mNewName = newName;
-        
+
         int pos = mOldName.indexOf('$');
         if (pos > 0) {
             mOldBase = mOldName.substring(0, pos);
@@ -62,7 +62,7 @@
         if (pos > 0) {
             mNewBase = mNewName.substring(0, pos);
         }
-        
+
         assert (mOldBase == null && mNewBase == null) || (mOldBase != null && mNewBase != null);
     }
 
@@ -78,7 +78,7 @@
 
         return renameType(Type.getType(desc));
     }
-    
+
     /**
      * Renames an object type, e.g. "Lcom.package.MyClass;" or an array type that has an
      * object element, e.g. "[Lcom.package.MyClass;"
@@ -150,7 +150,7 @@
         if (mOldBase != mOldName && type.equals(mOldBase)) {
             return mNewBase;
         }
-    
+
         int pos = type.indexOf('$');
         if (pos == mOldBase.length() && type.startsWith(mOldBase)) {
             return mNewBase + type.substring(pos);
@@ -183,7 +183,7 @@
             sb.append(name);
         }
         sb.append(')');
-        
+
         Type ret = Type.getReturnType(desc);
         String name = renameType(ret);
         sb.append(name);
@@ -191,9 +191,9 @@
         return sb.toString();
     }
 
-    
+
     /**
-     * Renames the ClassSignature handled by ClassVisitor.visit 
+     * Renames the ClassSignature handled by ClassVisitor.visit
      * or the MethodTypeSignature handled by ClassVisitor.visitMethod.
      */
     String renameTypeSignature(String sig) {
@@ -207,7 +207,7 @@
         return sig;
     }
 
-    
+
     /**
      * Renames the FieldTypeSignature handled by ClassVisitor.visitField
      * or MethodVisitor.visitLocalVariable.
@@ -223,17 +223,17 @@
         return sig;
     }
 
-    
+
     //----------------------------------
     // Methods from the ClassAdapter
-    
+
     @Override
     public void visit(int version, int access, String name, String signature,
             String superName, String[] interfaces) {
         name = renameInternalType(name);
         superName = renameInternalType(superName);
         signature = renameTypeSignature(signature);
-        
+
         super.visit(version, access, name, signature, superName, interfaces);
     }
 
@@ -259,7 +259,7 @@
         desc = renameTypeDesc(desc);
         return super.visitAnnotation(desc, visible);
     }
-    
+
     @Override
     public FieldVisitor visitField(int access, String name, String desc,
             String signature, Object value) {
@@ -267,14 +267,14 @@
         signature = renameFieldSignature(signature);
         return super.visitField(access, name, desc, signature, value);
     }
-    
-    
+
+
     //----------------------------------
 
     /**
      * A method visitor that renames all references from an old class name to a new class name.
      */
-    public class RenameMethodAdapter extends MethodAdapter {
+    public class RenameMethodAdapter extends MethodVisitor {
 
         /**
          * Creates a method visitor that renames all references from a given old name to a given new
@@ -282,13 +282,13 @@
          * The names must be full qualified internal ASM names (e.g. com/blah/MyClass$InnerClass).
          */
         public RenameMethodAdapter(MethodVisitor mv) {
-            super(mv);
+            super(Opcodes.ASM4, mv);
         }
 
         @Override
         public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
             desc = renameTypeDesc(desc);
-            
+
             return super.visitAnnotation(desc, visible);
         }
 
@@ -302,7 +302,7 @@
         @Override
         public void visitTypeInsn(int opcode, String type) {
             type = renameInternalType(type);
-            
+
             super.visitTypeInsn(opcode, type);
         }
 
@@ -321,7 +321,7 @@
 
             super.visitMethodInsn(opcode, owner, name, desc);
         }
-        
+
         @Override
         public void visitLdcInsn(Object cst) {
             // If cst is a Type, this means the code is trying to pull the .class constant
@@ -335,14 +335,14 @@
         @Override
         public void visitMultiANewArrayInsn(String desc, int dims) {
             desc = renameTypeDesc(desc);
-         
+
             super.visitMultiANewArrayInsn(desc, dims);
         }
 
         @Override
         public void visitTryCatchBlock(Label start, Label end, Label handler, String type) {
             type = renameInternalType(type);
-            
+
             super.visitTryCatchBlock(start, end, handler, type);
         }
 
@@ -351,96 +351,113 @@
                 Label start, Label end, int index) {
             desc = renameTypeDesc(desc);
             signature = renameFieldSignature(signature);
-            
+
             super.visitLocalVariable(name, desc, signature, start, end, index);
         }
 
     }
 
     //----------------------------------
-    
-    public class RenameSignatureAdapter implements SignatureVisitor {
+
+    public class RenameSignatureAdapter extends SignatureVisitor {
 
         private final SignatureVisitor mSv;
 
         public RenameSignatureAdapter(SignatureVisitor sv) {
+            super(Opcodes.ASM4);
             mSv = sv;
         }
 
+        @Override
         public void visitClassType(String name) {
             name = renameInternalType(name);
             mSv.visitClassType(name);
         }
 
+        @Override
         public void visitInnerClassType(String name) {
             name = renameInternalType(name);
             mSv.visitInnerClassType(name);
         }
 
+        @Override
         public SignatureVisitor visitArrayType() {
             SignatureVisitor sv = mSv.visitArrayType();
             return new RenameSignatureAdapter(sv);
         }
 
+        @Override
         public void visitBaseType(char descriptor) {
             mSv.visitBaseType(descriptor);
         }
 
+        @Override
         public SignatureVisitor visitClassBound() {
             SignatureVisitor sv = mSv.visitClassBound();
             return new RenameSignatureAdapter(sv);
         }
 
+        @Override
         public void visitEnd() {
             mSv.visitEnd();
         }
 
+        @Override
         public SignatureVisitor visitExceptionType() {
             SignatureVisitor sv = mSv.visitExceptionType();
             return new RenameSignatureAdapter(sv);
         }
 
+        @Override
         public void visitFormalTypeParameter(String name) {
             mSv.visitFormalTypeParameter(name);
         }
 
+        @Override
         public SignatureVisitor visitInterface() {
             SignatureVisitor sv = mSv.visitInterface();
             return new RenameSignatureAdapter(sv);
         }
 
+        @Override
         public SignatureVisitor visitInterfaceBound() {
             SignatureVisitor sv = mSv.visitInterfaceBound();
             return new RenameSignatureAdapter(sv);
         }
 
+        @Override
         public SignatureVisitor visitParameterType() {
             SignatureVisitor sv = mSv.visitParameterType();
             return new RenameSignatureAdapter(sv);
         }
 
+        @Override
         public SignatureVisitor visitReturnType() {
             SignatureVisitor sv = mSv.visitReturnType();
             return new RenameSignatureAdapter(sv);
         }
 
+        @Override
         public SignatureVisitor visitSuperclass() {
             SignatureVisitor sv = mSv.visitSuperclass();
             return new RenameSignatureAdapter(sv);
         }
 
+        @Override
         public void visitTypeArgument() {
             mSv.visitTypeArgument();
         }
 
+        @Override
         public SignatureVisitor visitTypeArgument(char wildcard) {
             SignatureVisitor sv = mSv.visitTypeArgument(wildcard);
             return new RenameSignatureAdapter(sv);
         }
 
+        @Override
         public void visitTypeVariable(String name) {
             mSv.visitTypeVariable(name);
         }
-        
+
     }
 }
diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/StubMethodAdapter.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/StubMethodAdapter.java
index d70d028..51e7535 100644
--- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/StubMethodAdapter.java
+++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/StubMethodAdapter.java
@@ -27,7 +27,7 @@
  * This method adapter rewrites a method by discarding the original code and generating
  * a stub depending on the return type. Original annotations are passed along unchanged.
  */
-class StubMethodAdapter implements MethodVisitor {
+class StubMethodAdapter extends MethodVisitor {
 
     private static String CONSTRUCTOR = "<init>";
     private static String CLASS_INIT = "<clinit>";
@@ -50,6 +50,7 @@
 
     public StubMethodAdapter(MethodVisitor mv, String methodName, Type returnType,
             String invokeSignature, boolean isStatic, boolean isNative) {
+        super(Opcodes.ASM4);
         mParentVisitor = mv;
         mReturnType = returnType;
         mInvokeSignature = invokeSignature;
@@ -172,6 +173,7 @@
     }
 
     /* Pass down to visitor writer. In this implementation, either do nothing. */
+    @Override
     public void visitCode() {
         mParentVisitor.visitCode();
     }
@@ -181,6 +183,7 @@
      * For non-constructor, generate the messaging code and the return statement
      * if it hasn't been done before.
      */
+    @Override
     public void visitMaxs(int maxStack, int maxLocals) {
         if (!mIsInitMethod && !mMessageGenerated) {
             generateInvoke();
@@ -194,6 +197,7 @@
      * For non-constructor, generate the messaging code and the return statement
      * if it hasn't been done before.
      */
+    @Override
     public void visitEnd() {
         if (!mIsInitMethod && !mMessageGenerated) {
             generateInvoke();
@@ -204,21 +208,25 @@
     }
 
     /* Writes all annotation from the original method. */
+    @Override
     public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
         return mParentVisitor.visitAnnotation(desc, visible);
     }
 
     /* Writes all annotation default values from the original method. */
+    @Override
     public AnnotationVisitor visitAnnotationDefault() {
         return mParentVisitor.visitAnnotationDefault();
     }
 
+    @Override
     public AnnotationVisitor visitParameterAnnotation(int parameter, String desc,
             boolean visible) {
         return mParentVisitor.visitParameterAnnotation(parameter, desc, visible);
     }
 
     /* Writes all attributes from the original method. */
+    @Override
     public void visitAttribute(Attribute attr) {
         mParentVisitor.visitAttribute(attr);
     }
@@ -227,6 +235,7 @@
      * Only writes the first line number present in the original code so that source
      * viewers can direct to the correct method, even if the content doesn't match.
      */
+    @Override
     public void visitLineNumber(int line, Label start) {
         if (mIsInitMethod || mOutputFirstLineNumber) {
             mParentVisitor.visitLineNumber(line, start);
@@ -237,6 +246,7 @@
     /**
      * For non-constructor, rewrite existing "return" instructions to write the message.
      */
+    @Override
     public void visitInsn(int opcode) {
         if (mIsInitMethod) {
             switch (opcode) {
@@ -257,60 +267,70 @@
         }
     }
 
+    @Override
     public void visitLabel(Label label) {
         if (mIsInitMethod) {
             mParentVisitor.visitLabel(label);
         }
     }
 
+    @Override
     public void visitTryCatchBlock(Label start, Label end, Label handler, String type) {
         if (mIsInitMethod) {
             mParentVisitor.visitTryCatchBlock(start, end, handler, type);
         }
     }
 
+    @Override
     public void visitMethodInsn(int opcode, String owner, String name, String desc) {
         if (mIsInitMethod) {
             mParentVisitor.visitMethodInsn(opcode, owner, name, desc);
         }
     }
 
+    @Override
     public void visitFieldInsn(int opcode, String owner, String name, String desc) {
         if (mIsInitMethod) {
             mParentVisitor.visitFieldInsn(opcode, owner, name, desc);
         }
     }
 
+    @Override
     public void visitFrame(int type, int nLocal, Object[] local, int nStack, Object[] stack) {
         if (mIsInitMethod) {
             mParentVisitor.visitFrame(type, nLocal, local, nStack, stack);
         }
     }
 
+    @Override
     public void visitIincInsn(int var, int increment) {
         if (mIsInitMethod) {
             mParentVisitor.visitIincInsn(var, increment);
         }
     }
 
+    @Override
     public void visitIntInsn(int opcode, int operand) {
         if (mIsInitMethod) {
             mParentVisitor.visitIntInsn(opcode, operand);
         }
     }
 
+    @Override
     public void visitJumpInsn(int opcode, Label label) {
         if (mIsInitMethod) {
             mParentVisitor.visitJumpInsn(opcode, label);
         }
     }
 
+    @Override
     public void visitLdcInsn(Object cst) {
         if (mIsInitMethod) {
             mParentVisitor.visitLdcInsn(cst);
         }
     }
 
+    @Override
     public void visitLocalVariable(String name, String desc, String signature,
             Label start, Label end, int index) {
         if (mIsInitMethod) {
@@ -318,30 +338,35 @@
         }
     }
 
+    @Override
     public void visitLookupSwitchInsn(Label dflt, int[] keys, Label[] labels) {
         if (mIsInitMethod) {
             mParentVisitor.visitLookupSwitchInsn(dflt, keys, labels);
         }
     }
 
+    @Override
     public void visitMultiANewArrayInsn(String desc, int dims) {
         if (mIsInitMethod) {
             mParentVisitor.visitMultiANewArrayInsn(desc, dims);
         }
     }
 
+    @Override
     public void visitTableSwitchInsn(int min, int max, Label dflt, Label[] labels) {
         if (mIsInitMethod) {
             mParentVisitor.visitTableSwitchInsn(min, max, dflt, labels);
         }
     }
 
+    @Override
     public void visitTypeInsn(int opcode, String type) {
         if (mIsInitMethod) {
             mParentVisitor.visitTypeInsn(opcode, type);
         }
     }
 
+    @Override
     public void visitVarInsn(int opcode, int var) {
         if (mIsInitMethod) {
             mParentVisitor.visitVarInsn(opcode, var);
diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/TransformClassAdapter.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/TransformClassAdapter.java
index 5a0a44a4..d45a183 100644
--- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/TransformClassAdapter.java
+++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/TransformClassAdapter.java
@@ -16,7 +16,6 @@
 
 package com.android.tools.layoutlib.create;
 
-import org.objectweb.asm.ClassAdapter;
 import org.objectweb.asm.ClassVisitor;
 import org.objectweb.asm.FieldVisitor;
 import org.objectweb.asm.MethodVisitor;
@@ -28,7 +27,7 @@
 /**
  * Class adapter that can stub some or all of the methods of the class.
  */
-class TransformClassAdapter extends ClassAdapter {
+class TransformClassAdapter extends ClassVisitor {
 
     /** True if all methods should be stubbed, false if only native ones must be stubbed. */
     private final boolean mStubAll;
@@ -54,7 +53,7 @@
     public TransformClassAdapter(Log logger, Set<String> stubMethods,
             Set<String> deleteReturns, String className, ClassVisitor cv,
             boolean stubNativesOnly, boolean hasNative) {
-        super(cv);
+        super(Opcodes.ASM4, cv);
         mLog = logger;
         mStubMethods = stubMethods;
         mClassName = className;
diff --git a/wifi/java/android/net/wifi/WifiWatchdogStateMachine.java b/wifi/java/android/net/wifi/WifiWatchdogStateMachine.java
index f330c32..b27c60f 100644
--- a/wifi/java/android/net/wifi/WifiWatchdogStateMachine.java
+++ b/wifi/java/android/net/wifi/WifiWatchdogStateMachine.java
@@ -150,6 +150,7 @@
     private ConnectedState mConnectedState = new ConnectedState();
     private DnsCheckingState mDnsCheckingState = new DnsCheckingState();
     private OnlineWatchState mOnlineWatchState = new OnlineWatchState();
+    private OnlineState mOnlineState = new OnlineState();
     private DnsCheckFailureState mDnsCheckFailureState = new DnsCheckFailureState();
     private DelayWalledGardenState mDelayWalledGardenState = new DelayWalledGardenState();
     private WalledGardenState mWalledGardenState = new WalledGardenState();
@@ -163,6 +164,7 @@
     private int mMinDnsResponses;
     private int mDnsPingTimeoutMs;
     private long mBlacklistFollowupIntervalMs;
+    private boolean mPoorNetworkDetectionEnabled;
     private boolean mWalledGardenTestEnabled;
     private String mWalledGardenUrl;
 
@@ -226,6 +228,7 @@
                     addState(mWalledGardenState, mConnectedState);
                     addState(mBlacklistedApState, mConnectedState);
                     addState(mOnlineWatchState, mConnectedState);
+                    addState(mOnlineState, mConnectedState);
 
         setInitialState(mWatchdogDisabledState);
         updateSettings();
@@ -411,6 +414,10 @@
         mBlacklistFollowupIntervalMs = Secure.getLong(mContentResolver,
                 Settings.Secure.WIFI_WATCHDOG_BLACKLIST_FOLLOWUP_INTERVAL_MS,
                 DEFAULT_BLACKLIST_FOLLOWUP_INTERVAL_MS);
+        //TODO: enable this by default after changing watchdog behavior
+        //Also, update settings description
+        mPoorNetworkDetectionEnabled = getSettingsBoolean(mContentResolver,
+                Settings.Secure.WIFI_WATCHDOG_POOR_NETWORK_TEST_ENABLED, false);
         mWalledGardenTestEnabled = getSettingsBoolean(mContentResolver,
                 Settings.Secure.WIFI_WATCHDOG_WALLED_GARDEN_TEST_ENABLED, true);
         mWalledGardenUrl = getSettingsStr(mContentResolver,
@@ -623,9 +630,13 @@
 
                             initConnection(wifiInfo);
                             mConnectionInfo = wifiInfo;
-                            updateBssids();
-                            transitionTo(mDnsCheckingState);
                             mNetEventCounter++;
+                            if (mPoorNetworkDetectionEnabled) {
+                                updateBssids();
+                                transitionTo(mDnsCheckingState);
+                            } else {
+                                transitionTo(mDelayWalledGardenState);
+                            }
                             break;
                         default:
                             mNetEventCounter++;
@@ -677,12 +688,18 @@
         public boolean processMessage(Message msg) {
             switch (msg.what) {
                 case EVENT_SCAN_RESULTS_AVAILABLE:
-                    updateBssids();
+                    if (mPoorNetworkDetectionEnabled) {
+                        updateBssids();
+                    }
                     return HANDLED;
                 case EVENT_WATCHDOG_SETTINGS_CHANGE:
-                    // Stop current checks, but let state update
-                    transitionTo(mOnlineWatchState);
-                    return NOT_HANDLED;
+                    updateSettings();
+                    if (mPoorNetworkDetectionEnabled) {
+                        transitionTo(mOnlineWatchState);
+                    } else {
+                        transitionTo(mOnlineState);
+                    }
+                    return HANDLED;
             }
             return NOT_HANDLED;
         }
@@ -829,7 +846,11 @@
                         transitionTo(mWalledGardenState);
                     } else {
                         if (DBG) log("Walled garden test complete - online");
-                        transitionTo(mOnlineWatchState);
+                        if (mPoorNetworkDetectionEnabled) {
+                            transitionTo(mOnlineWatchState);
+                        } else {
+                            transitionTo(mOnlineState);
+                        }
                     }
                     return HANDLED;
                 default:
@@ -961,6 +982,13 @@
         }
     }
 
+
+    /* Child state of ConnectedState indicating that we are online
+     * and there is nothing to do
+     */
+    class OnlineState extends State {
+    }
+
     class DnsCheckFailureState extends State {
 
         @Override
@@ -1037,7 +1065,11 @@
                 return HANDLED;
             }
             setWalledGardenNotificationVisible(true);
-            transitionTo(mOnlineWatchState);
+            if (mPoorNetworkDetectionEnabled) {
+                transitionTo(mOnlineWatchState);
+            } else {
+                transitionTo(mOnlineState);
+            }
             return HANDLED;
         }
     }