Merge "Fix BasicNfcEeTest java package."
diff --git a/api/current.txt b/api/current.txt
index 5dc32ae..9610853 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -5334,6 +5334,7 @@
     method public java.util.ArrayList<T> getParcelableArrayListExtra(java.lang.String);
     method public T getParcelableExtra(java.lang.String);
     method public java.lang.String getScheme();
+    method public android.content.Intent getSelector();
     method public java.io.Serializable getSerializableExtra(java.lang.String);
     method public short[] getShortArrayExtra(java.lang.String);
     method public short getShortExtra(java.lang.String, short);
@@ -5346,6 +5347,7 @@
     method public boolean hasExtra(java.lang.String);
     method public boolean hasFileDescriptors();
     method public static android.content.Intent makeMainActivity(android.content.ComponentName);
+    method public static android.content.Intent makeMainSelectorActivity(java.lang.String, java.lang.String);
     method public static android.content.Intent makeRestartActivityTask(android.content.ComponentName);
     method public static android.content.Intent parseIntent(android.content.res.Resources, org.xmlpull.v1.XmlPullParser, android.util.AttributeSet) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
     method public static android.content.Intent parseUri(java.lang.String, int) throws java.net.URISyntaxException;
@@ -5399,6 +5401,7 @@
     method public void setExtrasClassLoader(java.lang.ClassLoader);
     method public android.content.Intent setFlags(int);
     method public android.content.Intent setPackage(java.lang.String);
+    method public void setSelector(android.content.Intent);
     method public void setSourceBounds(android.graphics.Rect);
     method public android.content.Intent setType(java.lang.String);
     method public deprecated java.lang.String toURI();
@@ -5577,6 +5580,7 @@
     field public static final int FILL_IN_COMPONENT = 8; // 0x8
     field public static final int FILL_IN_DATA = 2; // 0x2
     field public static final int FILL_IN_PACKAGE = 16; // 0x10
+    field public static final int FILL_IN_SELECTOR = 64; // 0x40
     field public static final int FILL_IN_SOURCE_BOUNDS = 32; // 0x20
     field public static final int FLAG_ACTIVITY_BROUGHT_TO_FRONT = 4194304; // 0x400000
     field public static final int FLAG_ACTIVITY_CLEAR_TASK = 32768; // 0x8000
@@ -17431,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/am/src/com/android/commands/am/Am.java b/cmds/am/src/com/android/commands/am/Am.java
index 140222e..fddb429 100644
--- a/cmds/am/src/com/android/commands/am/Am.java
+++ b/cmds/am/src/com/android/commands/am/Am.java
@@ -131,6 +131,10 @@
             runScreenCompat();
         } else if (op.equals("display-size")) {
             runDisplaySize();
+        } else if (op.equals("to-uri")) {
+            runToUri(false);
+        } else if (op.equals("to-intent-uri")) {
+            runToUri(true);
         } else {
             throw new IllegalArgumentException("Unknown command: " + op);
         }
@@ -138,6 +142,7 @@
 
     private Intent makeIntent() throws URISyntaxException {
         Intent intent = new Intent();
+        Intent baseIntent = intent;
         boolean hasIntentInfo = false;
 
         mDebugOption = false;
@@ -152,35 +157,39 @@
         while ((opt=nextOption()) != null) {
             if (opt.equals("-a")) {
                 intent.setAction(nextArgRequired());
-                hasIntentInfo = true;
+                if (intent == baseIntent) {
+                    hasIntentInfo = true;
+                }
             } else if (opt.equals("-d")) {
                 data = Uri.parse(nextArgRequired());
-                hasIntentInfo = true;
+                if (intent == baseIntent) {
+                    hasIntentInfo = true;
+                }
             } else if (opt.equals("-t")) {
                 type = nextArgRequired();
-                hasIntentInfo = true;
+                if (intent == baseIntent) {
+                    hasIntentInfo = true;
+                }
             } else if (opt.equals("-c")) {
                 intent.addCategory(nextArgRequired());
-                hasIntentInfo = true;
+                if (intent == baseIntent) {
+                    hasIntentInfo = true;
+                }
             } else if (opt.equals("-e") || opt.equals("--es")) {
                 String key = nextArgRequired();
                 String value = nextArgRequired();
                 intent.putExtra(key, value);
-                hasIntentInfo = true;
             } else if (opt.equals("--esn")) {
                 String key = nextArgRequired();
                 intent.putExtra(key, (String) null);
-                hasIntentInfo = true;
             } else if (opt.equals("--ei")) {
                 String key = nextArgRequired();
                 String value = nextArgRequired();
                 intent.putExtra(key, Integer.valueOf(value));
-                hasIntentInfo = true;
             } else if (opt.equals("--eu")) {
                 String key = nextArgRequired();
                 String value = nextArgRequired();
                 intent.putExtra(key, Uri.parse(value));
-                hasIntentInfo = true;
             } else if (opt.equals("--eia")) {
                 String key = nextArgRequired();
                 String value = nextArgRequired();
@@ -190,12 +199,10 @@
                     list[i] = Integer.valueOf(strings[i]);
                 }
                 intent.putExtra(key, list);
-                hasIntentInfo = true;
             } else if (opt.equals("--el")) {
                 String key = nextArgRequired();
                 String value = nextArgRequired();
                 intent.putExtra(key, Long.valueOf(value));
-                hasIntentInfo = true;
             } else if (opt.equals("--ela")) {
                 String key = nextArgRequired();
                 String value = nextArgRequired();
@@ -205,18 +212,18 @@
                     list[i] = Long.valueOf(strings[i]);
                 }
                 intent.putExtra(key, list);
-                hasIntentInfo = true;
             } else if (opt.equals("--ez")) {
                 String key = nextArgRequired();
                 String value = nextArgRequired();
                 intent.putExtra(key, Boolean.valueOf(value));
-                hasIntentInfo = true;
             } else if (opt.equals("-n")) {
                 String str = nextArgRequired();
                 ComponentName cn = ComponentName.unflattenFromString(str);
                 if (cn == null) throw new IllegalArgumentException("Bad component name: " + str);
                 intent.setComponent(cn);
-                hasIntentInfo = true;
+                if (intent == baseIntent) {
+                    hasIntentInfo = true;
+                }
             } else if (opt.equals("-f")) {
                 String str = nextArgRequired();
                 intent.setFlags(Integer.decode(str).intValue());
@@ -264,6 +271,9 @@
                 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
             } else if (opt.equals("--receiver-replace-pending")) {
                 intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
+            } else if (opt.equals("--selector")) {
+                intent.setDataAndType(data, type);
+                intent = new Intent();
             } else if (opt.equals("-D")) {
                 mDebugOption = true;
             } else if (opt.equals("-W")) {
@@ -286,25 +296,42 @@
         }
         intent.setDataAndType(data, type);
 
+        final boolean hasSelector = intent != baseIntent;
+        if (hasSelector) {
+            // A selector was specified; fix up.
+            baseIntent.setSelector(intent);
+            intent = baseIntent;
+        }
+
         String arg = nextArg();
-        if (arg != null) {
-            Intent baseIntent;
-            if (arg.indexOf(':') >= 0) {
-                // The argument is a URI.  Fully parse it, and use that result
-                // to fill in any data not specified so far.
-                baseIntent = Intent.parseUri(arg, Intent.URI_INTENT_SCHEME);
-            } else if (arg.indexOf('/') >= 0) {
-                // The argument is a component name.  Build an Intent to launch
-                // it.
+        baseIntent = null;
+        if (arg == null) {
+            if (hasSelector) {
+                // If a selector has been specified, and no arguments
+                // have been supplied for the main Intent, then we can
+                // assume it is ACTION_MAIN CATEGORY_LAUNCHER; we don't
+                // need to have a component name specified yet, the
+                // selector will take care of that.
                 baseIntent = new Intent(Intent.ACTION_MAIN);
                 baseIntent.addCategory(Intent.CATEGORY_LAUNCHER);
-                baseIntent.setComponent(ComponentName.unflattenFromString(arg));
-            } else {
-                // Assume the argument is a package name.
-                baseIntent = new Intent(Intent.ACTION_MAIN);
-                baseIntent.addCategory(Intent.CATEGORY_LAUNCHER);
-                baseIntent.setPackage(arg);
             }
+        } else if (arg.indexOf(':') >= 0) {
+            // The argument is a URI.  Fully parse it, and use that result
+            // to fill in any data not specified so far.
+            baseIntent = Intent.parseUri(arg, Intent.URI_INTENT_SCHEME);
+        } else if (arg.indexOf('/') >= 0) {
+            // The argument is a component name.  Build an Intent to launch
+            // it.
+            baseIntent = new Intent(Intent.ACTION_MAIN);
+            baseIntent.addCategory(Intent.CATEGORY_LAUNCHER);
+            baseIntent.setComponent(ComponentName.unflattenFromString(arg));
+        } else {
+            // Assume the argument is a package name.
+            baseIntent = new Intent(Intent.ACTION_MAIN);
+            baseIntent.addCategory(Intent.CATEGORY_LAUNCHER);
+            baseIntent.setPackage(arg);
+        }
+        if (baseIntent != null) {
             Bundle extras = intent.getExtras();
             intent.replaceExtras((Bundle)null);
             Bundle uriExtras = baseIntent.getExtras();
@@ -315,7 +342,7 @@
                     baseIntent.removeCategory(c);
                 }
             }
-            intent.fillIn(baseIntent, Intent.FILL_IN_COMPONENT);
+            intent.fillIn(baseIntent, Intent.FILL_IN_COMPONENT | Intent.FILL_IN_SELECTOR);
             if (extras == null) {
                 extras = uriExtras;
             } else if (uriExtras != null) {
@@ -1064,6 +1091,11 @@
         }
     }
 
+    private void runToUri(boolean intentScheme) throws Exception {
+        Intent intent = makeIntent();
+        System.out.println(intent.toUri(intentScheme ? Intent.URI_INTENT_SCHEME : 0));
+    }
+
     private class IntentReceiver extends IIntentReceiver.Stub {
         private boolean mFinished = false;
 
@@ -1233,6 +1265,8 @@
                 "       am monitor [--gdb <port>]\n" +
                 "       am screen-compat [on|off] <PACKAGE>\n" +
                 "       am display-size [reset|MxN]\n" +
+                "       am to-uri [INTENT]\n" +
+                "       am to-intent-uri [INTENT]\n" +
                 "\n" +
                 "am start: start an Activity.  Options are:\n" +
                 "    -D: enable debugging\n" +
@@ -1284,6 +1318,10 @@
                 "\n" +
                 "am display-size: override display size.\n" +
                 "\n" +
+                "am to-uri: print the given Intent specification as a URI.\n" +
+                "\n" +
+                "am to-intent-uri: print the given Intent specification as an intent: URI.\n" +
+                "\n" +
                 "<INTENT> specifications include these flags and arguments:\n" +
                 "    [-a <ACTION>] [-d <DATA_URI>] [-t <MIME_TYPE>]\n" +
                 "    [-c <CATEGORY> [-c <CATEGORY>] ...]\n" +
@@ -1308,6 +1346,7 @@
                 "    [--activity-single-top] [--activity-clear-task]\n" +
                 "    [--activity-task-on-home]\n" +
                 "    [--receiver-registered-only] [--receiver-replace-pending]\n" +
+                "    [--selector]\n" +
                 "    [<URI> | <PACKAGE> | <COMPONENT>]\n"
                 );
     }
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/animation/ValueAnimator.java b/core/java/android/animation/ValueAnimator.java
index edd0fa3..9bf1634 100755
--- a/core/java/android/animation/ValueAnimator.java
+++ b/core/java/android/animation/ValueAnimator.java
@@ -20,6 +20,7 @@
 import android.os.Looper;
 import android.os.Message;
 import android.util.AndroidRuntimeException;
+import android.view.Choreographer;
 import android.view.animation.AccelerateDecelerateInterpolator;
 import android.view.animation.AnimationUtils;
 import android.view.animation.LinearInterpolator;
@@ -45,17 +46,10 @@
      * Internal constants
      */
 
-    /*
-     * The default amount of time in ms between animation frames
-     */
-    private static final long DEFAULT_FRAME_DELAY = 10;
-
     /**
-     * Messages sent to timing handler: START is sent when an animation first begins, FRAME is sent
-     * by the handler to itself to process the next animation frame
+     * Messages sent to timing handler: START is sent when an animation first begins.
      */
     static final int ANIMATION_START = 0;
-    static final int ANIMATION_FRAME = 1;
 
     /**
      * Values used with internal variable mPlayingState to indicate the current state of an
@@ -83,70 +77,15 @@
      */
     long mSeekTime = -1;
 
-    // TODO: We access the following ThreadLocal variables often, some of them on every update.
-    // If ThreadLocal access is significantly expensive, we may want to put all of these
-    // fields into a structure sot hat we just access ThreadLocal once to get the reference
-    // to that structure, then access the structure directly for each field.
-
     // The static sAnimationHandler processes the internal timing loop on which all animations
     // are based
     private static ThreadLocal<AnimationHandler> sAnimationHandler =
             new ThreadLocal<AnimationHandler>();
 
-    // The per-thread list of all active animations
-    private static final ThreadLocal<ArrayList<ValueAnimator>> sAnimations =
-            new ThreadLocal<ArrayList<ValueAnimator>>() {
-                @Override
-                protected ArrayList<ValueAnimator> initialValue() {
-                    return new ArrayList<ValueAnimator>();
-                }
-            };
-
-    // The per-thread set of animations to be started on the next animation frame
-    private static final ThreadLocal<ArrayList<ValueAnimator>> sPendingAnimations =
-            new ThreadLocal<ArrayList<ValueAnimator>>() {
-                @Override
-                protected ArrayList<ValueAnimator> initialValue() {
-                    return new ArrayList<ValueAnimator>();
-                }
-            };
-
-    /**
-     * Internal per-thread collections used to avoid set collisions as animations start and end
-     * while being processed.
-     */
-    private static final ThreadLocal<ArrayList<ValueAnimator>> sDelayedAnims =
-            new ThreadLocal<ArrayList<ValueAnimator>>() {
-                @Override
-                protected ArrayList<ValueAnimator> initialValue() {
-                    return new ArrayList<ValueAnimator>();
-                }
-            };
-
-    private static final ThreadLocal<ArrayList<ValueAnimator>> sEndingAnims =
-            new ThreadLocal<ArrayList<ValueAnimator>>() {
-                @Override
-                protected ArrayList<ValueAnimator> initialValue() {
-                    return new ArrayList<ValueAnimator>();
-                }
-            };
-
-    private static final ThreadLocal<ArrayList<ValueAnimator>> sReadyAnims =
-            new ThreadLocal<ArrayList<ValueAnimator>>() {
-                @Override
-                protected ArrayList<ValueAnimator> initialValue() {
-                    return new ArrayList<ValueAnimator>();
-                }
-            };
-
     // The time interpolator to be used if none is set on the animation
     private static final TimeInterpolator sDefaultInterpolator =
             new AccelerateDecelerateInterpolator();
 
-    // type evaluators for the primitive types handled by this implementation
-    private static final TypeEvaluator sIntEvaluator = new IntEvaluator();
-    private static final TypeEvaluator sFloatEvaluator = new FloatEvaluator();
-
     /**
      * Used to indicate whether the animation is currently playing in reverse. This causes the
      * elapsed fraction to be inverted to calculate the appropriate values.
@@ -217,9 +156,6 @@
     // The amount of time in ms to delay starting the animation after start() is called
     private long mStartDelay = 0;
 
-    // The number of milliseconds between animation frames
-    private static long sFrameDelay = DEFAULT_FRAME_DELAY;
-
     // The number of times the animation will repeat. The default is 0, which means the animation
     // will play only once
     private int mRepeatCount = 0;
@@ -566,119 +502,146 @@
      * animations possible.
      *
      */
-    private static class AnimationHandler extends Handler {
+    private static class AnimationHandler extends Handler
+            implements Choreographer.OnAnimateListener {
+        // The per-thread list of all active animations
+        private final ArrayList<ValueAnimator> mAnimations = new ArrayList<ValueAnimator>();
+
+        // The per-thread set of animations to be started on the next animation frame
+        private final ArrayList<ValueAnimator> mPendingAnimations = new ArrayList<ValueAnimator>();
+
         /**
-         * There are only two messages that we care about: ANIMATION_START and
-         * ANIMATION_FRAME. The START message is sent when an animation's start()
-         * method is called. It cannot start synchronously when start() is called
+         * Internal per-thread collections used to avoid set collisions as animations start and end
+         * while being processed.
+         */
+        private final ArrayList<ValueAnimator> mDelayedAnims = new ArrayList<ValueAnimator>();
+        private final ArrayList<ValueAnimator> mEndingAnims = new ArrayList<ValueAnimator>();
+        private final ArrayList<ValueAnimator> mReadyAnims = new ArrayList<ValueAnimator>();
+
+        private final Choreographer mChoreographer;
+        private boolean mIsChoreographed;
+
+        private AnimationHandler() {
+            mChoreographer = Choreographer.getInstance();
+        }
+
+        /**
+         * The START message is sent when an animation's start()  method is called.
+         * It cannot start synchronously when start() is called
          * because the call may be on the wrong thread, and it would also not be
          * synchronized with other animations because it would not start on a common
          * timing pulse. So each animation sends a START message to the handler, which
          * causes the handler to place the animation on the active animations queue and
          * start processing frames for that animation.
-         * The FRAME message is the one that is sent over and over while there are any
-         * active animations to process.
          */
         @Override
         public void handleMessage(Message msg) {
-            boolean callAgain = true;
-            ArrayList<ValueAnimator> animations = sAnimations.get();
-            ArrayList<ValueAnimator> delayedAnims = sDelayedAnims.get();
             switch (msg.what) {
-                // TODO: should we avoid sending frame message when starting if we
-                // were already running?
                 case ANIMATION_START:
-                    ArrayList<ValueAnimator> pendingAnimations = sPendingAnimations.get();
-                    if (animations.size() > 0 || delayedAnims.size() > 0) {
-                        callAgain = false;
-                    }
-                    // pendingAnims holds any animations that have requested to be started
-                    // We're going to clear sPendingAnimations, but starting animation may
-                    // cause more to be added to the pending list (for example, if one animation
-                    // starting triggers another starting). So we loop until sPendingAnimations
-                    // is empty.
-                    while (pendingAnimations.size() > 0) {
-                        ArrayList<ValueAnimator> pendingCopy =
-                                (ArrayList<ValueAnimator>) pendingAnimations.clone();
-                        pendingAnimations.clear();
-                        int count = pendingCopy.size();
-                        for (int i = 0; i < count; ++i) {
-                            ValueAnimator anim = pendingCopy.get(i);
-                            // If the animation has a startDelay, place it on the delayed list
-                            if (anim.mStartDelay == 0) {
-                                anim.startAnimation();
-                            } else {
-                                delayedAnims.add(anim);
-                            }
-                        }
-                    }
-                    // fall through to process first frame of new animations
-                case ANIMATION_FRAME:
-                    // currentTime holds the common time for all animations processed
-                    // during this frame
-                    long currentTime = AnimationUtils.currentAnimationTimeMillis();
-                    ArrayList<ValueAnimator> readyAnims = sReadyAnims.get();
-                    ArrayList<ValueAnimator> endingAnims = sEndingAnims.get();
-
-                    // First, process animations currently sitting on the delayed queue, adding
-                    // them to the active animations if they are ready
-                    int numDelayedAnims = delayedAnims.size();
-                    for (int i = 0; i < numDelayedAnims; ++i) {
-                        ValueAnimator anim = delayedAnims.get(i);
-                        if (anim.delayedAnimationFrame(currentTime)) {
-                            readyAnims.add(anim);
-                        }
-                    }
-                    int numReadyAnims = readyAnims.size();
-                    if (numReadyAnims > 0) {
-                        for (int i = 0; i < numReadyAnims; ++i) {
-                            ValueAnimator anim = readyAnims.get(i);
-                            anim.startAnimation();
-                            anim.mRunning = true;
-                            delayedAnims.remove(anim);
-                        }
-                        readyAnims.clear();
-                    }
-
-                    // Now process all active animations. The return value from animationFrame()
-                    // tells the handler whether it should now be ended
-                    int numAnims = animations.size();
-                    int i = 0;
-                    while (i < numAnims) {
-                        ValueAnimator anim = animations.get(i);
-                        if (anim.animationFrame(currentTime)) {
-                            endingAnims.add(anim);
-                        }
-                        if (animations.size() == numAnims) {
-                            ++i;
-                        } else {
-                            // An animation might be canceled or ended by client code
-                            // during the animation frame. Check to see if this happened by
-                            // seeing whether the current index is the same as it was before
-                            // calling animationFrame(). Another approach would be to copy
-                            // animations to a temporary list and process that list instead,
-                            // but that entails garbage and processing overhead that would
-                            // be nice to avoid.
-                            --numAnims;
-                            endingAnims.remove(anim);
-                        }
-                    }
-                    if (endingAnims.size() > 0) {
-                        for (i = 0; i < endingAnims.size(); ++i) {
-                            endingAnims.get(i).endAnimation();
-                        }
-                        endingAnims.clear();
-                    }
-
-                    // If there are still active or delayed animations, call the handler again
-                    // after the frameDelay
-                    if (callAgain && (!animations.isEmpty() || !delayedAnims.isEmpty())) {
-                        sendEmptyMessageDelayed(ANIMATION_FRAME, Math.max(0, sFrameDelay -
-                            (AnimationUtils.currentAnimationTimeMillis() - currentTime)));
-                    }
+                    doAnimationStart();
                     break;
             }
         }
+
+        private void doAnimationStart() {
+            // mPendingAnimations holds any animations that have requested to be started
+            // We're going to clear mPendingAnimations, but starting animation may
+            // cause more to be added to the pending list (for example, if one animation
+            // starting triggers another starting). So we loop until mPendingAnimations
+            // is empty.
+            while (mPendingAnimations.size() > 0) {
+                ArrayList<ValueAnimator> pendingCopy =
+                        (ArrayList<ValueAnimator>) mPendingAnimations.clone();
+                mPendingAnimations.clear();
+                int count = pendingCopy.size();
+                for (int i = 0; i < count; ++i) {
+                    ValueAnimator anim = pendingCopy.get(i);
+                    // If the animation has a startDelay, place it on the delayed list
+                    if (anim.mStartDelay == 0) {
+                        anim.startAnimation(this);
+                    } else {
+                        mDelayedAnims.add(anim);
+                    }
+                }
+            }
+            doAnimationFrame();
+        }
+
+        private void doAnimationFrame() {
+            // currentTime holds the common time for all animations processed
+            // during this frame
+            long currentTime = AnimationUtils.currentAnimationTimeMillis();
+
+            // First, process animations currently sitting on the delayed queue, adding
+            // them to the active animations if they are ready
+            int numDelayedAnims = mDelayedAnims.size();
+            for (int i = 0; i < numDelayedAnims; ++i) {
+                ValueAnimator anim = mDelayedAnims.get(i);
+                if (anim.delayedAnimationFrame(currentTime)) {
+                    mReadyAnims.add(anim);
+                }
+            }
+            int numReadyAnims = mReadyAnims.size();
+            if (numReadyAnims > 0) {
+                for (int i = 0; i < numReadyAnims; ++i) {
+                    ValueAnimator anim = mReadyAnims.get(i);
+                    anim.startAnimation(this);
+                    anim.mRunning = true;
+                    mDelayedAnims.remove(anim);
+                }
+                mReadyAnims.clear();
+            }
+
+            // Now process all active animations. The return value from animationFrame()
+            // tells the handler whether it should now be ended
+            int numAnims = mAnimations.size();
+            int i = 0;
+            while (i < numAnims) {
+                ValueAnimator anim = mAnimations.get(i);
+                if (anim.animationFrame(currentTime)) {
+                    mEndingAnims.add(anim);
+                }
+                if (mAnimations.size() == numAnims) {
+                    ++i;
+                } else {
+                    // An animation might be canceled or ended by client code
+                    // during the animation frame. Check to see if this happened by
+                    // seeing whether the current index is the same as it was before
+                    // calling animationFrame(). Another approach would be to copy
+                    // animations to a temporary list and process that list instead,
+                    // but that entails garbage and processing overhead that would
+                    // be nice to avoid.
+                    --numAnims;
+                    mEndingAnims.remove(anim);
+                }
+            }
+            if (mEndingAnims.size() > 0) {
+                for (i = 0; i < mEndingAnims.size(); ++i) {
+                    mEndingAnims.get(i).endAnimation(this);
+                }
+                mEndingAnims.clear();
+            }
+
+            // If there are still active or delayed animations, schedule a future call to
+            // onAnimate to process the next frame of the animations.
+            if (!mAnimations.isEmpty() || !mDelayedAnims.isEmpty()) {
+                if (!mIsChoreographed) {
+                    mIsChoreographed = true;
+                    mChoreographer.addOnAnimateListener(this);
+                }
+                mChoreographer.scheduleAnimation();
+            } else {
+                if (mIsChoreographed) {
+                    mIsChoreographed = false;
+                    mChoreographer.removeOnAnimateListener(this);
+                }
+            }
+        }
+
+        @Override
+        public void onAnimate() {
+            doAnimationFrame();
+        }
     }
 
     /**
@@ -708,10 +671,13 @@
      * function because the same delay will be applied to all animations, since they are all
      * run off of a single timing loop.
      *
+     * The frame delay may be ignored when the animation system uses an external timing
+     * source, such as the display refresh rate (vsync), to govern animations.
+     *
      * @return the requested time between frames, in milliseconds
      */
     public static long getFrameDelay() {
-        return sFrameDelay;
+        return Choreographer.getFrameDelay();
     }
 
     /**
@@ -721,10 +687,13 @@
      * function because the same delay will be applied to all animations, since they are all
      * run off of a single timing loop.
      *
+     * The frame delay may be ignored when the animation system uses an external timing
+     * source, such as the display refresh rate (vsync), to govern animations.
+     *
      * @param frameDelay the requested time between frames, in milliseconds
      */
     public static void setFrameDelay(long frameDelay) {
-        sFrameDelay = frameDelay;
+        Choreographer.setFrameDelay(frameDelay);
     }
 
     /**
@@ -921,7 +890,8 @@
         mPlayingState = STOPPED;
         mStarted = true;
         mStartedDelay = false;
-        sPendingAnimations.get().add(this);
+        AnimationHandler animationHandler = getOrCreateAnimationHandler();
+        animationHandler.mPendingAnimations.add(this);
         if (mStartDelay == 0) {
             // This sets the initial value of the animation, prior to actually starting it running
             setCurrentPlayTime(getCurrentPlayTime());
@@ -937,11 +907,6 @@
                 }
             }
         }
-        AnimationHandler animationHandler = sAnimationHandler.get();
-        if (animationHandler == null) {
-            animationHandler = new AnimationHandler();
-            sAnimationHandler.set(animationHandler);
-        }
         animationHandler.sendEmptyMessage(ANIMATION_START);
     }
 
@@ -954,8 +919,10 @@
     public void cancel() {
         // Only cancel if the animation is actually running or has been started and is about
         // to run
-        if (mPlayingState != STOPPED || sPendingAnimations.get().contains(this) ||
-                sDelayedAnims.get().contains(this)) {
+        AnimationHandler handler = getOrCreateAnimationHandler();
+        if (mPlayingState != STOPPED
+                || handler.mPendingAnimations.contains(this)
+                || handler.mDelayedAnims.contains(this)) {
             // Only notify listeners if the animator has actually started
             if (mRunning && mListeners != null) {
                 ArrayList<AnimatorListener> tmpListeners =
@@ -964,16 +931,17 @@
                     listener.onAnimationCancel(this);
                 }
             }
-            endAnimation();
+            endAnimation(handler);
         }
     }
 
     @Override
     public void end() {
-        if (!sAnimations.get().contains(this) && !sPendingAnimations.get().contains(this)) {
+        AnimationHandler handler = getOrCreateAnimationHandler();
+        if (!handler.mAnimations.contains(this) && !handler.mPendingAnimations.contains(this)) {
             // Special case if the animation has not yet started; get it ready for ending
             mStartedDelay = false;
-            startAnimation();
+            startAnimation(handler);
         } else if (!mInitialized) {
             initAnimation();
         }
@@ -984,7 +952,7 @@
         } else {
             animateValue(1f);
         }
-        endAnimation();
+        endAnimation(handler);
     }
 
     @Override
@@ -1020,10 +988,10 @@
      * Called internally to end an animation by removing it from the animations list. Must be
      * called on the UI thread.
      */
-    private void endAnimation() {
-        sAnimations.get().remove(this);
-        sPendingAnimations.get().remove(this);
-        sDelayedAnims.get().remove(this);
+    private void endAnimation(AnimationHandler handler) {
+        handler.mAnimations.remove(this);
+        handler.mPendingAnimations.remove(this);
+        handler.mDelayedAnims.remove(this);
         mPlayingState = STOPPED;
         if (mRunning && mListeners != null) {
             ArrayList<AnimatorListener> tmpListeners =
@@ -1041,9 +1009,9 @@
      * Called internally to start an animation by adding it to the active animations list. Must be
      * called on the UI thread.
      */
-    private void startAnimation() {
+    private void startAnimation(AnimationHandler handler) {
         initAnimation();
-        sAnimations.get().add(this);
+        handler.mAnimations.add(this);
         if (mStartDelay > 0 && mListeners != null) {
             // Listeners were already notified in start() if startDelay is 0; this is
             // just for delayed animations
@@ -1229,13 +1197,14 @@
     /**
      * Return the number of animations currently running.
      *
-     * Used by StrictMode internally to annotate violations.  Only
-     * called on the main thread.
+     * Used by StrictMode internally to annotate violations.
+     * May be called on arbitrary threads!
      *
      * @hide
      */
     public static int getCurrentAnimationsCount() {
-        return sAnimations.get().size();
+        AnimationHandler handler = sAnimationHandler.get();
+        return handler != null ? handler.mAnimations.size() : 0;
     }
 
     /**
@@ -1245,9 +1214,21 @@
      * @hide
      */
     public static void clearAllAnimations() {
-        sAnimations.get().clear();
-        sPendingAnimations.get().clear();
-        sDelayedAnims.get().clear();
+        AnimationHandler handler = sAnimationHandler.get();
+        if (handler != null) {
+            handler.mAnimations.clear();
+            handler.mPendingAnimations.clear();
+            handler.mDelayedAnims.clear();
+        }
+    }
+
+    private AnimationHandler getOrCreateAnimationHandler() {
+        AnimationHandler handler = sAnimationHandler.get();
+        if (handler == null) {
+            handler = new AnimationHandler();
+            sAnimationHandler.set(handler);
+        }
+        return handler;
     }
 
     @Override
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/content/ContentUris.java b/core/java/android/content/ContentUris.java
index aa7603470b..dbe8a7c 100644
--- a/core/java/android/content/ContentUris.java
+++ b/core/java/android/content/ContentUris.java
@@ -19,9 +19,54 @@
 import android.net.Uri;
 
 /**
- * Utility methods useful for working with content {@link android.net.Uri}s,
- * those with a "content" scheme.
- */
+* Utility methods useful for working with {@link android.net.Uri} objects
+* that use the &quot;content&quot; (content://) scheme.
+*
+*<p>
+*   Content URIs have the syntax
+*</p>
+*<p>
+*   <code>content://<em>authority</em>/<em>path</em>/<em>id</em></code>
+*</p>
+*<dl>
+*   <dt>
+*       <code>content:</code>
+*   </dt>
+*   <dd>
+*       The scheme portion of the URI. This is always set to {@link
+*       android.content.ContentResolver#SCHEME_CONTENT ContentResolver.SCHEME_CONTENT} (value
+*       <code>content://</code>).
+*   </dd>
+*   <dt>
+*       <em>authority</em>
+*   </dt>
+*   <dd>
+*       A string that identifies the entire content provider. All the content URIs for the provider
+*       start with this string. To guarantee a unique authority, providers should consider
+*       using an authority that is the same as the provider class' package identifier.
+*   </dd>
+*   <dt>
+*       <em>path</em>
+*   </dt>
+*   <dd>
+*       Zero or more segments, separated by a forward slash (<code>/</code>), that identify
+*       some subset of the provider's data. Most providers use the path part to identify
+*       individual tables. Individual segments in the path are often called
+*       &quot;directories&quot; although they do not refer to file directories. The right-most
+*       segment in a path is often called a &quot;twig&quot;
+*   </dd>
+*   <dt>
+*       <em>id</em>
+*   </dt>
+*   <dd>
+*       A unique numeric identifier for a single row in the subset of data identified by the
+*       preceding path part. Most providers recognize content URIs that contain an id part
+*       and give them special handling. A table that contains a column named <code>_ID</code>
+*       often expects the id part to be a particular value for that column.
+*   </dd>
+*</dl>
+*
+*/
 public class ContentUris {
 
     /**
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 9948985..4e5598b 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -2315,6 +2315,11 @@
     /**
      * Used with {@link #ACTION_MAIN} to launch the browser application.
      * The activity should be able to browse the Internet.
+     * <p>NOTE: This should not be used as the primary key of an Intent,
+     * since it will not result in the app launching with the correct
+     * action and category.  Instead, use this with
+     * {@link #makeMainSelectorActivity(String, String) to generate a main
+     * Intent with this category in the selector.</p>
      */
     @SdkConstant(SdkConstantType.INTENT_CATEGORY)
     public static final String CATEGORY_APP_BROWSER = "android.intent.category.APP_BROWSER";
@@ -2322,6 +2327,11 @@
     /**
      * Used with {@link #ACTION_MAIN} to launch the calculator application.
      * The activity should be able to perform standard arithmetic operations.
+     * <p>NOTE: This should not be used as the primary key of an Intent,
+     * since it will not result in the app launching with the correct
+     * action and category.  Instead, use this with
+     * {@link #makeMainSelectorActivity(String, String) to generate a main
+     * Intent with this category in the selector.</p>
      */
     @SdkConstant(SdkConstantType.INTENT_CATEGORY)
     public static final String CATEGORY_APP_CALCULATOR = "android.intent.category.APP_CALCULATOR";
@@ -2329,6 +2339,11 @@
     /**
      * Used with {@link #ACTION_MAIN} to launch the calendar application.
      * The activity should be able to view and manipulate calendar entries.
+     * <p>NOTE: This should not be used as the primary key of an Intent,
+     * since it will not result in the app launching with the correct
+     * action and category.  Instead, use this with
+     * {@link #makeMainSelectorActivity(String, String) to generate a main
+     * Intent with this category in the selector.</p>
      */
     @SdkConstant(SdkConstantType.INTENT_CATEGORY)
     public static final String CATEGORY_APP_CALENDAR = "android.intent.category.APP_CALENDAR";
@@ -2336,6 +2351,11 @@
     /**
      * Used with {@link #ACTION_MAIN} to launch the contacts application.
      * The activity should be able to view and manipulate address book entries.
+     * <p>NOTE: This should not be used as the primary key of an Intent,
+     * since it will not result in the app launching with the correct
+     * action and category.  Instead, use this with
+     * {@link #makeMainSelectorActivity(String, String) to generate a main
+     * Intent with this category in the selector.</p>
      */
     @SdkConstant(SdkConstantType.INTENT_CATEGORY)
     public static final String CATEGORY_APP_CONTACTS = "android.intent.category.APP_CONTACTS";
@@ -2343,6 +2363,11 @@
     /**
      * Used with {@link #ACTION_MAIN} to launch the email application.
      * The activity should be able to send and receive email.
+     * <p>NOTE: This should not be used as the primary key of an Intent,
+     * since it will not result in the app launching with the correct
+     * action and category.  Instead, use this with
+     * {@link #makeMainSelectorActivity(String, String) to generate a main
+     * Intent with this category in the selector.</p>
      */
     @SdkConstant(SdkConstantType.INTENT_CATEGORY)
     public static final String CATEGORY_APP_EMAIL = "android.intent.category.APP_EMAIL";
@@ -2351,6 +2376,11 @@
      * Used with {@link #ACTION_MAIN} to launch the gallery application.
      * The activity should be able to view and manipulate image and video files
      * stored on the device.
+     * <p>NOTE: This should not be used as the primary key of an Intent,
+     * since it will not result in the app launching with the correct
+     * action and category.  Instead, use this with
+     * {@link #makeMainSelectorActivity(String, String) to generate a main
+     * Intent with this category in the selector.</p>
      */
     @SdkConstant(SdkConstantType.INTENT_CATEGORY)
     public static final String CATEGORY_APP_GALLERY = "android.intent.category.APP_GALLERY";
@@ -2358,6 +2388,11 @@
     /**
      * Used with {@link #ACTION_MAIN} to launch the maps application.
      * The activity should be able to show the user's current location and surroundings.
+     * <p>NOTE: This should not be used as the primary key of an Intent,
+     * since it will not result in the app launching with the correct
+     * action and category.  Instead, use this with
+     * {@link #makeMainSelectorActivity(String, String) to generate a main
+     * Intent with this category in the selector.</p>
      */
     @SdkConstant(SdkConstantType.INTENT_CATEGORY)
     public static final String CATEGORY_APP_MAPS = "android.intent.category.APP_MAPS";
@@ -2365,13 +2400,24 @@
     /**
      * Used with {@link #ACTION_MAIN} to launch the messaging application.
      * The activity should be able to send and receive text messages.
+     * <p>NOTE: This should not be used as the primary key of an Intent,
+     * since it will not result in the app launching with the correct
+     * action and category.  Instead, use this with
+     * {@link #makeMainSelectorActivity(String, String) to generate a main
+     * Intent with this category in the selector.</p>
      */
     @SdkConstant(SdkConstantType.INTENT_CATEGORY)
     public static final String CATEGORY_APP_MESSAGING = "android.intent.category.APP_MESSAGING";
 
     /**
      * Used with {@link #ACTION_MAIN} to launch the music application.
-     * The activity should be able to play, browse, or manipulate music files stored on the device.
+     * The activity should be able to play, browse, or manipulate music files
+     * stored on the device.
+     * <p>NOTE: This should not be used as the primary key of an Intent,
+     * since it will not result in the app launching with the correct
+     * action and category.  Instead, use this with
+     * {@link #makeMainSelectorActivity(String, String) to generate a main
+     * Intent with this category in the selector.</p>
      */
     @SdkConstant(SdkConstantType.INTENT_CATEGORY)
     public static final String CATEGORY_APP_MUSIC = "android.intent.category.APP_MUSIC";
@@ -2963,6 +3009,7 @@
     private HashSet<String> mCategories;
     private Bundle mExtras;
     private Rect mSourceBounds;
+    private Intent mSelector;
 
     // ---------------------------------------------------------------------
 
@@ -2991,6 +3038,9 @@
         if (o.mSourceBounds != null) {
             this.mSourceBounds = new Rect(o.mSourceBounds);
         }
+        if (o.mSelector != null) {
+            this.mSelector = new Intent(o.mSelector);
+        }
     }
 
     @Override
@@ -3131,6 +3181,39 @@
     }
 
     /**
+     * Make an Intent for the main activity of an application, without
+     * specifying a specific activity to run but giving a selector to find
+     * the activity.  This results in a final Intent that is structured
+     * the same as when the application is launched from
+     * Home.  For anything else that wants to launch an application in the
+     * same way, it is important that they use an Intent structured the same
+     * way, and can use this function to ensure this is the case.
+     *
+     * <p>The returned Intent has {@link #ACTION_MAIN} as its action, and includes the
+     * category {@link #CATEGORY_LAUNCHER}.  This does <em>not</em> have
+     * {@link #FLAG_ACTIVITY_NEW_TASK} set, though typically you will want
+     * to do that through {@link #addFlags(int)} on the returned Intent.
+     *
+     * @param selectorAction The action name of the Intent's selector.
+     * @param selectorCategory The name of a category to add to the Intent's
+     * selector.
+     * @return Returns a newly created Intent that can be used to launch the
+     * activity as a main application entry.
+     *
+     * @see #setSelector(Intent)
+     */
+    public static Intent makeMainSelectorActivity(String selectorAction,
+            String selectorCategory) {
+        Intent intent = new Intent(ACTION_MAIN);
+        intent.addCategory(CATEGORY_LAUNCHER);
+        Intent selector = new Intent();
+        selector.setAction(selectorAction);
+        selector.addCategory(selectorCategory);
+        intent.setSelector(selector);
+        return intent;
+    }
+
+    /**
      * Make an Intent that can be used to re-launch an application's task
      * in its base state.  This is like {@link #makeMainActivity(ComponentName)},
      * but also sets the flags {@link #FLAG_ACTIVITY_NEW_TASK} and
@@ -3205,6 +3288,7 @@
 
             // new format
             Intent intent = new Intent(ACTION_VIEW);
+            Intent baseIntent = intent;
 
             // fetch data part, if present
             String data = i >= 0 ? uri.substring(0, i) : null;
@@ -3214,8 +3298,9 @@
             // loop over contents of Intent, all name=value;
             while (!uri.startsWith("end", i)) {
                 int eq = uri.indexOf('=', i);
-                int semi = uri.indexOf(';', eq);
-                String value = Uri.decode(uri.substring(eq + 1, semi));
+                if (eq < 0) eq = i-1;
+                int semi = uri.indexOf(';', i);
+                String value = eq < semi ? Uri.decode(uri.substring(eq + 1, semi)) : "";
 
                 // action
                 if (uri.startsWith("action=", i)) {
@@ -3257,6 +3342,11 @@
                     intent.mSourceBounds = Rect.unflattenFromString(value);
                 }
 
+                // selector
+                else if (semi == (i+3) && uri.startsWith("SEL", i)) {
+                    intent = new Intent();
+                }
+
                 // extra
                 else {
                     String key = Uri.decode(uri.substring(i + 2, eq));
@@ -3280,6 +3370,12 @@
                 i = semi + 1;
             }
 
+            if (intent != baseIntent) {
+                // The Intent had a selector; fix it up.
+                baseIntent.setSelector(intent);
+                intent = baseIntent;
+            }
+
             if (data != null) {
                 if (data.startsWith("intent:")) {
                     data = data.substring(7);
@@ -3605,7 +3701,7 @@
      * Return the set of all categories in the intent.  If there are no categories,
      * returns NULL.
      *
-     * @return Set The set of categories you can examine.  Do not modify!
+     * @return The set of categories you can examine.  Do not modify!
      *
      * @see #hasCategory
      * @see #addCategory
@@ -3615,6 +3711,16 @@
     }
 
     /**
+     * Return the specific selector associated with this Intent.  If there is
+     * none, returns null.  See {@link #setSelector} for more information.
+     *
+     * @see #setSelector
+     */
+    public Intent getSelector() {
+        return mSelector;
+    }
+
+    /**
      * Sets the ClassLoader that will be used when unmarshalling
      * any Parcelable values from the extras of this Intent.
      *
@@ -4433,6 +4539,49 @@
     }
 
     /**
+     * Set a selector for this Intent.  This is a modification to the kinds of
+     * things the Intent will match.  If the selector is set, it will be used
+     * when trying to find entities that can handle the Intent, instead of the
+     * main contents of the Intent.  This allows you build an Intent containing
+     * a generic protocol while targeting it more specifically.
+     *
+     * <p>An example of where this may be used is with things like
+     * {@link #CATEGORY_APP_BROWSER}.  This category allows you to build an
+     * Intent that will launch the Browser application.  However, the correct
+     * main entry point of an application is actually {@link #ACTION_MAIN}
+     * {@link #CATEGORY_LAUNCHER} with {@link #setComponent(ComponentName)}
+     * used to specify the actual Activity to launch.  If you launch the browser
+     * with something different, undesired behavior may happen if the user has
+     * previously or later launches it the normal way, since they do not match.
+     * Instead, you can build an Intent with the MAIN action (but no ComponentName
+     * yet specified) and set a selector with {@link #ACTION_MAIN} and
+     * {@link #CATEGORY_APP_BROWSER} to point it specifically to the browser activity.
+     *
+     * <p>Setting a selector does not impact the behavior of
+     * {@link #filterEquals(Intent)} and {@link #filterHashCode()}.  This is part of the
+     * desired behavior of a selector -- it does not impact the base meaning
+     * of the Intent, just what kinds of things will be matched against it
+     * when determining who can handle it.</p>
+     *
+     * <p>You can not use both a selector and {@link #setPackage(String)} on
+     * the same base Intent.</p>
+     *
+     * @param selector The desired selector Intent; set to null to not use
+     * a special selector.
+     */
+    public void setSelector(Intent selector) {
+        if (selector == this) {
+            throw new IllegalArgumentException(
+                    "Intent being set as a selector of itself");
+        }
+        if (selector != null && mPackage != null) {
+            throw new IllegalArgumentException(
+                    "Can't set selector when package name is already set");
+        }
+        mSelector = selector;
+    }
+
+    /**
      * Add extended data to the intent.  The name must include a package
      * prefix, for example the app com.android.contacts would use names
      * like "com.android.contacts.ShowAll".
@@ -5259,6 +5408,10 @@
      * @see #resolveActivity
      */
     public Intent setPackage(String packageName) {
+        if (packageName != null && mSelector != null) {
+            throw new IllegalArgumentException(
+                    "Can't set package name when selector is already set");
+        }
         mPackage = packageName;
         return this;
     }
@@ -5394,12 +5547,18 @@
     public static final int FILL_IN_PACKAGE = 1<<4;
 
     /**
-     * Use with {@link #fillIn} to allow the current package value to be
+     * Use with {@link #fillIn} to allow the current bounds rectangle to be
      * overwritten, even if it is already set.
      */
     public static final int FILL_IN_SOURCE_BOUNDS = 1<<5;
 
     /**
+     * Use with {@link #fillIn} to allow the current selector to be
+     * overwritten, even if it is already set.
+     */
+    public static final int FILL_IN_SELECTOR = 1<<6;
+
+    /**
      * Copy the contents of <var>other</var> in to this object, but only
      * where fields are not defined by this object.  For purposes of a field
      * being defined, the following pieces of data in the Intent are
@@ -5419,11 +5578,13 @@
      *
      * <p>In addition, you can use the {@link #FILL_IN_ACTION},
      * {@link #FILL_IN_DATA}, {@link #FILL_IN_CATEGORIES}, {@link #FILL_IN_PACKAGE},
-     * and {@link #FILL_IN_COMPONENT} to override the restriction where the
+     * {@link #FILL_IN_COMPONENT}, {@link #FILL_IN_SOURCE_BOUNDS}, and
+     * {@link #FILL_IN_SELECTOR} to override the restriction where the
      * corresponding field will not be replaced if it is already set.
      *
      * <p>Note: The component field will only be copied if {@link #FILL_IN_COMPONENT} is explicitly
-     * specified.
+     * specified.  The selector will only be copied if {@link #FILL_IN_SELECTOR} is
+     * explicitly specified.
      *
      * <p>For example, consider Intent A with {data="foo", categories="bar"}
      * and Intent B with {action="gotit", data-type="some/thing",
@@ -5439,7 +5600,8 @@
      *
      * @return Returns a bit mask of {@link #FILL_IN_ACTION},
      * {@link #FILL_IN_DATA}, {@link #FILL_IN_CATEGORIES}, {@link #FILL_IN_PACKAGE},
-     * and {@link #FILL_IN_COMPONENT} indicating which fields were changed.
+     * {@link #FILL_IN_COMPONENT}, {@link #FILL_IN_SOURCE_BOUNDS}, and
+     * {@link #FILL_IN_SELECTOR} indicating which fields were changed.
      */
     public int fillIn(Intent other, int flags) {
         int changes = 0;
@@ -5464,8 +5626,20 @@
         }
         if (other.mPackage != null
                 && (mPackage == null || (flags&FILL_IN_PACKAGE) != 0)) {
-            mPackage = other.mPackage;
-            changes |= FILL_IN_PACKAGE;
+            // Only do this if mSelector is not set.
+            if (mSelector == null) {
+                mPackage = other.mPackage;
+                changes |= FILL_IN_PACKAGE;
+            }
+        }
+        // Selector is special: it can only be set if explicitly allowed,
+        // for the same reason as the component name.
+        if (other.mSelector != null && (flags&FILL_IN_SELECTOR) != 0) {
+            if (mPackage == null) {
+                mSelector = new Intent(other.mSelector);
+                mPackage = null;
+                changes |= FILL_IN_SELECTOR;
+            }
         }
         // Component is special: it can -only- be set if explicitly allowed,
         // since otherwise the sender could force the intent somewhere the
@@ -5763,6 +5937,11 @@
             first = false;
             b.append("(has extras)");
         }
+        if (mSelector != null) {
+            b.append(" sel={");
+            mSelector.toShortString(b, secure, comp, extras);
+            b.append("}");
+        }
     }
 
     /**
@@ -5823,6 +6002,21 @@
 
         uri.append("#Intent;");
 
+        toUriInner(uri, scheme, flags);
+        if (mSelector != null) {
+            uri.append("SEL;");
+            // Note that for now we are not going to try to handle the
+            // data part; not clear how to represent this as a URI, and
+            // not much utility in it.
+            mSelector.toUriInner(uri, null, flags);
+        }
+
+        uri.append("end");
+
+        return uri.toString();
+    }
+
+    private void toUriInner(StringBuilder uri, String scheme, int flags) {
         if (scheme != null) {
             uri.append("scheme=").append(scheme).append(';');
         }
@@ -5877,10 +6071,6 @@
                 }
             }
         }
-
-        uri.append("end");
-
-        return uri.toString();
     }
 
     public int describeContents() {
@@ -5911,6 +6101,13 @@
             out.writeInt(0);
         }
 
+        if (mSelector != null) {
+            out.writeInt(1);
+            mSelector.writeToParcel(out, flags);
+        } else {
+            out.writeInt(0);
+        }
+
         out.writeBundle(mExtras);
     }
 
@@ -5952,6 +6149,10 @@
             mCategories = null;
         }
 
+        if (in.readInt() != 0) {
+            mSelector = new Intent(in);
+        }
+
         mExtras = in.readBundle();
     }
 
diff --git a/core/java/android/content/SyncManager.java b/core/java/android/content/SyncManager.java
index b2909b3..3c4e545 100644
--- a/core/java/android/content/SyncManager.java
+++ b/core/java/android/content/SyncManager.java
@@ -24,6 +24,7 @@
 import android.accounts.Account;
 import android.accounts.AccountManager;
 import android.accounts.OnAccountsUpdateListener;
+import android.app.ActivityManager;
 import android.app.AlarmManager;
 import android.app.Notification;
 import android.app.NotificationManager;
@@ -86,8 +87,13 @@
     private static final long MAX_TIME_PER_SYNC;
 
     static {
-        MAX_SIMULTANEOUS_INITIALIZATION_SYNCS = SystemProperties.getInt("sync.max_init_syncs", 5);
-        MAX_SIMULTANEOUS_REGULAR_SYNCS = SystemProperties.getInt("sync.max_regular_syncs", 2);
+        final boolean isLargeRAM = ActivityManager.isLargeRAM();
+        int defaultMaxInitSyncs = isLargeRAM ? 5 : 2;
+        int defaultMaxRegularSyncs = isLargeRAM ? 2 : 1;
+        MAX_SIMULTANEOUS_INITIALIZATION_SYNCS =
+                SystemProperties.getInt("sync.max_init_syncs", defaultMaxInitSyncs);
+        MAX_SIMULTANEOUS_REGULAR_SYNCS =
+                SystemProperties.getInt("sync.max_regular_syncs", defaultMaxRegularSyncs);
         LOCAL_SYNC_DELAY =
                 SystemProperties.getLong("sync.local_sync_delay", 30 * 1000 /* 30 seconds */);
         MAX_TIME_PER_SYNC =
diff --git a/core/java/android/inputmethodservice/ExtractEditText.java b/core/java/android/inputmethodservice/ExtractEditText.java
index 72431f3..10c1195 100644
--- a/core/java/android/inputmethodservice/ExtractEditText.java
+++ b/core/java/android/inputmethodservice/ExtractEditText.java
@@ -158,25 +158,46 @@
     }
 
     /**
-     * Delete the range of text, supposedly valid
+     * {@inheritDoc}
      * @hide
      */
     @Override
     protected void deleteText_internal(int start, int end) {
-        // Do not call the super method. This will change the source TextView instead, which
-        // will update the ExtractTextView.
+        // Do not call the super method.
+        // This will change the source TextView instead, which will update the ExtractTextView.
         mIME.onExtractedDeleteText(start, end);
     }
 
     /**
-     * Replaces the range of text [start, end[ by replacement text
+     * {@inheritDoc}
      * @hide
      */
     @Override
     protected void replaceText_internal(int start, int end, CharSequence text) {
-        // Do not call the super method. This will change the source TextView instead, which
-        // will update the ExtractTextView.
+        // Do not call the super method.
+        // This will change the source TextView instead, which will update the ExtractTextView.
         mIME.onExtractedReplaceText(start, end, text);
     }
 
+    /**
+     * {@inheritDoc}
+     * @hide
+     */
+    @Override
+    protected void setSpan_internal(Object span, int start, int end, int flags) {
+        // Do not call the super method.
+        // This will change the source TextView instead, which will update the ExtractTextView.
+        mIME.onExtractedSetSpan(span, start, end, flags);
+    }
+
+    /**
+     * {@inheritDoc}
+     * @hide
+     */
+    @Override
+    protected void setCursorPosition_internal(int start, int end) {
+        // Do not call the super method.
+        // This will change the source TextView instead, which will update the ExtractTextView.
+        mIME.onExtractedSelectionChanged(start, end);
+    }
 }
diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java
index 02839db..53cdf21 100644
--- a/core/java/android/inputmethodservice/InputMethodService.java
+++ b/core/java/android/inputmethodservice/InputMethodService.java
@@ -2006,6 +2006,22 @@
     }
 
     /**
+     * @hide
+     */
+    public void onExtractedSetSpan(Object span, int start, int end, int flags) {
+        InputConnection conn = getCurrentInputConnection();
+        if (conn != null) {
+            if (!conn.setSelection(start, end)) return;
+            CharSequence text = conn.getSelectedText(InputConnection.GET_TEXT_WITH_STYLES);
+            if (text instanceof Spannable) {
+                ((Spannable) text).setSpan(span, 0, text.length(), flags);
+                conn.setComposingRegion(start, end);
+                conn.commitText(text, 1);
+            }
+        }
+    }
+
+    /**
      * This is called when the user has clicked on the extracted text view,
      * when running in fullscreen mode.  The default implementation hides
      * the candidates view when this happens, but only if the extracted text
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/net/NetworkUtils.java b/core/java/android/net/NetworkUtils.java
index e289fc1..d39e741 100644
--- a/core/java/android/net/NetworkUtils.java
+++ b/core/java/android/net/NetworkUtils.java
@@ -250,4 +250,32 @@
         }
         return result;
     }
+
+    /**
+     * Trim leading zeros from IPv4 address strings
+     * Our base libraries will interpret that as octel..
+     * Must leave non v4 addresses and host names alone.
+     * For example, 192.168.000.010 -> 192.168.0.10
+     * TODO - fix base libraries and remove this function
+     * @param addr a string representing an ip addr
+     * @return a string propertly trimmed
+     */
+    public static String trimV4AddrZeros(String addr) {
+        if (addr == null) return null;
+        String[] octets = addr.split("\\.");
+        if (octets.length != 4) return addr;
+        StringBuilder builder = new StringBuilder(16);
+        String result = null;
+        for (int i = 0; i < 4; i++) {
+            try {
+                if (octets[i].length() > 3) return addr;
+                builder.append(Integer.parseInt(octets[i]));
+            } catch (NumberFormatException e) {
+                return addr;
+            }
+            if (i < 3) builder.append('.');
+        }
+        result = builder.toString();
+        return result;
+    }
 }
diff --git a/core/java/android/os/AsyncTask.java b/core/java/android/os/AsyncTask.java
index 9dea4c4..5e9abb7 100644
--- a/core/java/android/os/AsyncTask.java
+++ b/core/java/android/os/AsyncTask.java
@@ -195,6 +195,7 @@
 
     private volatile Status mStatus = Status.PENDING;
     
+    private final AtomicBoolean mCancelled = new AtomicBoolean();
     private final AtomicBoolean mTaskInvoked = new AtomicBoolean();
 
     private static class SerialExecutor implements Executor {
@@ -261,6 +262,7 @@
                 mTaskInvoked.set(true);
 
                 Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
+                //noinspection unchecked
                 return postResult(doInBackground(mParams));
             }
         };
@@ -269,9 +271,7 @@
             @Override
             protected void done() {
                 try {
-                    final Result result = get();
-
-                    postResultIfNotInvoked(result);
+                    postResultIfNotInvoked(get());
                 } catch (InterruptedException e) {
                     android.util.Log.w(LOG_TAG, e);
                 } catch (ExecutionException e) {
@@ -295,6 +295,7 @@
     }
 
     private Result postResult(Result result) {
+        @SuppressWarnings("unchecked")
         Message message = sHandler.obtainMessage(MESSAGE_POST_RESULT,
                 new AsyncTaskResult<Result>(this, result));
         message.sendToTarget();
@@ -411,7 +412,7 @@
      * @see #cancel(boolean)
      */
     public final boolean isCancelled() {
-        return mFuture.isCancelled();
+        return mCancelled.get();
     }
 
     /**
@@ -444,6 +445,7 @@
      * @see #onCancelled(Object)
      */
     public final boolean cancel(boolean mayInterruptIfRunning) {
+        mCancelled.set(true);
         return mFuture.cancel(mayInterruptIfRunning);
     }
 
diff --git a/core/java/android/os/Build.java b/core/java/android/os/Build.java
index 7d034940..88fea91 100644
--- a/core/java/android/os/Build.java
+++ b/core/java/android/os/Build.java
@@ -311,7 +311,7 @@
         public static final int ICE_CREAM_SANDWICH = 14;
 
         /**
-         * Android 4.1.
+         * Android 4.0.3.
          */
         public static final int ICE_CREAM_SANDWICH_MR1 = 15;
     }
diff --git a/core/java/android/os/storage/package.html b/core/java/android/os/storage/package.html
new file mode 100644
index 0000000..a5f1e1c
--- /dev/null
+++ b/core/java/android/os/storage/package.html
@@ -0,0 +1,8 @@
+<HTML>
+<BODY>
+<p>
+Contains classes for the system storage service, which manages binary asset filesystems
+known as Opaque Binary Blobs (OBBs).
+</p>
+</BODY>
+</HTML>
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 1b5d73e..c44f23b 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -2774,10 +2774,15 @@
             "enabled_accessibility_services";
 
         /**
-         * If injection of accessibility enhancing JavaScript scripts
+         * Whether to speak passwords while in accessibility mode.
+         */
+        public static final String ACCESSIBILITY_SPEAK_PASSWORD = "speak_password";
+
+        /**
+         * If injection of accessibility enhancing JavaScript screen-reader
          * is enabled.
          * <p>
-         *   Note: Accessibility injecting scripts are served by the
+         *   Note: The JavaScript based screen-reader is served by the
          *   Google infrastructure and enable users with disabilities to
          *   efficiantly navigate in and explore web content.
          * </p>
@@ -2790,6 +2795,22 @@
             "accessibility_script_injection";
 
         /**
+         * The URL for the injected JavaScript based screen-reader used
+         * for providing accessiblity of content in WebView.
+         * <p>
+         *   Note: The JavaScript based screen-reader is served by the
+         *   Google infrastructure and enable users with disabilities to
+         *   efficiently navigate in and explore web content.
+         * </p>
+         * <p>
+         *   This property represents a string value.
+         * </p>
+         * @hide
+         */
+        public static final String ACCESSIBILITY_SCREEN_READER_URL =
+            "accessibility_script_injection_url";
+
+        /**
          * Key bindings for navigation in built-in accessibility support for web content.
          * <p>
          *   Note: These key bindings are for the built-in accessibility navigation for
@@ -3127,6 +3148,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 +4150,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/server/BluetoothAdapterStateMachine.java b/core/java/android/server/BluetoothAdapterStateMachine.java
index c59a05a..f4a390e 100644
--- a/core/java/android/server/BluetoothAdapterStateMachine.java
+++ b/core/java/android/server/BluetoothAdapterStateMachine.java
@@ -186,8 +186,8 @@
             switch(message.what) {
                 case USER_TURN_ON:
                     // starts turning on BT module, broadcast this out
-                    transitionTo(mWarmUp);
                     broadcastState(BluetoothAdapter.STATE_TURNING_ON);
+                    transitionTo(mWarmUp);
                     if (prepareBluetooth()) {
                         // this is user request, save the setting
                         if ((Boolean) message.obj) {
@@ -209,8 +209,8 @@
                 case AIRPLANE_MODE_OFF:
                     if (getBluetoothPersistedSetting()) {
                         // starts turning on BT module, broadcast this out
-                        transitionTo(mWarmUp);
                         broadcastState(BluetoothAdapter.STATE_TURNING_ON);
+                        transitionTo(mWarmUp);
                         if (prepareBluetooth()) {
                             // We will continue turn the BT on all the way to the BluetoothOn state
                             deferMessage(obtainMessage(TURN_ON_CONTINUE));
@@ -366,9 +366,9 @@
                     // let it fall to TURN_ON_CONTINUE:
                     //$FALL-THROUGH$
                 case TURN_ON_CONTINUE:
+                    broadcastState(BluetoothAdapter.STATE_TURNING_ON);
                     mBluetoothService.switchConnectable(true);
                     transitionTo(mSwitching);
-                    broadcastState(BluetoothAdapter.STATE_TURNING_ON);
                     break;
                 case AIRPLANE_MODE_ON:
                 case TURN_COLD:
@@ -378,9 +378,9 @@
                     break;
                 case AIRPLANE_MODE_OFF:
                     if (getBluetoothPersistedSetting()) {
+                        broadcastState(BluetoothAdapter.STATE_TURNING_ON);
                         transitionTo(mSwitching);
                         mBluetoothService.switchConnectable(true);
-                        broadcastState(BluetoothAdapter.STATE_TURNING_ON);
                     }
                     break;
                 case PER_PROCESS_TURN_ON:
@@ -526,8 +526,8 @@
                     }
                     //$FALL-THROUGH$ to AIRPLANE_MODE_ON
                 case AIRPLANE_MODE_ON:
-                    transitionTo(mSwitching);
                     broadcastState(BluetoothAdapter.STATE_TURNING_OFF);
+                    transitionTo(mSwitching);
                     if (mBluetoothService.getAdapterConnectionState() !=
                         BluetoothAdapter.STATE_DISCONNECTED) {
                         mBluetoothService.disconnectDevices();
diff --git a/core/java/android/speech/tts/AudioPlaybackQueueItem.java b/core/java/android/speech/tts/AudioPlaybackQueueItem.java
index 668b459..1a1fda81 100644
--- a/core/java/android/speech/tts/AudioPlaybackQueueItem.java
+++ b/core/java/android/speech/tts/AudioPlaybackQueueItem.java
@@ -15,27 +15,91 @@
  */
 package android.speech.tts;
 
+import android.content.Context;
+import android.media.MediaPlayer;
+import android.net.Uri;
+import android.os.ConditionVariable;
 import android.speech.tts.TextToSpeechService.UtteranceProgressDispatcher;
 import android.util.Log;
 
 class AudioPlaybackQueueItem extends PlaybackQueueItem {
-    private final BlockingMediaPlayer mPlayer;
+    private static final String TAG = "TTS.AudioQueueItem";
+
+    private final Context mContext;
+    private final Uri mUri;
+    private final int mStreamType;
+
+    private final ConditionVariable mDone;
+    private MediaPlayer mPlayer;
+    private volatile boolean mFinished;
 
     AudioPlaybackQueueItem(UtteranceProgressDispatcher dispatcher,
-            Object callerIdentity, BlockingMediaPlayer player) {
+            Object callerIdentity,
+            Context context, Uri uri, int streamType) {
         super(dispatcher, callerIdentity);
-        mPlayer = player;
+
+        mContext = context;
+        mUri = uri;
+        mStreamType = streamType;
+
+        mDone = new ConditionVariable();
+        mPlayer = null;
+        mFinished = false;
     }
     @Override
     public void run() {
-        getDispatcher().dispatchOnStart();
-        // TODO: This can be avoided. Will be fixed later in this CL.
-        mPlayer.startAndWait();
-        getDispatcher().dispatchOnDone();
+        final UtteranceProgressDispatcher dispatcher = getDispatcher();
+
+        dispatcher.dispatchOnStart();
+        mPlayer = MediaPlayer.create(mContext, mUri);
+        if (mPlayer == null) {
+            dispatcher.dispatchOnError();
+            return;
+        }
+
+        try {
+            mPlayer.setOnErrorListener(new MediaPlayer.OnErrorListener() {
+                @Override
+                public boolean onError(MediaPlayer mp, int what, int extra) {
+                    Log.w(TAG, "Audio playback error: " + what + ", " + extra);
+                    mDone.open();
+                    return true;
+                }
+            });
+            mPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
+                @Override
+                public void onCompletion(MediaPlayer mp) {
+                    mFinished = true;
+                    mDone.open();
+                }
+            });
+            mPlayer.setAudioStreamType(mStreamType);
+            mPlayer.start();
+            mDone.block();
+            finish();
+        } catch (IllegalArgumentException ex) {
+            Log.w(TAG, "MediaPlayer failed", ex);
+            mDone.open();
+        }
+
+        if (mFinished) {
+            dispatcher.dispatchOnDone();
+        } else {
+            dispatcher.dispatchOnError();
+        }
+    }
+
+    private void finish() {
+        try {
+            mPlayer.stop();
+        } catch (IllegalStateException ex) {
+            // Do nothing, the player is already stopped
+        }
+        mPlayer.release();
     }
 
     @Override
     void stop(boolean isError) {
-        mPlayer.stop();
+        mDone.open();
     }
 }
diff --git a/core/java/android/speech/tts/BlockingMediaPlayer.java b/core/java/android/speech/tts/BlockingMediaPlayer.java
deleted file mode 100644
index 1ccc6e4..0000000
--- a/core/java/android/speech/tts/BlockingMediaPlayer.java
+++ /dev/null
@@ -1,145 +0,0 @@
-/*
- * 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 android.speech.tts;
-
-import android.content.Context;
-import android.media.MediaPlayer;
-import android.net.Uri;
-import android.os.ConditionVariable;
-import android.os.Handler;
-import android.os.HandlerThread;
-import android.os.Looper;
-import android.util.Log;
-
-/**
- * A media player that allows blocking to wait for it to finish.
- */
-class BlockingMediaPlayer {
-
-    private static final String TAG = "BlockMediaPlayer";
-
-    private static final String MEDIA_PLAYER_THREAD_NAME = "TTS-MediaPlayer";
-
-    private final Context mContext;
-    private final Uri mUri;
-    private final int mStreamType;
-    private final ConditionVariable mDone;
-    // Only accessed on the Handler thread
-    private MediaPlayer mPlayer;
-    private volatile boolean mFinished;
-
-    /**
-     * Creates a new blocking media player.
-     * Creating a blocking media player is a cheap operation.
-     *
-     * @param context
-     * @param uri
-     * @param streamType
-     */
-    public BlockingMediaPlayer(Context context, Uri uri, int streamType) {
-        mContext = context;
-        mUri = uri;
-        mStreamType = streamType;
-        mDone = new ConditionVariable();
-    }
-
-    /**
-     * Starts playback and waits for it to finish.
-     * Can be called from any thread.
-     *
-     * @return {@code true} if the playback finished normally, {@code false} if the playback
-     *         failed or {@link #stop} was called before the playback finished.
-     */
-    public boolean startAndWait() {
-        HandlerThread thread = new HandlerThread(MEDIA_PLAYER_THREAD_NAME);
-        thread.start();
-        Handler handler = new Handler(thread.getLooper());
-        mFinished = false;
-        handler.post(new Runnable() {
-            @Override
-            public void run() {
-                startPlaying();
-            }
-        });
-        mDone.block();
-        handler.post(new Runnable() {
-            @Override
-            public void run() {
-                finish();
-                // No new messages should get posted to the handler thread after this
-                Looper.myLooper().quit();
-            }
-        });
-        return mFinished;
-    }
-
-    /**
-     * Stops playback. Can be called multiple times.
-     * Can be called from any thread.
-     */
-    public void stop() {
-        mDone.open();
-    }
-
-    /**
-     * Starts playback.
-     * Called on the handler thread.
-     */
-    private void startPlaying() {
-        mPlayer = MediaPlayer.create(mContext, mUri);
-        if (mPlayer == null) {
-            Log.w(TAG, "Failed to play " + mUri);
-            mDone.open();
-            return;
-        }
-        try {
-            mPlayer.setOnErrorListener(new MediaPlayer.OnErrorListener() {
-                @Override
-                public boolean onError(MediaPlayer mp, int what, int extra) {
-                    Log.w(TAG, "Audio playback error: " + what + ", " + extra);
-                    mDone.open();
-                    return true;
-                }
-            });
-            mPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
-                @Override
-                public void onCompletion(MediaPlayer mp) {
-                    mFinished = true;
-                    mDone.open();
-                }
-            });
-            mPlayer.setAudioStreamType(mStreamType);
-            mPlayer.start();
-        } catch (IllegalArgumentException ex) {
-            Log.w(TAG, "MediaPlayer failed", ex);
-            mDone.open();
-        }
-    }
-
-    /**
-     * Stops playback and release the media player.
-     * Called on the handler thread.
-     */
-    private void finish() {
-        try {
-            mPlayer.stop();
-        } catch (IllegalStateException ex) {
-            // Do nothing, the player is already stopped
-        }
-        mPlayer.release();
-    }
-
-}
\ No newline at end of file
diff --git a/core/java/android/speech/tts/MessageParams.java b/core/java/android/speech/tts/MessageParams.java
deleted file mode 100644
index f83b793..0000000
--- a/core/java/android/speech/tts/MessageParams.java
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * 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 android.speech.tts;
-
-import android.speech.tts.TextToSpeechService.UtteranceProgressDispatcher;
-
-abstract class MessageParams {
-    static final int TYPE_SYNTHESIS = 1;
-    static final int TYPE_AUDIO = 2;
-    static final int TYPE_SILENCE = 3;
-
-    private final UtteranceProgressDispatcher mDispatcher;
-    private final Object mCallerIdentity;
-
-    MessageParams(UtteranceProgressDispatcher dispatcher, Object callerIdentity) {
-        mDispatcher = dispatcher;
-        mCallerIdentity = callerIdentity;
-    }
-
-    UtteranceProgressDispatcher getDispatcher() {
-        return mDispatcher;
-    }
-
-    Object getCallerIdentity() {
-        return mCallerIdentity;
-    }
-
-    @Override
-    public String toString() {
-        return "MessageParams[" + hashCode() + "]";
-    }
-
-    abstract int getType();
-}
diff --git a/core/java/android/speech/tts/TextToSpeechService.java b/core/java/android/speech/tts/TextToSpeechService.java
index ba8485a..4c1a0af 100644
--- a/core/java/android/speech/tts/TextToSpeechService.java
+++ b/core/java/android/speech/tts/TextToSpeechService.java
@@ -694,12 +694,12 @@
     }
 
     private class AudioSpeechItem extends SpeechItem {
-        private final BlockingMediaPlayer mPlayer;
-
+        private final AudioPlaybackQueueItem mItem;
         public AudioSpeechItem(Object callerIdentity, int callerUid, int callerPid,
                 Bundle params, Uri uri) {
             super(callerIdentity, callerUid, callerPid, params);
-            mPlayer = new BlockingMediaPlayer(TextToSpeechService.this, uri, getStreamType());
+            mItem = new AudioPlaybackQueueItem(this, getCallerIdentity(),
+                    TextToSpeechService.this, uri, getStreamType());
         }
 
         @Override
@@ -709,8 +709,7 @@
 
         @Override
         protected int playImpl() {
-            mAudioPlaybackHandler.enqueue(new AudioPlaybackQueueItem(
-                    this, getCallerIdentity(), mPlayer));
+            mAudioPlaybackHandler.enqueue(mItem);
             return TextToSpeech.SUCCESS;
         }
 
diff --git a/core/java/android/text/style/SuggestionSpan.java b/core/java/android/text/style/SuggestionSpan.java
index ed2af10..0f26a34 100644
--- a/core/java/android/text/style/SuggestionSpan.java
+++ b/core/java/android/text/style/SuggestionSpan.java
@@ -92,11 +92,6 @@
     private float mAutoCorrectionUnderlineThickness;
     private int mAutoCorrectionUnderlineColor;
 
-    /*
-     * TODO: If switching IME is required, needs to add parameters for ids of InputMethodInfo
-     * and InputMethodSubtype.
-     */
-
     /**
      * @param context Context for the application
      * @param suggestions Suggestions for the string under the span
@@ -146,6 +141,16 @@
     }
 
     private void initStyle(Context context) {
+        if (context == null) {
+            mMisspelledUnderlineThickness = 0;
+            mEasyCorrectUnderlineThickness = 0;
+            mAutoCorrectionUnderlineThickness = 0;
+            mMisspelledUnderlineColor = Color.BLACK;
+            mEasyCorrectUnderlineColor = Color.BLACK;
+            mAutoCorrectionUnderlineColor = Color.BLACK;
+            return;
+        }
+
         int defStyle = com.android.internal.R.attr.textAppearanceMisspelledSuggestion;
         TypedArray typedArray = context.obtainStyledAttributes(
                 null, com.android.internal.R.styleable.SuggestionSpan, defStyle, 0);
@@ -169,7 +174,6 @@
                 com.android.internal.R.styleable.SuggestionSpan_textUnderlineThickness, 0);
         mAutoCorrectionUnderlineColor = typedArray.getColor(
                 com.android.internal.R.styleable.SuggestionSpan_textUnderlineColor, Color.BLACK);
-
     }
 
     public SuggestionSpan(Parcel src) {
diff --git a/core/java/android/view/Choreographer.java b/core/java/android/view/Choreographer.java
new file mode 100644
index 0000000..63de128
--- /dev/null
+++ b/core/java/android/view/Choreographer.java
@@ -0,0 +1,382 @@
+/*
+ * 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 android.view;
+
+import com.android.internal.util.ArrayUtils;
+
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.os.SystemClock;
+import android.os.SystemProperties;
+import android.util.Log;
+
+/**
+ * Coodinates animations and drawing for UI on a particular thread.
+ * @hide
+ */
+public final class Choreographer extends Handler {
+    private static final String TAG = "Choreographer";
+    private static final boolean DEBUG = false;
+
+    // The default amount of time in ms between animation frames.
+    // When vsync is not enabled, we want to have some idea of how long we should
+    // wait before posting the next animation message.  It is important that the
+    // default value be less than the true inter-frame delay on all devices to avoid
+    // situations where we might skip frames by waiting too long (we must compensate
+    // for jitter and hardware variations).  Regardless of this value, the animation
+    // and display loop is ultimately rate-limited by how fast new graphics buffers can
+    // be dequeued.
+    private static final long DEFAULT_FRAME_DELAY = 10;
+
+    // The number of milliseconds between animation frames.
+    private static long sFrameDelay = DEFAULT_FRAME_DELAY;
+
+    // Thread local storage for the choreographer.
+    private static final ThreadLocal<Choreographer> sThreadInstance =
+            new ThreadLocal<Choreographer>() {
+        @Override
+        protected Choreographer initialValue() {
+            Looper looper = Looper.myLooper();
+            if (looper == null) {
+                throw new IllegalStateException("The current thread must have a looper!");
+            }
+            return new Choreographer(looper);
+        }
+    };
+
+    // System property to enable/disable vsync for animations and drawing.
+    // Enabled by default.
+    private static final boolean USE_VSYNC = SystemProperties.getBoolean(
+            "debug.choreographer.vsync", true);
+
+    // System property to enable/disable the use of the vsync / animation timer
+    // for drawing rather than drawing immediately.
+    // 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", false);
+
+    private static final int MSG_DO_ANIMATION = 0;
+    private static final int MSG_DO_DRAW = 1;
+
+    private final Looper mLooper;
+
+    private OnAnimateListener[] mOnAnimateListeners;
+    private OnDrawListener[] mOnDrawListeners;
+
+    private boolean mAnimationScheduled;
+    private boolean mDrawScheduled;
+    private FrameDisplayEventReceiver mFrameDisplayEventReceiver;
+    private long mLastAnimationTime;
+    private long mLastDrawTime;
+
+    private Choreographer(Looper looper) {
+        super(looper);
+        mLooper = looper;
+        mLastAnimationTime = Long.MIN_VALUE;
+        mLastDrawTime = Long.MIN_VALUE;
+    }
+
+    /**
+     * Gets the choreographer for this thread.
+     * Must be called on the UI thread.
+     *
+     * @return The choreographer for this thread.
+     * @throws IllegalStateException if the thread does not have a looper.
+     */
+    public static Choreographer getInstance() {
+        return sThreadInstance.get();
+    }
+
+    /**
+     * The amount of time, in milliseconds, between each frame of the animation. This is a
+     * requested time that the animation will attempt to honor, but the actual delay between
+     * frames may be different, depending on system load and capabilities. This is a static
+     * function because the same delay will be applied to all animations, since they are all
+     * run off of a single timing loop.
+     *
+     * The frame delay may be ignored when the animation system uses an external timing
+     * source, such as the display refresh rate (vsync), to govern animations.
+     *
+     * @return the requested time between frames, in milliseconds
+     */
+    public static long getFrameDelay() {
+        return sFrameDelay;
+    }
+
+    /**
+     * The amount of time, in milliseconds, between each frame of the animation. This is a
+     * requested time that the animation will attempt to honor, but the actual delay between
+     * frames may be different, depending on system load and capabilities. This is a static
+     * function because the same delay will be applied to all animations, since they are all
+     * run off of a single timing loop.
+     *
+     * The frame delay may be ignored when the animation system uses an external timing
+     * source, such as the display refresh rate (vsync), to govern animations.
+     *
+     * @param frameDelay the requested time between frames, in milliseconds
+     */
+    public static void setFrameDelay(long frameDelay) {
+        sFrameDelay = frameDelay;
+    }
+
+    /**
+     * Schedules animation (and drawing) to occur on the next frame synchronization boundary.
+     * Must be called on the UI thread.
+     */
+    public void scheduleAnimation() {
+        if (!mAnimationScheduled) {
+            mAnimationScheduled = true;
+            if (USE_VSYNC) {
+                if (DEBUG) {
+                    Log.d(TAG, "Scheduling vsync for animation.");
+                }
+                if (mFrameDisplayEventReceiver == null) {
+                    mFrameDisplayEventReceiver = new FrameDisplayEventReceiver(mLooper);
+                }
+                mFrameDisplayEventReceiver.scheduleVsync();
+            } else {
+                final long now = SystemClock.uptimeMillis();
+                final long nextAnimationTime = Math.max(mLastAnimationTime + sFrameDelay, now);
+                if (DEBUG) {
+                    Log.d(TAG, "Scheduling animation in " + (nextAnimationTime - now) + " ms.");
+                }
+                sendEmptyMessageAtTime(MSG_DO_ANIMATION, nextAnimationTime);
+            }
+        }
+    }
+
+    /**
+     * Schedules drawing to occur on the next frame synchronization boundary.
+     * Must be called on the UI thread.
+     */
+    public void scheduleDraw() {
+        if (!mDrawScheduled) {
+            mDrawScheduled = true;
+            if (USE_ANIMATION_TIMER_FOR_DRAW) {
+                scheduleAnimation();
+            } else {
+                if (DEBUG) {
+                    Log.d(TAG, "Scheduling draw immediately.");
+                }
+                sendEmptyMessage(MSG_DO_DRAW);
+            }
+        }
+    }
+
+    @Override
+    public void handleMessage(Message msg) {
+        switch (msg.what) {
+            case MSG_DO_ANIMATION:
+                doAnimation();
+                break;
+            case MSG_DO_DRAW:
+                doDraw();
+                break;
+        }
+    }
+
+    private void doAnimation() {
+        if (mAnimationScheduled) {
+            mAnimationScheduled = false;
+
+            final long start = SystemClock.uptimeMillis();
+            if (DEBUG) {
+                Log.d(TAG, "Performing animation: " + Math.max(0, start - mLastAnimationTime)
+                        + " ms have elapsed since previous animation.");
+            }
+            mLastAnimationTime = start;
+
+            final OnAnimateListener[] listeners = mOnAnimateListeners;
+            if (listeners != null) {
+                for (int i = 0; i < listeners.length; i++) {
+                    listeners[i].onAnimate();
+                }
+            }
+
+            if (DEBUG) {
+                Log.d(TAG, "Animation took " + (SystemClock.uptimeMillis() - start) + " ms.");
+            }
+        }
+
+        if (USE_ANIMATION_TIMER_FOR_DRAW) {
+            doDraw();
+        }
+    }
+
+    private void doDraw() {
+        if (mDrawScheduled) {
+            mDrawScheduled = false;
+
+            final long start = SystemClock.uptimeMillis();
+            if (DEBUG) {
+                Log.d(TAG, "Performing draw: " + Math.max(0, start - mLastDrawTime)
+                        + " ms have elapsed since previous draw.");
+            }
+            mLastDrawTime = start;
+
+            final OnDrawListener[] listeners = mOnDrawListeners;
+            if (listeners != null) {
+                for (int i = 0; i < listeners.length; i++) {
+                    listeners[i].onDraw();
+                }
+            }
+
+            if (DEBUG) {
+                Log.d(TAG, "Draw took " + (SystemClock.uptimeMillis() - start) + " ms.");
+            }
+        }
+    }
+
+    /**
+     * Adds an animation listener.
+     * Must be called on the UI thread.
+     *
+     * @param listener The listener to add.
+     */
+    public void addOnAnimateListener(OnAnimateListener listener) {
+        if (listener == null) {
+            throw new IllegalArgumentException("listener must not be null");
+        }
+
+        if (DEBUG) {
+            Log.d(TAG, "Adding onAnimate listener: " + listener);
+        }
+
+        mOnAnimateListeners = ArrayUtils.appendElement(OnAnimateListener.class,
+                mOnAnimateListeners, listener);
+    }
+
+    /**
+     * Removes an animation listener.
+     * Must be called on the UI thread.
+     *
+     * @param listener The listener to remove.
+     */
+    public void removeOnAnimateListener(OnAnimateListener listener) {
+        if (listener == null) {
+            throw new IllegalArgumentException("listener must not be null");
+        }
+
+        if (DEBUG) {
+            Log.d(TAG, "Removing onAnimate listener: " + listener);
+        }
+
+        mOnAnimateListeners = ArrayUtils.removeElement(OnAnimateListener.class,
+                mOnAnimateListeners, listener);
+        stopTimingLoopIfNoListeners();
+    }
+
+    /**
+     * Adds a draw listener.
+     * Must be called on the UI thread.
+     *
+     * @param listener The listener to add.
+     */
+    public void addOnDrawListener(OnDrawListener listener) {
+        if (listener == null) {
+            throw new IllegalArgumentException("listener must not be null");
+        }
+
+        if (DEBUG) {
+            Log.d(TAG, "Adding onDraw listener: " + listener);
+        }
+
+        mOnDrawListeners = ArrayUtils.appendElement(OnDrawListener.class,
+                mOnDrawListeners, listener);
+    }
+
+    /**
+     * Removes a draw listener.
+     * Must be called on the UI thread.
+     *
+     * @param listener The listener to remove.
+     */
+    public void removeOnDrawListener(OnDrawListener listener) {
+        if (listener == null) {
+            throw new IllegalArgumentException("listener must not be null");
+        }
+
+        if (DEBUG) {
+            Log.d(TAG, "Removing onDraw listener: " + listener);
+        }
+
+        mOnDrawListeners = ArrayUtils.removeElement(OnDrawListener.class,
+                mOnDrawListeners, listener);
+        stopTimingLoopIfNoListeners();
+    }
+
+    private void stopTimingLoopIfNoListeners() {
+        if (mOnDrawListeners == null && mOnAnimateListeners == null) {
+            if (DEBUG) {
+                Log.d(TAG, "Stopping timing loop.");
+            }
+
+            if (mAnimationScheduled) {
+                mAnimationScheduled = false;
+                if (!USE_VSYNC) {
+                    removeMessages(MSG_DO_ANIMATION);
+                }
+            }
+
+            if (mDrawScheduled) {
+                mDrawScheduled = false;
+                if (!USE_ANIMATION_TIMER_FOR_DRAW) {
+                    removeMessages(MSG_DO_DRAW);
+                }
+            }
+
+            if (mFrameDisplayEventReceiver != null) {
+                mFrameDisplayEventReceiver.dispose();
+                mFrameDisplayEventReceiver = null;
+            }
+        }
+    }
+
+    /**
+     * Listens for animation frame timing events.
+     */
+    public static interface OnAnimateListener {
+        /**
+         * Called to animate properties before drawing the frame.
+         */
+        public void onAnimate();
+    }
+
+    /**
+     * Listens for draw frame timing events.
+     */
+    public static interface OnDrawListener {
+        /**
+         * Called to draw the frame.
+         */
+        public void onDraw();
+    }
+
+    private final class FrameDisplayEventReceiver extends DisplayEventReceiver {
+        public FrameDisplayEventReceiver(Looper looper) {
+            super(looper);
+        }
+
+        @Override
+        public void onVsync(long timestampNanos, int frame) {
+            doAnimation();
+        }
+    }
+}
diff --git a/core/java/android/view/DisplayEventReceiver.java b/core/java/android/view/DisplayEventReceiver.java
new file mode 100644
index 0000000..d6711ee
--- /dev/null
+++ b/core/java/android/view/DisplayEventReceiver.java
@@ -0,0 +1,115 @@
+/*
+ * 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 android.view;
+
+import dalvik.system.CloseGuard;
+
+import android.os.Looper;
+import android.os.MessageQueue;
+import android.util.Log;
+
+/**
+ * Provides a low-level mechanism for an application to receive display events
+ * such as vertical sync.
+ * @hide
+ */
+public abstract class DisplayEventReceiver {
+    private static final String TAG = "DisplayEventReceiver";
+
+    private final CloseGuard mCloseGuard = CloseGuard.get();
+
+    private int mReceiverPtr;
+
+    // We keep a reference message queue object here so that it is not
+    // GC'd while the native peer of the receiver is using them.
+    private MessageQueue mMessageQueue;
+
+    private static native int nativeInit(DisplayEventReceiver receiver,
+            MessageQueue messageQueue);
+    private static native void nativeDispose(int receiverPtr);
+    private static native void nativeScheduleVsync(int receiverPtr);
+
+    /**
+     * Creates a display event receiver.
+     *
+     * @param looper The looper to use when invoking callbacks.
+     */
+    public DisplayEventReceiver(Looper looper) {
+        if (looper == null) {
+            throw new IllegalArgumentException("looper must not be null");
+        }
+
+        mMessageQueue = looper.getQueue();
+        mReceiverPtr = nativeInit(this, mMessageQueue);
+
+        mCloseGuard.open("dispose");
+    }
+
+    @Override
+    protected void finalize() throws Throwable {
+        try {
+            dispose();
+        } finally {
+            super.finalize();
+        }
+    }
+
+    /**
+     * Disposes the receiver.
+     */
+    public void dispose() {
+        if (mCloseGuard != null) {
+            mCloseGuard.close();
+        }
+        if (mReceiverPtr != 0) {
+            nativeDispose(mReceiverPtr);
+            mReceiverPtr = 0;
+        }
+        mMessageQueue = null;
+    }
+
+    /**
+     * Called when a vertical sync pulse is received.
+     * The recipient should render a frame and then call {@link #scheduleVsync}
+     * to schedule the next vertical sync pulse.
+     *
+     * @param timestampNanos The timestamp of the pulse, in the {@link System#nanoTime()}
+     * timebase.
+     * @param frame The frame number.  Increases by one for each vertical sync interval.
+     */
+    public void onVsync(long timestampNanos, int frame) {
+    }
+
+    /**
+     * Schedules a single vertical sync pulse to be delivered when the next
+     * display frame begins.
+     */
+    public void scheduleVsync() {
+        if (mReceiverPtr == 0) {
+            Log.w(TAG, "Attempted to schedule a vertical sync pulse but the display event "
+                    + "receiver has already been disposed.");
+        } else {
+            nativeScheduleVsync(mReceiverPtr);
+        }
+    }
+
+    // Called from native code.
+    @SuppressWarnings("unused")
+    private void dispatchVsync(long timestampNanos, int frame) {
+        onVsync(timestampNanos, frame);
+    }
+}
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/HardwareRenderer.java b/core/java/android/view/HardwareRenderer.java
index 443acf6..3f793bb 100644
--- a/core/java/android/view/HardwareRenderer.java
+++ b/core/java/android/view/HardwareRenderer.java
@@ -441,6 +441,8 @@
         }
 
         boolean mDirtyRegionsEnabled;
+        boolean mUpdateDirtyRegions;
+
         final boolean mVsyncDisabled;
 
         final int mGlVersion;
@@ -675,6 +677,12 @@
             
             initCaches();
 
+            enableDirtyRegions();
+
+            return mEglContext.getGL();
+        }
+
+        private void enableDirtyRegions() {
             // If mDirtyRegions is set, this means we have an EGL configuration
             // with EGL_SWAP_BEHAVIOR_PRESERVED_BIT set
             if (sDirtyRegions) {
@@ -690,8 +698,6 @@
                 // configuration (see RENDER_DIRTY_REGIONS)
                 mDirtyRegionsEnabled = GLES20Canvas.isBackBufferPreserved();
             }
-
-            return mEglContext.getGL();
         }
 
         abstract void initCaches();
@@ -745,6 +751,9 @@
                 if (!createSurface(holder)) {
                     return;
                 }
+
+                mUpdateDirtyRegions = true;
+
                 if (mCanvas != null) {
                     setEnabled(true);
                 }
@@ -943,6 +952,10 @@
                     fallback(true);
                     return SURFACE_STATE_ERROR;
                 } else {
+                    if (mUpdateDirtyRegions) {
+                        enableDirtyRegions();
+                        mUpdateDirtyRegions = false;
+                    }
                     return SURFACE_STATE_UPDATED;
                 }
             }
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 304a9a1..5c93a42 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;
@@ -12208,13 +12220,16 @@
      * @param location an array of two integers in which to hold the coordinates
      */
     public void getLocationInWindow(int[] location) {
-        // When the view is not attached to a window, this method does not make sense
-        if (mAttachInfo == null) return;
-
         if (location == null || location.length < 2) {
             throw new IllegalArgumentException("location must be an array of two integers");
         }
 
+        if (mAttachInfo == null) {
+            // When the view is not attached to a window, this method does not make sense
+            location[0] = location[1] = 0;
+            return;
+        }
+
         float[] position = mAttachInfo.mTmpTransformLocation;
         position[0] = position[1] = 0.0f;
 
diff --git a/core/java/android/view/ViewConfiguration.java b/core/java/android/view/ViewConfiguration.java
index d824e36..b455ad5 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 = 8;
     
     /**
      * 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..1102a47 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -2719,13 +2719,6 @@
             return more;
         }
 
-        float alpha = child.getAlpha();
-        // Bail out early if the view does not need to be drawn
-        if (alpha <= ViewConfiguration.ALPHA_THRESHOLD && (child.mPrivateFlags & ALPHA_SET) == 0 &&
-                !(child instanceof SurfaceView)) {
-            return more;
-        }
-
         if (hardwareAccelerated) {
             // Clear INVALIDATED flag to allow invalidation to occur during rendering, but
             // retain the flag's value temporarily in the mRecreateDisplayList flag
@@ -2779,6 +2772,7 @@
             }
         }
 
+        float alpha = child.getAlpha();
         if (transformToApply != null || alpha < 1.0f || !child.hasIdentityMatrix()) {
             if (transformToApply != null || !childHasIdentityMatrix) {
                 int transX = 0;
@@ -2958,6 +2952,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 +2973,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 95c473c..72966ef4 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -96,7 +96,8 @@
  */
 @SuppressWarnings({"EmptyCatchBlock", "PointlessBooleanExpression"})
 public final class ViewRootImpl extends Handler implements ViewParent,
-        View.AttachInfo.Callbacks, HardwareRenderer.HardwareDrawCallbacks {
+        View.AttachInfo.Callbacks, HardwareRenderer.HardwareDrawCallbacks,
+        Choreographer.OnDrawListener {
     private static final String TAG = "ViewRootImpl";
     private static final boolean DBG = false;
     private static final boolean LOCAL_LOGV = false;
@@ -110,7 +111,6 @@
     private static final boolean DEBUG_IMF = false || LOCAL_LOGV;
     private static final boolean DEBUG_CONFIGURATION = false || LOCAL_LOGV;
     private static final boolean DEBUG_FPS = false;
-    private static final boolean WATCH_POINTER = false;
 
     /**
      * Set this system property to true to force the view hierarchy to render
@@ -201,13 +201,14 @@
     InputQueue.Callback mInputQueueCallback;
     InputQueue mInputQueue;
     FallbackEventHandler mFallbackEventHandler;
+    Choreographer mChoreographer;
     
     final Rect mTempRect; // used in the transaction to not thrash the heap.
     final Rect mVisRect; // used to retrieve visible rect of focused view.
 
     boolean mTraversalScheduled;
     long mLastTraversalFinishedTimeNanos;
-    long mLastDrawDurationNanos;
+    long mLastDrawFinishedTimeNanos;
     boolean mWillDrawSoon;
     boolean mLayoutRequested;
     boolean mFirst;
@@ -225,7 +226,7 @@
     // Input event queue.
     QueuedInputEvent mFirstPendingInputEvent;
     QueuedInputEvent mCurrentInputEvent;
-    boolean mProcessInputEventsPending;
+    boolean mProcessInputEventsScheduled;
 
     boolean mWindowAttributesChanged = false;
     int mWindowAttributesChangesFlag = 0;
@@ -374,6 +375,7 @@
         mFallbackEventHandler = PolicyManager.makeNewFallbackEventHandler(context);
         mProfileRendering = Boolean.parseBoolean(
                 SystemProperties.get(PROPERTY_PROFILE_RENDERING, "false"));
+        mChoreographer = Choreographer.getInstance();
     }
 
     public static void addFirstDrawHandler(Runnable callback) {
@@ -425,6 +427,8 @@
     public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
         synchronized (this) {
             if (mView == null) {
+                mChoreographer.addOnDrawListener(this);
+
                 mView = view;
                 mFallbackEventHandler.setView(view);
                 mWindowAttributes.copyFrom(attrs);
@@ -794,23 +798,19 @@
     public void scheduleTraversals() {
         if (!mTraversalScheduled) {
             mTraversalScheduled = true;
-
-            //noinspection ConstantConditions
-            if (ViewDebug.DEBUG_LATENCY && mLastTraversalFinishedTimeNanos != 0) {
-                final long now = System.nanoTime();
-                Log.d(TAG, "Latency: Scheduled traversal, it has been "
-                        + ((now - mLastTraversalFinishedTimeNanos) * 0.000001f)
-                        + "ms since the last traversal finished.");
-            }
-
-            sendEmptyMessage(DO_TRAVERSAL);
+            mChoreographer.scheduleDraw();
         }
     }
 
     public void unscheduleTraversals() {
+        mTraversalScheduled = false;
+    }
+
+    @Override
+    public void onDraw() {
         if (mTraversalScheduled) {
             mTraversalScheduled = false;
-            removeMessages(DO_TRAVERSAL);
+            doTraversal();
         }
     }
 
@@ -847,12 +847,45 @@
         }
     }
 
+    private void doTraversal() {
+        doProcessInputEvents();
+
+        if (mProfile) {
+            Debug.startMethodTracing("ViewAncestor");
+        }
+
+        final long traversalStartTime;
+        if (ViewDebug.DEBUG_LATENCY) {
+            traversalStartTime = System.nanoTime();
+            if (mLastTraversalFinishedTimeNanos != 0) {
+                Log.d(ViewDebug.DEBUG_LATENCY_TAG, "Starting performTraversals(); it has been "
+                        + ((traversalStartTime - mLastTraversalFinishedTimeNanos) * 0.000001f)
+                        + "ms since the last traversals finished.");
+            } else {
+                Log.d(ViewDebug.DEBUG_LATENCY_TAG, "Starting performTraversals().");
+            }
+        }
+
+        performTraversals();
+
+        if (ViewDebug.DEBUG_LATENCY) {
+            long now = System.nanoTime();
+            Log.d(ViewDebug.DEBUG_LATENCY_TAG, "performTraversals() took "
+                    + ((now - traversalStartTime) * 0.000001f)
+                    + "ms.");
+            mLastTraversalFinishedTimeNanos = now;
+        }
+
+        if (mProfile) {
+            Debug.stopMethodTracing();
+            mProfile = false;
+        }
+    }
+
     private void performTraversals() {
         // cache mView since it is used so much below...
         final View host = mView;
 
-        processInputEvents();
-
         if (DBG) {
             System.out.println("======================================");
             System.out.println("performTraversals");
@@ -862,10 +895,8 @@
         if (host == null || !mAdded)
             return;
 
-        mTraversalScheduled = false;
         mWillDrawSoon = true;
         boolean windowSizeMayChange = false;
-        boolean fullRedrawNeeded = mFullRedrawNeeded;
         boolean newSurface = false;
         boolean surfaceChanged = false;
         WindowManager.LayoutParams lp = mWindowAttributes;
@@ -890,7 +921,7 @@
         CompatibilityInfo compatibilityInfo = mCompatibilityInfo.get();
         if (compatibilityInfo.supportsScreen() == mLastInCompatMode) {
             params = lp;
-            fullRedrawNeeded = true;
+            mFullRedrawNeeded = true;
             mLayoutRequested = true;
             if (mLastInCompatMode) {
                 params.flags &= ~WindowManager.LayoutParams.FLAG_COMPATIBLE_WINDOW;
@@ -905,7 +936,7 @@
         
         Rect frame = mWinFrame;
         if (mFirst) {
-            fullRedrawNeeded = true;
+            mFullRedrawNeeded = true;
             mLayoutRequested = true;
 
             if (lp.type == WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL) {
@@ -949,7 +980,7 @@
             if (desiredWindowWidth != mWidth || desiredWindowHeight != mHeight) {
                 if (DEBUG_ORIENTATION) Log.v(TAG,
                         "View " + host + " resized to: " + frame);
-                fullRedrawNeeded = true;
+                mFullRedrawNeeded = true;
                 mLayoutRequested = true;
                 windowSizeMayChange = true;
             }
@@ -1287,7 +1318,7 @@
                         // before actually drawing them, so it can display then
                         // all at once.
                         newSurface = true;
-                        fullRedrawNeeded = true;
+                        mFullRedrawNeeded = true;
                         mPreviousTransparentRegion.setEmpty();
 
                         if (mAttachInfo.mHardwareRenderer != null) {
@@ -1323,7 +1354,7 @@
                     }
                 } else if (surfaceGenerationId != mSurface.getGenerationId() &&
                         mSurfaceHolder == null && mAttachInfo.mHardwareRenderer != null) {
-                    fullRedrawNeeded = true;
+                    mFullRedrawNeeded = true;
                     try {
                         mAttachInfo.mHardwareRenderer.updateSurface(mHolder);
                     } catch (Surface.OutOfResourcesException e) {
@@ -1609,6 +1640,11 @@
             }
         }
 
+        // Remember if we must report the next draw.
+        if ((relayoutResult & WindowManagerImpl.RELAYOUT_RES_FIRST_TIME) != 0) {
+            mReportNextDraw = true;
+        }
+
         boolean cancelDraw = attachInfo.mTreeObserver.dispatchOnPreDraw() ||
                 viewVisibility != View.VISIBLE;
 
@@ -1619,42 +1655,8 @@
                 }
                 mPendingTransitions.clear();
             }
-            mFullRedrawNeeded = false;
 
-            final long drawStartTime;
-            if (ViewDebug.DEBUG_LATENCY) {
-                drawStartTime = System.nanoTime();
-            }
-
-            draw(fullRedrawNeeded);
-
-            if (ViewDebug.DEBUG_LATENCY) {
-                mLastDrawDurationNanos = System.nanoTime() - drawStartTime;
-            }
-
-            if ((relayoutResult&WindowManagerImpl.RELAYOUT_RES_FIRST_TIME) != 0
-                    || mReportNextDraw) {
-                if (LOCAL_LOGV) {
-                    Log.v(TAG, "FINISHED DRAWING: " + mWindowAttributes.getTitle());
-                }
-                mReportNextDraw = false;
-                if (mSurfaceHolder != null && mSurface.isValid()) {
-                    mSurfaceHolderCallback.surfaceRedrawNeeded(mSurfaceHolder);
-                    SurfaceHolder.Callback callbacks[] = mSurfaceHolder.getCallbacks();
-                    if (callbacks != null) {
-                        for (SurfaceHolder.Callback c : callbacks) {
-                            if (c instanceof SurfaceHolder.Callback2) {
-                                ((SurfaceHolder.Callback2)c).surfaceRedrawNeeded(
-                                        mSurfaceHolder);
-                            }
-                        }
-                    }
-                }
-                try {
-                    sWindowSession.finishDrawing(mWindow);
-                } catch (RemoteException e) {
-                }
-            }
+            performDraw();
         } else {
             // End any pending transitions on this non-visible window
             if (mPendingTransitions != null && mPendingTransitions.size() > 0) {
@@ -1663,14 +1665,6 @@
                 }
                 mPendingTransitions.clear();
             }
-            // We were supposed to report when we are done drawing. Since we canceled the
-            // draw, remember it here.
-            if ((relayoutResult&WindowManagerImpl.RELAYOUT_RES_FIRST_TIME) != 0) {
-                mReportNextDraw = true;
-            }
-            if (fullRedrawNeeded) {
-                mFullRedrawNeeded = true;
-            }
 
             if (viewVisibility == View.VISIBLE) {
                 // Try again
@@ -1814,6 +1808,56 @@
         }
     }
 
+    private void performDraw() {
+        final long drawStartTime;
+        if (ViewDebug.DEBUG_LATENCY) {
+            drawStartTime = System.nanoTime();
+            if (mLastDrawFinishedTimeNanos != 0) {
+                Log.d(ViewDebug.DEBUG_LATENCY_TAG, "Starting draw(); it has been "
+                        + ((drawStartTime - mLastDrawFinishedTimeNanos) * 0.000001f)
+                        + "ms since the last draw finished.");
+            } else {
+                Log.d(ViewDebug.DEBUG_LATENCY_TAG, "Starting draw().");
+            }
+        }
+
+        final boolean fullRedrawNeeded = mFullRedrawNeeded;
+        mFullRedrawNeeded = false;
+        draw(fullRedrawNeeded);
+
+        if (ViewDebug.DEBUG_LATENCY) {
+            long now = System.nanoTime();
+            Log.d(ViewDebug.DEBUG_LATENCY_TAG, "performDraw() took "
+                    + ((now - drawStartTime) * 0.000001f)
+                    + "ms.");
+            mLastDrawFinishedTimeNanos = now;
+        }
+
+        if (mReportNextDraw) {
+            mReportNextDraw = false;
+
+            if (LOCAL_LOGV) {
+                Log.v(TAG, "FINISHED DRAWING: " + mWindowAttributes.getTitle());
+            }
+            if (mSurfaceHolder != null && mSurface.isValid()) {
+                mSurfaceHolderCallback.surfaceRedrawNeeded(mSurfaceHolder);
+                SurfaceHolder.Callback callbacks[] = mSurfaceHolder.getCallbacks();
+                if (callbacks != null) {
+                    for (SurfaceHolder.Callback c : callbacks) {
+                        if (c instanceof SurfaceHolder.Callback2) {
+                            ((SurfaceHolder.Callback2)c).surfaceRedrawNeeded(
+                                    mSurfaceHolder);
+                        }
+                    }
+                }
+            }
+            try {
+                sWindowSession.finishDrawing(mWindow);
+            } catch (RemoteException e) {
+            }
+        }
+    }
+
     private void draw(boolean fullRedrawNeeded) {
         Surface surface = mSurface;
         if (surface == null || !surface.isValid()) {
@@ -1852,8 +1896,9 @@
             mCurScrollY = yoff;
             fullRedrawNeeded = true;
         }
-        float appScale = mAttachInfo.mApplicationScale;
-        boolean scalingRequired = mAttachInfo.mScalingRequired;
+
+        final float appScale = mAttachInfo.mApplicationScale;
+        final boolean scalingRequired = mAttachInfo.mScalingRequired;
 
         int resizeAlpha = 0;
         if (mResizeBuffer != null) {
@@ -1868,7 +1913,7 @@
             }
         }
 
-        Rect dirty = mDirty;
+        final Rect dirty = mDirty;
         if (mSurfaceHolder != null) {
             // The app owns the surface, we won't draw.
             dirty.setEmpty();
@@ -1886,35 +1931,6 @@
             dirty.set(0, 0, (int) (mWidth * appScale + 0.5f), (int) (mHeight * appScale + 0.5f));
         }
 
-        if (mAttachInfo.mHardwareRenderer != null && mAttachInfo.mHardwareRenderer.isEnabled()) {
-            if (!dirty.isEmpty() || mIsAnimating) {
-                mIsAnimating = false;
-                mHardwareYOffset = yoff;
-                mResizeAlpha = resizeAlpha;
-
-                mCurrentDirty.set(dirty);
-                mCurrentDirty.union(mPreviousDirty);
-                mPreviousDirty.set(dirty);
-                dirty.setEmpty();
-
-                Rect currentDirty = mCurrentDirty;
-                if (animating) {
-                    currentDirty = null;
-                }
-
-                if (mAttachInfo.mHardwareRenderer.draw(mView, mAttachInfo, this, currentDirty)) {
-                    mPreviousDirty.set(0, 0, mWidth, mHeight);
-                }
-            }
-
-            if (animating) {
-                mFullRedrawNeeded = true;
-                scheduleTraversals();
-            }
-
-            return;
-        }
-
         if (DEBUG_ORIENTATION || DEBUG_DRAW) {
             Log.v(TAG, "Draw " + mView + "/"
                     + mWindowAttributes.getTitle()
@@ -1925,64 +1941,79 @@
         }
 
         if (!dirty.isEmpty() || mIsAnimating) {
-            Canvas canvas;
-            try {
-                int left = dirty.left;
-                int top = dirty.top;
-                int right = dirty.right;
-                int bottom = dirty.bottom;
+            if (mAttachInfo.mHardwareRenderer != null
+                    && mAttachInfo.mHardwareRenderer.isEnabled()) {
+                // Draw with hardware renderer.
+                mIsAnimating = false;
+                mHardwareYOffset = yoff;
+                mResizeAlpha = resizeAlpha;
 
-                final long lockCanvasStartTime;
-                if (ViewDebug.DEBUG_LATENCY) {
-                    lockCanvasStartTime = System.nanoTime();
+                mCurrentDirty.set(dirty);
+                mCurrentDirty.union(mPreviousDirty);
+                mPreviousDirty.set(dirty);
+                dirty.setEmpty();
+
+                if (mAttachInfo.mHardwareRenderer.draw(mView, mAttachInfo, this,
+                        animating ? null : mCurrentDirty)) {
+                    mPreviousDirty.set(0, 0, mWidth, mHeight);
                 }
-
-                canvas = surface.lockCanvas(dirty);
-
-                if (ViewDebug.DEBUG_LATENCY) {
-                    long now = System.nanoTime();
-                    Log.d(TAG, "Latency: Spent "
-                            + ((now - lockCanvasStartTime) * 0.000001f)
-                            + "ms waiting for surface.lockCanvas()");
-                }
-
-                if (left != dirty.left || top != dirty.top || right != dirty.right ||
-                        bottom != dirty.bottom) {
-                    mAttachInfo.mIgnoreDirtyState = true;
-                }
-
-                // TODO: Do this in native
-                canvas.setDensity(mDensity);
-            } catch (Surface.OutOfResourcesException e) {
-                Log.e(TAG, "OutOfResourcesException locking surface", e);
+            } else {
+                // Draw with software renderer.
+                Canvas canvas;
                 try {
-                    if (!sWindowSession.outOfMemory(mWindow)) {
-                        Slog.w(TAG, "No processes killed for memory; killing self");
-                        Process.killProcess(Process.myPid());
+                    int left = dirty.left;
+                    int top = dirty.top;
+                    int right = dirty.right;
+                    int bottom = dirty.bottom;
+
+                    final long lockCanvasStartTime;
+                    if (ViewDebug.DEBUG_LATENCY) {
+                        lockCanvasStartTime = System.nanoTime();
                     }
-                } catch (RemoteException ex) {
+
+                    canvas = mSurface.lockCanvas(dirty);
+
+                    if (ViewDebug.DEBUG_LATENCY) {
+                        long now = System.nanoTime();
+                        Log.d(ViewDebug.DEBUG_LATENCY_TAG, "- lockCanvas() took "
+                                + ((now - lockCanvasStartTime) * 0.000001f) + "ms");
+                    }
+
+                    if (left != dirty.left || top != dirty.top || right != dirty.right ||
+                            bottom != dirty.bottom) {
+                        mAttachInfo.mIgnoreDirtyState = true;
+                    }
+
+                    // TODO: Do this in native
+                    canvas.setDensity(mDensity);
+                } catch (Surface.OutOfResourcesException e) {
+                    Log.e(TAG, "OutOfResourcesException locking surface", e);
+                    try {
+                        if (!sWindowSession.outOfMemory(mWindow)) {
+                            Slog.w(TAG, "No processes killed for memory; killing self");
+                            Process.killProcess(Process.myPid());
+                        }
+                    } catch (RemoteException ex) {
+                    }
+                    mLayoutRequested = true;    // ask wm for a new surface next time.
+                    return;
+                } catch (IllegalArgumentException e) {
+                    Log.e(TAG, "IllegalArgumentException locking surface", e);
+                    // Don't assume this is due to out of memory, it could be
+                    // something else, and if it is something else then we could
+                    // kill stuff (or ourself) for no reason.
+                    mLayoutRequested = true;    // ask wm for a new surface next time.
+                    return;
                 }
-                mLayoutRequested = true;    // ask wm for a new surface next time.
-                return;
-            } catch (IllegalArgumentException e) {
-                Log.e(TAG, "IllegalArgumentException locking surface", e);
-                // Don't assume this is due to out of memory, it could be
-                // something else, and if it is something else then we could
-                // kill stuff (or ourself) for no reason.
-                mLayoutRequested = true;    // ask wm for a new surface next time.
-                return;
-            }
 
-            try {
-                if (!dirty.isEmpty() || mIsAnimating) {
-                    long startTime = 0L;
-
+                try {
                     if (DEBUG_ORIENTATION || DEBUG_DRAW) {
                         Log.v(TAG, "Surface " + surface + " drawing to bitmap w="
                                 + canvas.getWidth() + ", h=" + canvas.getHeight());
                         //canvas.drawARGB(255, 255, 0, 0);
                     }
 
+                    long startTime = 0L;
                     if (ViewDebug.DEBUG_PROFILE_DRAWING) {
                         startTime = SystemClock.elapsedRealtime();
                     }
@@ -2045,23 +2076,23 @@
                     if (ViewDebug.DEBUG_PROFILE_DRAWING) {
                         EventLog.writeEvent(60000, SystemClock.elapsedRealtime() - startTime);
                     }
-                }
-            } finally {
-                final long unlockCanvasAndPostStartTime;
-                if (ViewDebug.DEBUG_LATENCY) {
-                    unlockCanvasAndPostStartTime = System.nanoTime();
-                }
+                } finally {
+                    final long unlockCanvasAndPostStartTime;
+                    if (ViewDebug.DEBUG_LATENCY) {
+                        unlockCanvasAndPostStartTime = System.nanoTime();
+                    }
 
-                surface.unlockCanvasAndPost(canvas);
+                    surface.unlockCanvasAndPost(canvas);
 
-                if (ViewDebug.DEBUG_LATENCY) {
-                    long now = System.nanoTime();
-                    Log.d(ViewDebug.DEBUG_LATENCY_TAG, "- unlockCanvasAndPost() took "
-                            + ((now - unlockCanvasAndPostStartTime) * 0.000001f) + "ms");
-                }
+                    if (ViewDebug.DEBUG_LATENCY) {
+                        long now = System.nanoTime();
+                        Log.d(ViewDebug.DEBUG_LATENCY_TAG, "- unlockCanvasAndPost() took "
+                                + ((now - unlockCanvasAndPostStartTime) * 0.000001f) + "ms");
+                    }
 
-                if (LOCAL_LOGV) {
-                    Log.v(TAG, "Surface " + surface + " unlockCanvasAndPost");
+                    if (LOCAL_LOGV) {
+                        Log.v(TAG, "Surface " + surface + " unlockCanvasAndPost");
+                    }
                 }
             }
         }
@@ -2297,6 +2328,8 @@
             mInputChannel.dispose();
             mInputChannel = null;
         }
+
+        mChoreographer.removeOnDrawListener(this);
     }
 
     void updateConfiguration(Configuration config, boolean force) {
@@ -2351,14 +2384,11 @@
         }
     }
 
-    public final static int DO_TRAVERSAL = 1000;
     public final static int DIE = 1001;
     public final static int RESIZED = 1002;
     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;
@@ -2380,8 +2410,6 @@
     @Override
     public String getMessageName(Message message) {
         switch (message.what) {
-            case DO_TRAVERSAL:
-                return "DO_TRAVERSAL";
             case DIE:
                 return "DIE";
             case RESIZED:
@@ -2392,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:
@@ -2445,45 +2469,12 @@
             info.target.invalidate(info.left, info.top, info.right, info.bottom);
             info.release();
             break;
-        case DO_TRAVERSAL:
-            if (mProfile) {
-                Debug.startMethodTracing("ViewAncestor");
-            }
-
-            final long traversalStartTime;
-            if (ViewDebug.DEBUG_LATENCY) {
-                traversalStartTime = System.nanoTime();
-                mLastDrawDurationNanos = 0;
-                if (mLastTraversalFinishedTimeNanos != 0) {
-                    Log.d(ViewDebug.DEBUG_LATENCY_TAG, "Starting performTraversals(); it has been "
-                            + ((traversalStartTime - mLastTraversalFinishedTimeNanos) * 0.000001f)
-                            + "ms since the last traversals finished.");
-                } else {
-                    Log.d(ViewDebug.DEBUG_LATENCY_TAG, "Starting performTraversals().");
-                }
-            }
-
-            performTraversals();
-
-            if (ViewDebug.DEBUG_LATENCY) {
-                long now = System.nanoTime();
-                Log.d(ViewDebug.DEBUG_LATENCY_TAG, "performTraversals() took "
-                        + ((now - traversalStartTime) * 0.000001f)
-                        + "ms.");
-                mLastTraversalFinishedTimeNanos = now;
-            }
-
-            if (mProfile) {
-                Debug.stopMethodTracing();
-                mProfile = false;
-            }
-            break;
         case IME_FINISHED_EVENT:
             handleImeFinishedEvent(msg.arg1, msg.arg2 != 0);
             break;
         case DO_PROCESS_INPUT_EVENTS:
-            mProcessInputEventsPending = false;
-            processInputEvents();
+            mProcessInputEventsScheduled = false;
+            doProcessInputEvents();
             break;
         case DISPATCH_APP_VISIBILITY:
             handleAppVisibility(msg.arg1 != 0);
@@ -2594,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 "
@@ -3262,8 +3257,9 @@
         }
 
         // If the Control modifier is held, try to interpret the key as a shortcut.
-        if (event.getAction() == KeyEvent.ACTION_UP
+        if (event.getAction() == KeyEvent.ACTION_DOWN
                 && event.isCtrlPressed()
+                && event.getRepeatCount() == 0
                 && !KeyEvent.isModifierKey(event.getKeyCode())) {
             if (mView.dispatchKeyShortcutEvent(event)) {
                 finishInputEvent(q, true);
@@ -3782,13 +3778,13 @@
     }
 
     private void scheduleProcessInputEvents() {
-        if (!mProcessInputEventsPending) {
-            mProcessInputEventsPending = true;
+        if (!mProcessInputEventsScheduled) {
+            mProcessInputEventsScheduled = true;
             sendEmptyMessage(DO_PROCESS_INPUT_EVENTS);
         }
     }
 
-    void processInputEvents() {
+    private void doProcessInputEvents() {
         while (mCurrentInputEvent == null && mFirstPendingInputEvent != null) {
             QueuedInputEvent q = mFirstPendingInputEvent;
             mFirstPendingInputEvent = q.mNext;
@@ -3799,8 +3795,8 @@
 
         // We are done processing all input events that we can process right now
         // so we can clear the pending flag immediately.
-        if (mProcessInputEventsPending) {
-            mProcessInputEventsPending = false;
+        if (mProcessInputEventsScheduled) {
+            mProcessInputEventsScheduled = false;
             removeMessages(DO_PROCESS_INPUT_EVENTS);
         }
     }
diff --git a/core/java/android/webkit/WebTextView.java b/core/java/android/webkit/WebTextView.java
index f18a396..2b59b80 100644
--- a/core/java/android/webkit/WebTextView.java
+++ b/core/java/android/webkit/WebTextView.java
@@ -19,10 +19,13 @@
 import android.content.Context;
 import android.graphics.Canvas;
 import android.graphics.Color;
+import android.graphics.ColorFilter;
 import android.graphics.Paint;
 import android.graphics.Paint.Style;
+import android.graphics.PixelFormat;
 import android.graphics.Rect;
 import android.graphics.drawable.ColorDrawable;
+import android.graphics.drawable.Drawable;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.Message;
@@ -51,7 +54,6 @@
 import android.view.inputmethod.EditorInfo;
 import android.view.inputmethod.InputConnection;
 import android.view.inputmethod.InputMethodManager;
-import android.widget.AbsoluteLayout;
 import android.widget.AbsoluteLayout.LayoutParams;
 import android.widget.AdapterView;
 import android.widget.ArrayAdapter;
@@ -74,7 +76,6 @@
 
     static final String LOGTAG = "webtextview";
 
-    private Paint mRingPaint;
     private int mRingInset;
 
     private WebView         mWebView;
@@ -207,13 +208,51 @@
                 }
             }
         };
-        float ringWidth = 4f * context.getResources().getDisplayMetrics().density;
         mReceiver = new MyResultReceiver(mHandler);
-        mRingPaint = new Paint();
-        mRingPaint.setColor(0x6633b5e5);
-        mRingPaint.setStrokeWidth(ringWidth);
-        mRingPaint.setStyle(Style.FILL);
+        float ringWidth = 2f * context.getResources().getDisplayMetrics().density;
         mRingInset = (int) ringWidth;
+        setBackgroundDrawable(new BackgroundDrawable(mRingInset));
+        setPadding(getPaddingLeft(), getPaddingTop(), getPaddingRight(),
+                getPaddingBottom());
+    }
+
+    private static class BackgroundDrawable extends Drawable {
+
+        private Paint mPaint = new Paint();
+        private int mBorderWidth;
+        private Rect mInsetRect = new Rect();
+
+        public BackgroundDrawable(int width) {
+            mPaint = new Paint();
+            mPaint.setStrokeWidth(width);
+            mBorderWidth = width;
+        }
+
+        @Override
+        public void draw(Canvas canvas) {
+            mPaint.setColor(0x6633b5e5);
+            canvas.drawRect(getBounds(), mPaint);
+            mInsetRect.left = getBounds().left + mBorderWidth;
+            mInsetRect.top = getBounds().top + mBorderWidth;
+            mInsetRect.right = getBounds().right - mBorderWidth;
+            mInsetRect.bottom = getBounds().bottom - mBorderWidth;
+            mPaint.setColor(Color.WHITE);
+            canvas.drawRect(mInsetRect, mPaint);
+        }
+
+        @Override
+        public void setAlpha(int alpha) {
+        }
+
+        @Override
+        public void setColorFilter(ColorFilter cf) {
+        }
+
+        @Override
+        public int getOpacity() {
+            return PixelFormat.TRANSLUCENT;
+        }
+
     }
 
     public void setAutoFillable(int queryId) {
@@ -223,37 +262,9 @@
     }
 
     @Override
-    protected void onDraw(Canvas canvas) {
-        super.onDraw(canvas);
-        if (isFocused()) {
-            final int ib = getHeight() - mRingInset;
-            canvas.drawRect(0, 0, getWidth(), mRingInset, mRingPaint);
-            canvas.drawRect(0, ib, getWidth(), getHeight(), mRingPaint);
-            canvas.drawRect(0, mRingInset, mRingInset, ib, mRingPaint);
-            canvas.drawRect(getWidth() - mRingInset, mRingInset, getWidth(), ib, mRingPaint);
-        }
-    }
-
-    private void growOrShrink(boolean grow) {
-        AbsoluteLayout.LayoutParams lp = (AbsoluteLayout.LayoutParams) getLayoutParams();
-        if (grow) {
-            Log.i("webtextview", "grow");
-            lp.x -= mRingInset;
-            lp.y -= mRingInset;
-            lp.width += 2 * mRingInset;
-            lp.height += 2 * mRingInset;
-            setPadding(getPaddingLeft() + mRingInset, getPaddingTop() + mRingInset,
-                    getPaddingRight() + mRingInset, getPaddingBottom() + mRingInset);
-        } else {
-            Log.i("webtextview", "shrink");
-            lp.x += mRingInset;
-            lp.y += mRingInset;
-            lp.width -= 2 * mRingInset;
-            lp.height -= 2 * mRingInset;
-            setPadding(getPaddingLeft() - mRingInset, getPaddingTop() - mRingInset,
-                    getPaddingRight() - mRingInset, getPaddingBottom() - mRingInset);
-        }
-        setLayoutParams(lp);
+    public void setPadding(int left, int top, int right, int bottom) {
+        super.setPadding(left + mRingInset, top + mRingInset,
+                right + mRingInset, bottom + mRingInset);
     }
 
     @Override
@@ -557,7 +568,6 @@
         } else if (!mInsideRemove) {
             mWebView.setActive(false);
         }
-        growOrShrink(focused);
         mFromFocusChange = false;
     }
 
@@ -968,6 +978,10 @@
      */
     /* package */ void setRect(int x, int y, int width, int height) {
         LayoutParams lp = (LayoutParams) getLayoutParams();
+        x -= mRingInset;
+        y -= mRingInset;
+        width += 2 * mRingInset;
+        height += 2 * mRingInset;
         boolean needsUpdate = false;
         if (null == lp) {
             lp = new LayoutParams(width, height, x, y);
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 4958d3c..a284a17 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -59,6 +59,7 @@
 import android.os.StrictMode;
 import android.provider.Settings;
 import android.speech.tts.TextToSpeech;
+import android.text.TextUtils;
 import android.util.AttributeSet;
 import android.util.EventLog;
 import android.util.Log;
@@ -849,13 +850,12 @@
     // the alias via which accessibility JavaScript interface is exposed
     private static final String ALIAS_ACCESSIBILITY_JS_INTERFACE = "accessibility";
 
-    // JavaScript to inject the script chooser which will
-    // pick the right script for the current URL
-    private static final String ACCESSIBILITY_SCRIPT_CHOOSER_JAVASCRIPT =
+    // Template for JavaScript that injects a screen-reader.
+    private static final String ACCESSIBILITY_SCREEN_READER_JAVASCRIPT_TEMPLATE =
         "javascript:(function() {" +
         "    var chooser = document.createElement('script');" +
         "    chooser.type = 'text/javascript';" +
-        "    chooser.src = 'https://ssl.gstatic.com/accessibility/javascript/android/AndroidScriptChooser.user.js';" +
+        "    chooser.src = '%1s';" +
         "    document.getElementsByTagName('head')[0].appendChild(chooser);" +
         "  })();";
 
@@ -2496,11 +2496,12 @@
     }
 
     /**
-     * Return the reading level scale of the WebView
+     * Compute the reading level scale of the WebView
+     * @param scale The current scale.
      * @return The reading level scale.
      */
-    /*package*/ float getReadingLevelScale() {
-        return mZoomManager.getReadingLevelScale();
+    /*package*/ float computeReadingLevelScale(float scale) {
+        return mZoomManager.computeReadingLevelScale(scale);
     }
 
     /**
@@ -3818,7 +3819,7 @@
             if (onDeviceScriptInjectionEnabled) {
                 ensureAccessibilityScriptInjectorInstance(false);
                 // neither script injected nor script injection opted out => we inject
-                loadUrl(ACCESSIBILITY_SCRIPT_CHOOSER_JAVASCRIPT);
+                loadUrl(getScreenReaderInjectingJs());
                 // TODO: Set this flag after successfull script injection. Maybe upon injection
                 // the chooser should update the meta tag and we check it to declare success
                 mAccessibilityScriptInjected = true;
@@ -3832,7 +3833,7 @@
         } else if (axsParameterValue == ACCESSIBILITY_SCRIPT_INJECTION_PROVIDED) {
             ensureAccessibilityScriptInjectorInstance(false);
             // the URL provides accessibility but we still need to add our generic script
-            loadUrl(ACCESSIBILITY_SCRIPT_CHOOSER_JAVASCRIPT);
+            loadUrl(getScreenReaderInjectingJs());
         } else {
             Log.e(LOGTAG, "Unknown URL value for the \"axs\" URL parameter: " + axsParameterValue);
         }
@@ -3854,6 +3855,17 @@
     }
 
     /**
+     * Gets JavaScript that injects a screen-reader.
+     *
+     * @return The JavaScript snippet.
+     */
+    private String getScreenReaderInjectingJs() {
+        String screenReaderUrl = Settings.Secure.getString(mContext.getContentResolver(),
+                Settings.Secure.ACCESSIBILITY_SCREEN_READER_URL);
+        return String.format(ACCESSIBILITY_SCREEN_READER_JAVASCRIPT_TEMPLATE, screenReaderUrl);
+    }
+
+    /**
      * Gets the "axs" URL parameter value.
      *
      * @param url A url to fetch the paramter from.
@@ -4250,6 +4262,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 +5848,8 @@
         }
         calcOurContentVisibleRectF(mVisibleContentRect);
         nativeUpdateDrawGLFunction(mGLViewportEmpty ? null : mGLRectViewport,
-                mGLViewportEmpty ? null : mViewRectViewport, mVisibleContentRect);
+                mGLViewportEmpty ? null : mViewRectViewport,
+                mVisibleContentRect);
     }
 
     /**
@@ -5980,6 +5996,7 @@
         if (inFullScreenMode()) {
             mFullScreenHolder.hide();
             mFullScreenHolder = null;
+            invalidate();
         }
     }
 
@@ -8655,6 +8672,7 @@
                     mFullScreenHolder = new PluginFullScreenHolder(WebView.this, orientation, npp);
                     mFullScreenHolder.setContentView(view);
                     mFullScreenHolder.show();
+                    invalidate();
 
                     break;
                 }
diff --git a/core/java/android/webkit/WebViewCore.java b/core/java/android/webkit/WebViewCore.java
index 0f749bc..14da23e 100644
--- a/core/java/android/webkit/WebViewCore.java
+++ b/core/java/android/webkit/WebViewCore.java
@@ -2514,7 +2514,7 @@
                     if (mSettings.isNarrowColumnLayout()) {
                         // In case of automatic text reflow in fixed view port mode.
                         mInitialViewState.mTextWrapScale =
-                                mWebView.getReadingLevelScale();
+                                mWebView.computeReadingLevelScale(data.mScale);
                     }
                 } else {
                     // Scale is given such as when page is restored, use it.
diff --git a/core/java/android/webkit/ZoomManager.java b/core/java/android/webkit/ZoomManager.java
index 14bdc42..8ffba64 100644
--- a/core/java/android/webkit/ZoomManager.java
+++ b/core/java/android/webkit/ZoomManager.java
@@ -316,7 +316,12 @@
      * Returns the zoom scale used for reading text on a double-tap.
      */
     public final float getReadingLevelScale() {
-        return mDisplayDensity * mDoubleTapZoomFactor;
+        return computeScaleWithLimits(computeReadingLevelScale(getZoomOverviewScale()));
+    }
+
+    /* package */ final float computeReadingLevelScale(float scale) {
+        return Math.max(mDisplayDensity * mDoubleTapZoomFactor,
+                scale + MIN_DOUBLE_TAP_SCALE_INCREMENT);
     }
 
     public final float getInvDefaultScale() {
@@ -678,7 +683,7 @@
             }
             zoomToOverview();
         } else {
-            zoomToReadingLevelOrMore();
+            zoomToReadingLevel();
         }
     }
 
@@ -709,9 +714,8 @@
             !mWebView.getSettings().getUseFixedViewport());
     }
 
-    private void zoomToReadingLevelOrMore() {
-        final float zoomScale = Math.max(getReadingLevelScale(),
-                mActualScale + MIN_DOUBLE_TAP_SCALE_INCREMENT);
+    private void zoomToReadingLevel() {
+        final float readingScale = getReadingLevelScale();
 
         int left = mWebView.nativeGetBlockLeftEdge(mAnchorX, mAnchorY, mActualScale);
         if (left != WebView.NO_LEFTEDGE) {
@@ -721,13 +725,13 @@
             // Re-calculate the zoom center so that the new scroll x will be
             // on the left edge.
             if (viewLeft > 0) {
-                mZoomCenterX = viewLeft * zoomScale / (zoomScale - mActualScale);
+                mZoomCenterX = viewLeft * readingScale / (readingScale - mActualScale);
             } else {
                 mWebView.scrollBy(viewLeft, 0);
                 mZoomCenterX = 0;
             }
         }
-        startZoomAnimation(zoomScale,
+        startZoomAnimation(readingScale,
             !mWebView.getSettings().getUseFixedViewport());
     }
 
diff --git a/core/java/android/widget/RemoteViewsService.java b/core/java/android/widget/RemoteViewsService.java
index 7ba4777..07bd918 100644
--- a/core/java/android/widget/RemoteViewsService.java
+++ b/core/java/android/widget/RemoteViewsService.java
@@ -145,6 +145,9 @@
                 Thread.getDefaultUncaughtExceptionHandler().uncaughtException(t, ex);
             }
         }
+        public synchronized void onDataSetChangedAsync() {
+            onDataSetChanged();
+        }
         public synchronized int getCount() {
             int count = 0;
             try {
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..db9629a 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;
@@ -9828,7 +9835,7 @@
                 highlightTextDifferences(mSuggestionInfos[i], spanUnionStart, spanUnionEnd);
             }
 
-            // Add to dictionary item is there a span with the misspelled flag
+            // Add to dictionary item if there is a span with the misspelled flag
             if (misspelledSpan != null) {
                 final int misspelledStart = spannable.getSpanStart(misspelledSpan);
                 final int misspelledEnd = spannable.getSpanEnd(misspelledSpan);
@@ -9914,7 +9921,7 @@
 
             final int spanStart = editable.getSpanStart(suggestionInfo.suggestionSpan);
             final int spanEnd = editable.getSpanEnd(suggestionInfo.suggestionSpan);
-            if (spanStart < 0 || spanEnd < 0) {
+            if (spanStart < 0 || spanEnd <= spanStart) {
                 // Span has been removed
                 hide();
                 return;
@@ -9924,6 +9931,7 @@
             if (suggestionInfo.suggestionIndex == ADD_TO_DICTIONARY) {
                 Intent intent = new Intent(Settings.ACTION_USER_DICTIONARY_INSERT);
                 intent.putExtra("word", originalText);
+                intent.putExtra("locale", getTextServicesLocale().toString());
                 intent.setFlags(intent.getFlags() | Intent.FLAG_ACTIVITY_NEW_TASK);
                 getContext().startActivity(intent);
                 // There is no way to know if the word was indeed added. Re-check.
@@ -9981,14 +9989,14 @@
                     // way to assign them a valid range after replacement
                     if (suggestionSpansStarts[i] <= spanStart &&
                             suggestionSpansEnds[i] >= spanEnd) {
-                        // TODO The ExtractEditText should restore these spans in the original text
-                        editable.setSpan(suggestionSpans[i], suggestionSpansStarts[i],
+                        setSpan_internal(suggestionSpans[i], suggestionSpansStarts[i],
                                 suggestionSpansEnds[i] + lengthDifference, suggestionSpansFlags[i]);
                     }
                 }
 
                 // Move cursor at the end of the replaced word
-                Selection.setSelection(editable, spanEnd + lengthDifference);
+                final int newCursorPosition = spanEnd + lengthDifference;
+                setCursorPosition_internal(newCursorPosition, newCursorPosition);
             }
 
             hide();
@@ -11461,6 +11469,22 @@
         ((Editable) mText).replace(start, end, text);
     }
 
+    /**
+     * Sets a span on the specified range of text
+     * @hide
+     */
+    protected void setSpan_internal(Object span, int start, int end, int flags) {
+        ((Editable) mText).setSpan(span, start, end, flags);
+    }
+
+    /**
+     * Moves the cursor to the specified offset position in text
+     * @hide
+     */
+    protected void setCursorPosition_internal(int start, int end) {
+        Selection.setSelection(((Editable) mText), start, end);
+    }
+
     @ViewDebug.ExportedProperty(category = "text")
     private CharSequence            mText;
     private CharSequence            mTransformed;
diff --git a/core/java/com/android/internal/util/ArrayUtils.java b/core/java/com/android/internal/util/ArrayUtils.java
index 3d22929..edeb2a8 100644
--- a/core/java/com/android/internal/util/ArrayUtils.java
+++ b/core/java/com/android/internal/util/ArrayUtils.java
@@ -17,7 +17,6 @@
 package com.android.internal.util;
 
 import java.lang.reflect.Array;
-import java.util.Collection;
 
 // XXX these should be changed to reflect the actual memory allocator we use.
 // it looks like right now objects want to be powers of 2 minus 8
@@ -142,4 +141,56 @@
         }
         return false;
     }
+
+    /**
+     * Appends an element to a copy of the array and returns the copy.
+     * @param array The original array, or null to represent an empty array.
+     * @param element The element to add.
+     * @return A new array that contains all of the elements of the original array
+     * with the specified element added at the end.
+     */
+    @SuppressWarnings("unchecked")
+    public static <T> T[] appendElement(Class<T> kind, T[] array, T element) {
+        final T[] result;
+        final int end;
+        if (array != null) {
+            end = array.length;
+            result = (T[])Array.newInstance(kind, end + 1);
+            System.arraycopy(array, 0, result, 0, end);
+        } else {
+            end = 0;
+            result = (T[])Array.newInstance(kind, 1);
+        }
+        result[end] = element;
+        return result;
+    }
+
+    /**
+     * Removes an element from a copy of the array and returns the copy.
+     * If the element is not present, then the original array is returned unmodified.
+     * @param array The original array, or null to represent an empty array.
+     * @param element The element to remove.
+     * @return A new array that contains all of the elements of the original array
+     * except the first copy of the specified element removed.  If the specified element
+     * was not present, then returns the original array.  Returns null if the result
+     * would be an empty array.
+     */
+    @SuppressWarnings("unchecked")
+    public static <T> T[] removeElement(Class<T> kind, T[] array, T element) {
+        if (array != null) {
+            final int length = array.length;
+            for (int i = 0; i < length; i++) {
+                if (array[i] == element) {
+                    if (length == 1) {
+                        return null;
+                    }
+                    T[] result = (T[])Array.newInstance(kind, length - 1);
+                    System.arraycopy(array, 0, result, 0, i);
+                    System.arraycopy(array, i + 1, result, i, length - i - 1);
+                    return result;
+                }
+            }
+        }
+        return array;
+    }
 }
diff --git a/core/java/com/android/internal/util/StateMachine.java b/core/java/com/android/internal/util/StateMachine.java
index 72489a2..61c0c8e 100644
--- a/core/java/com/android/internal/util/StateMachine.java
+++ b/core/java/com/android/internal/util/StateMachine.java
@@ -1367,10 +1367,12 @@
     /**
      * Get a message and set Message.target = this.
      *
-     * @return message
+     * @return message or null if SM has quit
      */
     public final Message obtainMessage()
     {
+        if (mSmHandler == null) return null;
+
         return Message.obtain(mSmHandler);
     }
 
@@ -1378,9 +1380,11 @@
      * Get a message and set Message.target = this and what
      *
      * @param what is the assigned to Message.what.
-     * @return message
+     * @return message or null if SM has quit
      */
     public final Message obtainMessage(int what) {
+        if (mSmHandler == null) return null;
+
         return Message.obtain(mSmHandler, what);
     }
 
@@ -1390,10 +1394,12 @@
      *
      * @param what is the assigned to Message.what.
      * @param obj is assigned to Message.obj.
-     * @return message
+     * @return message or null if SM has quit
      */
     public final Message obtainMessage(int what, Object obj)
     {
+        if (mSmHandler == null) return null;
+
         return Message.obtain(mSmHandler, what, obj);
     }
 
@@ -1404,10 +1410,13 @@
      * @param what  is assigned to Message.what
      * @param arg1  is assigned to Message.arg1
      * @param arg2  is assigned to Message.arg2
-     * @return  A Message object from the global pool.
+     * @return  A Message object from the global pool or null if
+     *          SM has quit
      */
     public final Message obtainMessage(int what, int arg1, int arg2)
     {
+        if (mSmHandler == null) return null;
+
         return Message.obtain(mSmHandler, what, arg1, arg2);
     }
 
@@ -1419,10 +1428,13 @@
      * @param arg1  is assigned to Message.arg1
      * @param arg2  is assigned to Message.arg2
      * @param obj is assigned to Message.obj
-     * @return  A Message object from the global pool.
+     * @return  A Message object from the global pool or null if
+     *          SM has quit
      */
     public final Message obtainMessage(int what, int arg1, int arg2, Object obj)
     {
+        if (mSmHandler == null) return null;
+
         return Message.obtain(mSmHandler, what, arg1, arg2, obj);
     }
 
@@ -1430,6 +1442,9 @@
      * Enqueue a message to this state machine.
      */
     public final void sendMessage(int what) {
+        // mSmHandler can be null if the state machine has quit.
+        if (mSmHandler == null) return;
+
         mSmHandler.sendMessage(obtainMessage(what));
     }
 
@@ -1437,6 +1452,9 @@
      * Enqueue a message to this state machine.
      */
     public final void sendMessage(int what, Object obj) {
+        // mSmHandler can be null if the state machine has quit.
+        if (mSmHandler == null) return;
+
         mSmHandler.sendMessage(obtainMessage(what,obj));
     }
 
@@ -1444,6 +1462,9 @@
      * Enqueue a message to this state machine.
      */
     public final void sendMessage(Message msg) {
+        // mSmHandler can be null if the state machine has quit.
+        if (mSmHandler == null) return;
+
         mSmHandler.sendMessage(msg);
     }
 
@@ -1451,6 +1472,9 @@
      * Enqueue a message to this state machine after a delay.
      */
     public final void sendMessageDelayed(int what, long delayMillis) {
+        // mSmHandler can be null if the state machine has quit.
+        if (mSmHandler == null) return;
+
         mSmHandler.sendMessageDelayed(obtainMessage(what), delayMillis);
     }
 
@@ -1458,6 +1482,9 @@
      * Enqueue a message to this state machine after a delay.
      */
     public final void sendMessageDelayed(int what, Object obj, long delayMillis) {
+        // mSmHandler can be null if the state machine has quit.
+        if (mSmHandler == null) return;
+
         mSmHandler.sendMessageDelayed(obtainMessage(what, obj), delayMillis);
     }
 
@@ -1465,6 +1492,9 @@
      * Enqueue a message to this state machine after a delay.
      */
     public final void sendMessageDelayed(Message msg, long delayMillis) {
+        // mSmHandler can be null if the state machine has quit.
+        if (mSmHandler == null) return;
+
         mSmHandler.sendMessageDelayed(msg, delayMillis);
     }
 
@@ -1509,6 +1539,9 @@
      * will be processed.
      */
     public final void quit() {
+        // mSmHandler can be null if the state machine has quit.
+        if (mSmHandler == null) return;
+
         mSmHandler.quit();
     }
 
@@ -1523,6 +1556,9 @@
      * @return if debugging is enabled
      */
     public boolean isDbg() {
+        // mSmHandler can be null if the state machine has quit.
+        if (mSmHandler == null) return false;
+
         return mSmHandler.isDbg();
     }
 
@@ -1532,6 +1568,9 @@
      * @param dbg is true to enable debugging.
      */
     public void setDbg(boolean dbg) {
+        // mSmHandler can be null if the state machine has quit.
+        if (mSmHandler == null) return;
+
         mSmHandler.setDbg(dbg);
     }
 
@@ -1539,6 +1578,9 @@
      * Start the state machine.
      */
     public void start() {
+        // mSmHandler can be null if the state machine has quit.
+        if (mSmHandler == null) return;
+
         /** Send the complete construction message */
         mSmHandler.completeConstruction();
     }
diff --git a/core/java/com/android/internal/widget/IRemoteViewsFactory.aidl b/core/java/com/android/internal/widget/IRemoteViewsFactory.aidl
index 18076c4..7317ecf 100644
--- a/core/java/com/android/internal/widget/IRemoteViewsFactory.aidl
+++ b/core/java/com/android/internal/widget/IRemoteViewsFactory.aidl
@@ -22,6 +22,7 @@
 /** {@hide} */
 interface IRemoteViewsFactory {
     void onDataSetChanged();
+    oneway void onDataSetChangedAsync();
     oneway void onDestroy(in Intent intent);
     int getCount();
     RemoteViews getViewAt(int position);
diff --git a/core/jni/Android.mk b/core/jni/Android.mk
index f20fbbb..bafee0e 100644
--- a/core/jni/Android.mk
+++ b/core/jni/Android.mk
@@ -47,6 +47,7 @@
 	android_database_SQLiteStatement.cpp \
 	android_emoji_EmojiFactory.cpp \
 	android_view_Display.cpp \
+	android_view_DisplayEventReceiver.cpp \
 	android_view_Surface.cpp \
 	android_view_TextureView.cpp \
 	android_view_InputChannel.cpp \
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index c6447e1..8db7b24 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -115,6 +115,7 @@
 extern int register_android_graphics_Xfermode(JNIEnv* env);
 extern int register_android_graphics_PixelFormat(JNIEnv* env);
 extern int register_android_view_Display(JNIEnv* env);
+extern int register_android_view_DisplayEventReceiver(JNIEnv* env);
 extern int register_android_view_GLES20Canvas(JNIEnv* env);
 extern int register_android_view_HardwareRenderer(JNIEnv* env);
 extern int register_android_view_Surface(JNIEnv* env);
@@ -1098,6 +1099,7 @@
     REG_JNI(register_android_os_SystemProperties),
     REG_JNI(register_android_os_Binder),
     REG_JNI(register_android_view_Display),
+    REG_JNI(register_android_view_DisplayEventReceiver),
     REG_JNI(register_android_nio_utils),
     REG_JNI(register_android_graphics_PixelFormat),
     REG_JNI(register_android_graphics_Graphics),
diff --git a/core/jni/android/graphics/Canvas.cpp b/core/jni/android/graphics/Canvas.cpp
index 7724646..feba1e6 100644
--- a/core/jni/android/graphics/Canvas.cpp
+++ b/core/jni/android/graphics/Canvas.cpp
@@ -732,11 +732,7 @@
                                       jcharArray text, int index, int count,
                                       jfloat x, jfloat y, int flags, SkPaint* paint) {
         jchar* textArray = env->GetCharArrayElements(text, NULL);
-#if RTL_USE_HARFBUZZ
         drawTextWithGlyphs(canvas, textArray + index, 0, count, x, y, flags, paint);
-#else
-        TextLayout::drawText(paint, textArray + index, count, flags, x, y, canvas);
-#endif
         env->ReleaseCharArrayElements(text, textArray, JNI_ABORT);
     }
 
@@ -745,11 +741,7 @@
                                           int start, int end,
                                           jfloat x, jfloat y, int flags, SkPaint* paint) {
         const jchar* textArray = env->GetStringChars(text, NULL);
-#if RTL_USE_HARFBUZZ
         drawTextWithGlyphs(canvas, textArray, start, end, x, y, flags, paint);
-#else
-        TextLayout::drawText(paint, textArray + start, end - start, flags, x, y, canvas);
-#endif
         env->ReleaseStringChars(text, textArray);
     }
 
@@ -770,12 +762,14 @@
         value = TextLayoutCache::getInstance().getValue(paint, textArray, start, count,
                 contextCount, flags);
         if (value == NULL) {
-            LOGE("Cannot get TextLayoutCache value");
+            LOGE("Cannot get TextLayoutCache value for text = '%s'",
+                    String8(textArray + start, count).string());
             return ;
         }
 #else
-        value = new TextLayoutCacheValue();
-        value->computeValues(paint, textArray, start, count, contextCount, flags);
+        value = new TextLayoutCacheValue(contextCount);
+        TextLayoutEngine::getInstance().computeValues(value.get(), paint,
+                reinterpret_cast<const UChar*>(textArray), start, count, contextCount, flags);
 #endif
         doDrawGlyphs(canvas, value->getGlyphs(), 0, value->getGlyphsCount(), x, y, flags, paint);
     }
@@ -802,13 +796,8 @@
         jfloat x, jfloat y, int dirFlags, SkPaint* paint) {
 
         jchar* chars = env->GetCharArrayElements(text, NULL);
-#if RTL_USE_HARFBUZZ
         drawTextWithGlyphs(canvas, chars + contextIndex, index - contextIndex,
                 count, contextCount, x, y, dirFlags, paint);
-#else
-        TextLayout::drawTextRun(paint, chars + contextIndex, index - contextIndex,
-                count, contextCount, dirFlags, x, y, canvas);
-#endif
         env->ReleaseCharArrayElements(text, chars, JNI_ABORT);
     }
 
@@ -820,13 +809,8 @@
         jint count = end - start;
         jint contextCount = contextEnd - contextStart;
         const jchar* chars = env->GetStringChars(text, NULL);
-#if RTL_USE_HARFBUZZ
         drawTextWithGlyphs(canvas, chars + contextStart, start - contextStart,
                 count, contextCount, x, y, dirFlags, paint);
-#else
-        TextLayout::drawTextRun(paint, chars + contextStart, start - contextStart,
-                count, contextCount, dirFlags, x, y, canvas);
-#endif
         env->ReleaseStringChars(text, chars);
     }
 
diff --git a/core/jni/android/graphics/Paint.cpp b/core/jni/android/graphics/Paint.cpp
index 883940b..19f53d7 100644
--- a/core/jni/android/graphics/Paint.cpp
+++ b/core/jni/android/graphics/Paint.cpp
@@ -350,14 +350,10 @@
         SkPaint* paint = GraphicsJNI::getNativePaint(env, jpaint);
         const jchar* textArray = env->GetCharArrayElements(text, NULL);
         jfloat result = 0;
-#if RTL_USE_HARFBUZZ
+
         TextLayout::getTextRunAdvances(paint, textArray, index, count, textLength,
                 paint->getFlags(), NULL /* dont need all advances */, &result);
-#else
-        // we double count, since measureText wants a byteLength
-        SkScalar width = paint->measureText(textArray + index, count << 1);
-        result = SkScalarToFloat(width);
-#endif
+
         env->ReleaseCharArrayElements(text, const_cast<jchar*>(textArray), JNI_ABORT);
         return result;
     }
@@ -380,13 +376,9 @@
         SkPaint* paint = GraphicsJNI::getNativePaint(env, jpaint);
         jfloat width = 0;
 
-#if RTL_USE_HARFBUZZ
         TextLayout::getTextRunAdvances(paint, textArray, start, count, textLength,
                 paint->getFlags(), NULL /* dont need all advances */, &width);
-#else
 
-        width = SkScalarToFloat(paint->measureText(textArray + start, count << 1));
-#endif
         env->ReleaseStringChars(text, textArray);
         return width;
     }
@@ -404,12 +396,9 @@
         SkPaint* paint = GraphicsJNI::getNativePaint(env, jpaint);
         jfloat width = 0;
 
-#if RTL_USE_HARFBUZZ
         TextLayout::getTextRunAdvances(paint, textArray, 0, textLength, textLength,
                 paint->getFlags(), NULL /* dont need all advances */, &width);
-#else
-        width = SkScalarToFloat(paint->measureText(textArray, textLength << 1));
-#endif
+
         env->ReleaseStringChars(text, textArray);
         return width;
     }
@@ -434,17 +423,9 @@
         AutoJavaFloatArray autoWidths(env, widths, count);
         jfloat* widthsArray = autoWidths.ptr();
 
-#if RTL_USE_HARFBUZZ
         TextLayout::getTextRunAdvances(paint, text, 0, count, count,
                 paint->getFlags(), widthsArray, NULL /* dont need totalAdvance */);
-#else
-        SkScalar* scalarArray = (SkScalar*)widthsArray;
 
-        count = paint->getTextWidths(text, count << 1, scalarArray);
-        for (int i = 0; i < count; i++) {
-            widthsArray[i] = SkScalarToFloat(scalarArray[i]);
-        }
-#endif
         return count;
     }
 
@@ -597,54 +578,11 @@
 
     static jint doTextRunCursor(JNIEnv *env, SkPaint* paint, const jchar *text, jint start,
             jint count, jint flags, jint offset, jint opt) {
-#if RTL_USE_HARFBUZZ
         jfloat scalarArray[count];
 
         TextLayout::getTextRunAdvances(paint, text, start, count, count, flags,
                 scalarArray, NULL /* dont need totalAdvance */);
-#else
-        SkScalar scalarArray[count];
-        jchar buffer[count];
 
-        // this is where we'd call harfbuzz
-        // for now we just use ushape.c and widths returned from skia
-
-        int widths;
-        if (flags & 0x1) { // rtl, call arabic shaping in case
-            UErrorCode status = U_ZERO_ERROR;
-            // Use fixed length since we need to keep start and count valid
-            u_shapeArabic(text + start, count, buffer, count,
-                    U_SHAPE_LENGTH_FIXED_SPACES_NEAR | U_SHAPE_TEXT_DIRECTION_LOGICAL |
-                    U_SHAPE_LETTERS_SHAPE | U_SHAPE_X_LAMALEF_SUB_ALTERNATE, &status);
-            // we shouldn't fail unless there's an out of memory condition,
-            // in which case we're hosed anyway
-            for (int i = 0; i < count; ++i) {
-              if (buffer[i] == 0xffff) {
-                buffer[i] = 0x200b; // zero-width-space for skia
-              }
-            }
-            widths = paint->getTextWidths(buffer, count << 1, scalarArray);
-        } else {
-            widths = paint->getTextWidths(text + start, count << 1, scalarArray);
-        }
-
-        if (widths < count) {
-            // Skia operates on code points, not code units, so surrogate pairs return only one
-            // value. Expand the result so we have one value per UTF-16 code unit.
-
-            // Note, skia's getTextWidth gets confused if it encounters a surrogate pair,
-            // leaving the remaining widths zero.  Not nice.
-            const jchar *chars = text + start;
-            for (int i = count, p = widths - 1; --i > p;) {
-                if (chars[i] >= 0xdc00 && chars[i] < 0xe000 &&
-                        chars[i-1] >= 0xd800 && chars[i-1] < 0xdc00) {
-                    scalarArray[i] = 0;
-                } else {
-                  scalarArray[i] = scalarArray[--p];
-                }
-            }
-        }
-#endif
         jint pos = offset - start;
         switch (opt) {
         case AFTER:
diff --git a/core/jni/android/graphics/RtlProperties.h b/core/jni/android/graphics/RtlProperties.h
index a41c91b..d43745f 100644
--- a/core/jni/android/graphics/RtlProperties.h
+++ b/core/jni/android/graphics/RtlProperties.h
@@ -45,9 +45,6 @@
     return kRtlDebugDisabled;
 }
 
-// Define if we want to use Harfbuzz (1) or not (0)
-#define RTL_USE_HARFBUZZ 1
-
 // Define if we want (1) to have Advances debug values or not (0)
 #define DEBUG_ADVANCES 0
 
diff --git a/core/jni/android/graphics/TextLayout.cpp b/core/jni/android/graphics/TextLayout.cpp
index e1398e9..bc30ace 100644
--- a/core/jni/android/graphics/TextLayout.cpp
+++ b/core/jni/android/graphics/TextLayout.cpp
@@ -14,6 +14,8 @@
  * limitations under the License.
  */
 
+#define LOG_TAG "TextLayout"
+
 #include "TextLayout.h"
 #include "TextLayoutCache.h"
 
@@ -46,211 +48,35 @@
     return false;
 }
 
-/**
- * Character-based Arabic shaping.
- *
- * We'll use harfbuzz and glyph-based shaping instead once we're set up for it.
- *
- * @context the text context
- * @start the start of the text to render
- * @count the length of the text to render, start + count  must be <= contextCount
- * @contextCount the length of the context
- * @shaped where to put the shaped text, must have capacity for count uchars
- * @return the length of the shaped text, or -1 if error
- */
-int TextLayout::shapeRtlText(const jchar* context, jsize start, jsize count, jsize contextCount,
-                        jchar* shaped, UErrorCode& status) {
-    SkAutoSTMalloc<CHAR_BUFFER_SIZE, jchar> tempBuffer(contextCount);
-    jchar* buffer = tempBuffer.get();
-
-    // Use fixed length since we need to keep start and count valid
-    u_shapeArabic(context, contextCount, buffer, contextCount,
-                   U_SHAPE_LENGTH_FIXED_SPACES_NEAR |
-                   U_SHAPE_TEXT_DIRECTION_LOGICAL | U_SHAPE_LETTERS_SHAPE |
-                   U_SHAPE_X_LAMALEF_SUB_ALTERNATE, &status);
-
-    if (U_SUCCESS(status)) {
-        // trim out UNICODE_NOT_A_CHAR following ligatures, if any
-        int end = 0;
-        for (int i = start, e = start + count; i < e; ++i) {
-            if (buffer[i] != UNICODE_NOT_A_CHAR) {
-                buffer[end++] = buffer[i];
-            }
-        }
-        count = end;
-        // ALOG(LOG_INFO, "CSRTL", "start %d count %d ccount %d\n", start, count, contextCount);
-        ubidi_writeReverse(buffer, count, shaped, count, UBIDI_DO_MIRRORING | UBIDI_OUTPUT_REVERSE
-                           | UBIDI_KEEP_BASE_COMBINING, &status);
-        if (U_SUCCESS(status)) {
-            return count;
-        }
-    }
-    return -1;
-}
-
-/**
- * Basic character-based layout supporting rtl and arabic shaping.
- * Runs bidi on the text and generates a reordered, shaped line in buffer, returning
- * the length.
- * @text the text
- * @len the length of the text in uchars
- * @dir receives the resolved paragraph direction
- * @buffer the buffer to receive the reordered, shaped line.  Must have capacity of
- * at least len jchars.
- * @flags line bidi flags
- * @return the length of the reordered, shaped line, or -1 if error
- */
-jint TextLayout::layoutLine(const jchar* text, jint len, jint flags, int& dir, jchar* buffer,
-        UErrorCode& status) {
-    static const int RTL_OPTS = UBIDI_DO_MIRRORING | UBIDI_KEEP_BASE_COMBINING |
-            UBIDI_REMOVE_BIDI_CONTROLS | UBIDI_OUTPUT_REVERSE;
-
-    UBiDiLevel bidiReq = 0;
-    switch (flags) {
-    case kBidi_LTR: bidiReq = 0; break; // no ICU constant, canonical LTR level
-    case kBidi_RTL: bidiReq = 1; break; // no ICU constant, canonical RTL level
-    case kBidi_Default_LTR: bidiReq = UBIDI_DEFAULT_LTR; break;
-    case kBidi_Default_RTL: bidiReq = UBIDI_DEFAULT_RTL; break;
-    case kBidi_Force_LTR: memcpy(buffer, text, len * sizeof(jchar)); return len;
-    case kBidi_Force_RTL: return shapeRtlText(text, 0, len, len, buffer, status);
-    }
-
-    int32_t result = -1;
-
-    UBiDi* bidi = ubidi_open();
-    if (bidi) {
-        ubidi_setPara(bidi, text, len, bidiReq, NULL, &status);
-        if (U_SUCCESS(status)) {
-            dir = ubidi_getParaLevel(bidi) & 0x1; // 0 if ltr, 1 if rtl
-
-            int rc = ubidi_countRuns(bidi, &status);
-            if (U_SUCCESS(status)) {
-                // ALOG(LOG_INFO, "LAYOUT", "para bidiReq=%d dir=%d rc=%d\n", bidiReq, dir, rc);
-
-                int32_t slen = 0;
-                for (int i = 0; i < rc; ++i) {
-                    int32_t start;
-                    int32_t length;
-                    UBiDiDirection runDir = ubidi_getVisualRun(bidi, i, &start, &length);
-
-                    if (runDir == UBIDI_RTL) {
-                        slen += shapeRtlText(text + start, 0, length, length, buffer + slen, status);
-                    } else {
-                        memcpy(buffer + slen, text + start, length * sizeof(jchar));
-                        slen += length;
-                    }
-                }
-                if (U_SUCCESS(status)) {
-                    result = slen;
-                }
-            }
-        }
-        ubidi_close(bidi);
-    }
-
-    return result;
-}
-
-bool TextLayout::prepareText(SkPaint* paint, const jchar* text, jsize len, jint bidiFlags,
-        const jchar** outText, int32_t* outBytes, jchar** outBuffer) {
-    const jchar *workText = text;
-    jchar *buffer = NULL;
-    int dir = kDirection_LTR;
-    if (needsLayout(text, len, bidiFlags)) {
-        buffer =(jchar *) malloc(len * sizeof(jchar));
-        if (!buffer) {
-            return false;
-        }
-        UErrorCode status = U_ZERO_ERROR;
-        len = layoutLine(text, len, bidiFlags, dir, buffer, status); // might change len, dir
-        if (!U_SUCCESS(status)) {
-            ALOG(LOG_WARN, "LAYOUT", "drawText error %d\n", status);
-            free(buffer);
-            return false; // can't render
-        }
-        workText = buffer; // use the shaped text
-    }
-
-    bool trimLeft = false;
-    bool trimRight = false;
-
-    SkPaint::Align horiz = paint->getTextAlign();
-    switch (horiz) {
-        case SkPaint::kLeft_Align: trimLeft = dir & kDirection_Mask; break;
-        case SkPaint::kCenter_Align: trimLeft = trimRight = true; break;
-        case SkPaint::kRight_Align: trimRight = !(dir & kDirection_Mask);
-        default: break;
-    }
-    const jchar* workLimit = workText + len;
-
-    if (trimLeft) {
-        while (workText < workLimit && *workText == ' ') {
-            ++workText;
-        }
-    }
-    if (trimRight) {
-        while (workLimit > workText && *(workLimit - 1) == ' ') {
-            --workLimit;
-        }
-    }
-
-    *outBytes = (workLimit - workText) << 1;
-    *outText = workText;
-    *outBuffer = buffer;
-
-    return true;
-}
-
 // Draws or gets the path of a paragraph of text on a single line, running bidi and shaping.
 // This will draw if canvas is not null, otherwise path must be non-null and it will create
 // a path representing the text that would have been drawn.
 void TextLayout::handleText(SkPaint *paint, const jchar* text, jsize len,
                             jint bidiFlags, jfloat x, jfloat y,SkCanvas *canvas, SkPath *path) {
-    const jchar *workText;
-    jchar *buffer = NULL;
-    int32_t workBytes;
-    if (prepareText(paint, text, len, bidiFlags, &workText, &workBytes, &buffer)) {
-        SkScalar x_ = SkFloatToScalar(x);
-        SkScalar y_ = SkFloatToScalar(y);
-        if (canvas) {
-            canvas->drawText(workText, workBytes, x_, y_, *paint);
-        } else {
-            paint->getTextPath(workText, workBytes, x_, y_, path);
-        }
-        free(buffer);
+    sp<TextLayoutCacheValue> value;
+#if USE_TEXT_LAYOUT_CACHE
+    // Return advances from the cache. Compute them if needed
+    value = TextLayoutCache::getInstance().getValue(paint, text, 0, len,
+            len, bidiFlags);
+#else
+    value = new TextLayoutCacheValue(len);
+    TextLayoutEngine::getInstance().computeValues(value.get(), paint,
+            reinterpret_cast<const UChar*>(text), 0, len, len, bidiFlags);
+#endif
+    if (value == NULL) {
+        LOGE("Cannot get TextLayoutCache value for text = '%s'",
+                String8(text, len).string());
+        return ;
     }
-}
-
-bool TextLayout::prepareRtlTextRun(const jchar* context, jsize start, jsize& count,
-        jsize contextCount, jchar* shaped) {
-    UErrorCode status = U_ZERO_ERROR;
-    count = shapeRtlText(context, start, count, contextCount, shaped, status);
-    if (U_SUCCESS(status)) {
-        return true;
+    SkScalar x_ = SkFloatToScalar(x);
+    SkScalar y_ = SkFloatToScalar(y);
+    if (canvas) {
+        canvas->drawText(value->getGlyphs(), value->getGlyphsCount() * 2, x_, y_, *paint);
     } else {
-        LOGW("drawTextRun error %d\n", status);
+        paint->getTextPath(value->getGlyphs(), value->getGlyphsCount() * 2, x_, y_, path);
     }
-    return false;
 }
 
-void TextLayout::drawTextRun(SkPaint* paint, const jchar* chars,
-                             jint start, jint count, jint contextCount,
-                             int dirFlags, jfloat x, jfloat y, SkCanvas* canvas) {
-
-     SkScalar x_ = SkFloatToScalar(x);
-     SkScalar y_ = SkFloatToScalar(y);
-
-     uint8_t rtl = dirFlags & 0x1;
-     if (rtl) {
-         SkAutoSTMalloc<CHAR_BUFFER_SIZE, jchar> buffer(contextCount);
-         if (prepareRtlTextRun(chars, start, count, contextCount, buffer.get())) {
-             canvas->drawText(buffer.get(), count << 1, x_, y_, *paint);
-         }
-     } else {
-         canvas->drawText(chars + start, count << 1, x_, y_, *paint);
-     }
- }
-
 void TextLayout::getTextRunAdvances(SkPaint* paint, const jchar* chars, jint start,
                                     jint count, jint contextCount, jint dirFlags,
                                     jfloat* resultAdvances, jfloat* resultTotalAdvance) {
@@ -260,16 +86,20 @@
     value = TextLayoutCache::getInstance().getValue(paint, chars, start, count,
             contextCount, dirFlags);
 #else
-    value = new TextLayoutCacheValue();
-    value->computeValues(paint, chars, start, count, contextCount, dirFlags);
+    value = new TextLayoutCacheValue(contextCount);
+    TextLayoutEngine::getInstance().computeValues(value.get(), paint,
+            reinterpret_cast<const UChar*>(chars), start, count, contextCount, dirFlags);
 #endif
-    if (value != NULL) {
-        if (resultAdvances) {
-            memcpy(resultAdvances, value->getAdvances(), value->getAdvancesCount() * sizeof(jfloat));
-        }
-        if (resultTotalAdvance) {
-            *resultTotalAdvance = value->getTotalAdvance();
-        }
+    if (value == NULL) {
+        LOGE("Cannot get TextLayoutCache value for text = '%s'",
+                String8(chars + start, count).string());
+        return ;
+    }
+    if (resultAdvances) {
+        memcpy(resultAdvances, value->getAdvances(), value->getAdvancesCount() * sizeof(jfloat));
+    }
+    if (resultTotalAdvance) {
+        *resultTotalAdvance = value->getTotalAdvance();
     }
 }
 
@@ -281,12 +111,6 @@
             resultAdvances, &resultTotalAdvance);
 }
 
-// Draws a paragraph of text on a single line, running bidi and shaping
-void TextLayout::drawText(SkPaint* paint, const jchar* text, jsize len,
-                          int bidiFlags, jfloat x, jfloat y, SkCanvas* canvas) {
-    handleText(paint, text, len, bidiFlags, x, y, canvas, NULL);
-}
-
 void TextLayout::getTextPath(SkPaint *paint, const jchar *text, jsize len,
                              jint bidiFlags, jfloat x, jfloat y, SkPath *path) {
     handleText(paint, text, len, bidiFlags, x, y, NULL, path);
@@ -305,14 +129,30 @@
         return;
     }
 
-    SkAutoSTMalloc<CHAR_BUFFER_SIZE, jchar> buffer(count);
-
-    int dir = kDirection_LTR;
-    UErrorCode status = U_ZERO_ERROR;
-    count = layoutLine(text, count, bidiFlags, dir, buffer.get(), status);
-    if (U_SUCCESS(status)) {
-        canvas->drawTextOnPathHV(buffer.get(), count << 1, *path, h_, v_, *paint);
+    sp<TextLayoutCacheValue> value;
+#if USE_TEXT_LAYOUT_CACHE
+    value = TextLayoutCache::getInstance().getValue(paint, text, 0, count,
+            count, bidiFlags);
+#else
+    value = new TextLayoutCacheValue(count);
+    TextLayoutEngine::getInstance().computeValues(value.get(), paint,
+            reinterpret_cast<const UChar*>(text), 0, count, count, bidiFlags);
+#endif
+    if (value == NULL) {
+        LOGE("Cannot get TextLayoutCache value for text = '%s'",
+                String8(text, count).string());
+        return ;
     }
+
+    // Save old text encoding
+    SkPaint::TextEncoding oldEncoding = paint->getTextEncoding();
+    // Define Glyph encoding
+    paint->setTextEncoding(SkPaint::kGlyphID_TextEncoding);
+
+    canvas->drawTextOnPathHV(value->getGlyphs(), value->getGlyphsCount() * 2, *path, h_, v_, *paint);
+
+    // Get back old encoding
+    paint->setTextEncoding(oldEncoding);
 }
 
 void TextLayout::computeAdvancesWithICU(SkPaint* paint, const UChar* chars,
diff --git a/core/jni/android/graphics/TextLayout.h b/core/jni/android/graphics/TextLayout.h
index 9df3829..1dabe32 100644
--- a/core/jni/android/graphics/TextLayout.h
+++ b/core/jni/android/graphics/TextLayout.h
@@ -62,13 +62,6 @@
 class TextLayout {
 public:
 
-    /*
-     * Draws a unidirectional run of text.
-     */
-    static void drawTextRun(SkPaint* paint, const jchar* chars,
-                            jint start, jint count, jint contextCount,
-                            int dirFlags, jfloat x, jfloat y, SkCanvas* canvas);
-
     static void getTextRunAdvances(SkPaint* paint, const jchar* chars, jint start,
                                    jint count, jint contextCount, jint dirFlags,
                                    jfloat* resultAdvances, jfloat* resultTotalAdvance);
@@ -77,29 +70,16 @@
                                    jint count, jint contextCount, jint dirFlags,
                                    jfloat* resultAdvances, jfloat& resultTotalAdvance);
 
-    static void drawText(SkPaint* paint, const jchar* text, jsize len,
-                         jint bidiFlags, jfloat x, jfloat y, SkCanvas* canvas);
-
     static void getTextPath(SkPaint* paint, const jchar* text, jsize len,
                             jint bidiFlags, jfloat x, jfloat y, SkPath* path);
 
     static void drawTextOnPath(SkPaint* paint, const jchar* text, jsize len,
                                int bidiFlags, jfloat hOffset, jfloat vOffset,
                                SkPath* path, SkCanvas* canvas);
-                               
-    static bool prepareText(SkPaint* paint, const jchar* text, jsize len, jint bidiFlags,
-        const jchar** outText, int32_t* outBytes, jchar** outBuffer);
-
-    static bool prepareRtlTextRun(const jchar* context, jsize start, jsize& count,
-        jsize contextCount, jchar* shaped);
-        
 
 private:
     static bool needsLayout(const jchar* text, jint len, jint bidiFlags);
-    static int shapeRtlText(const jchar* context, jsize start, jsize count, jsize contextCount,
-                            jchar* shaped, UErrorCode& status);
-    static jint layoutLine(const jchar* text, jint len, jint flags, int &dir, jchar* buffer,
-                           UErrorCode &status);
+
     static void handleText(SkPaint* paint, const jchar* text, jsize len,
                            int bidiFlags, jfloat x, jfloat y, SkCanvas* canvas, SkPath* path);
 
diff --git a/core/jni/android/graphics/TextLayoutCache.cpp b/core/jni/android/graphics/TextLayoutCache.cpp
index d69f2d3..81bf4d5 100644
--- a/core/jni/android/graphics/TextLayoutCache.cpp
+++ b/core/jni/android/graphics/TextLayoutCache.cpp
@@ -34,10 +34,11 @@
 #if USE_TEXT_LAYOUT_CACHE
 
     ANDROID_SINGLETON_STATIC_INSTANCE(TextLayoutCache);
-    ANDROID_SINGLETON_STATIC_INSTANCE(TextLayoutEngine);
 
 #endif
 
+    ANDROID_SINGLETON_STATIC_INSTANCE(TextLayoutEngine);
+
 //--------------------------------------------------------------------------------------------------
 
 TextLayoutCache::TextLayoutCache() :
@@ -328,8 +329,7 @@
     return mElapsedTime;
 }
 
-TextLayoutEngine::TextLayoutEngine() : mShaperItemGlyphArraySize(0),
-        mShaperItemLogClustersArraySize(0) {
+TextLayoutEngine::TextLayoutEngine() : mShaperItemGlyphArraySize(0) {
     mDefaultTypeface = SkFontHost::CreateTypeface(NULL, NULL, NULL, 0, SkTypeface::kNormal);
     mArabicTypeface = NULL;
     mHebrewRegularTypeface = NULL;
@@ -372,6 +372,10 @@
         size_t start, size_t count, size_t contextCount, int dirFlags,
         Vector<jfloat>* const outAdvances, jfloat* outTotalAdvance,
         Vector<jchar>* const outGlyphs) {
+        if (!count) {
+            *outTotalAdvance = 0;
+            return;
+        }
 
         UBiDiLevel bidiReq = 0;
         bool forceLTR = false;
@@ -409,7 +413,7 @@
 #if DEBUG_GLYPHS
                     LOGD("      -- dirFlags = %d", dirFlags);
                     LOGD("      -- paraDir = %d", paraDir);
-                    LOGD("      -- run-count = %d", rc);
+                    LOGD("      -- run-count = %d", int(rc));
 #endif
                     if (U_SUCCESS(status) && rc == 1) {
                         // Normal case: one run, status is ok
@@ -418,7 +422,7 @@
                     } else if (!U_SUCCESS(status) || rc < 1) {
                         LOGW("Need to force to single run -- string = '%s',"
                                 " status = %d, rc = %d",
-                                String8(chars + start, count).string(), status, rc);
+                                String8(chars + start, count).string(), status, int(rc));
                         isRTL = (paraDir == 1);
                         useSingleRun = true;
                     } else {
@@ -509,9 +513,11 @@
         size_t count, bool isRTL,
         Vector<jfloat>* const outAdvances, jfloat* outTotalAdvance,
         Vector<jchar>* const outGlyphs) {
-
-    *outTotalAdvance = 0;
-    jfloat totalAdvance = 0;
+    if (!count) {
+        // We cannot shape an empty run.
+        *outTotalAdvance = 0;
+        return;
+    }
 
     // Set the string properties
     mShaperItem.string = chars;
@@ -528,6 +534,7 @@
     // into the shaperItem
     ssize_t indexFontRun = isRTL ? count - 1 : 0;
     unsigned numCodePoints = 0;
+    jfloat totalAdvance = 0;
     while ((isRTL) ?
             hb_utf16_script_run_prev(&numCodePoints, &mShaperItem.item, chars,
                     count, &indexFontRun):
@@ -543,8 +550,8 @@
         LOGD("Shaping Script Run with");
         LOGD("         -- isRTL = %d", isRTL);
         LOGD("         -- HB script = %d", mShaperItem.item.script);
-        LOGD("         -- startFontRun = %d", startScriptRun);
-        LOGD("         -- endFontRun = %d", endScriptRun);
+        LOGD("         -- startFontRun = %d", int(startScriptRun));
+        LOGD("         -- endFontRun = %d", int(endScriptRun));
         LOGD("         -- countFontRun = %d", countScriptRun);
         LOGD("         -- run = '%s'", String8(chars + startScriptRun, countScriptRun).string());
         LOGD("         -- string = '%s'", String8(chars, count).string());
@@ -566,12 +573,12 @@
         if (isRTL) {
             endScriptRun = startScriptRun;
 #if DEBUG_GLYPHS
-            LOGD("Updated endScriptRun = %d", endScriptRun);
+            LOGD("Updated endScriptRun = %d", int(endScriptRun));
 #endif
         } else {
             startScriptRun = endScriptRun;
 #if DEBUG_GLYPHS
-            LOGD("Updated startScriptRun = %d", startScriptRun);
+            LOGD("Updated startScriptRun = %d", int(startScriptRun));
 #endif
         }
 
@@ -720,7 +727,7 @@
     }
 
     // Shape
-    ensureShaperItemLogClustersArray(mShaperItem.item.length);
+    assert(mShaperItem.item.length > 0); // Harfbuzz will overwrite other memory if length is 0.
     ensureShaperItemGlyphArrays(mShaperItem.item.length * 3 / 2);
     mShaperItem.num_glyphs = mShaperItemGlyphArraySize;
     while (!HB_ShapeItem(&mShaperItem)) {
@@ -744,10 +751,17 @@
     LOGD("Creating Glyph Arrays with size = %d", size);
 #endif
     mShaperItemGlyphArraySize = size;
+
+    // These arrays are all indexed by glyph.
     mShaperItem.glyphs = new HB_Glyph[size];
     mShaperItem.attributes = new HB_GlyphAttributes[size];
     mShaperItem.advances = new HB_Fixed[size];
     mShaperItem.offsets = new HB_FixedPoint[size];
+
+    // Although the log_clusters array is indexed by character, Harfbuzz expects that
+    // it is big enough to hold one element per glyph.  So we allocate log_clusters along
+    // with the other glyph arrays above.
+    mShaperItem.log_clusters = new unsigned short[size];
 }
 
 void TextLayoutEngine::deleteShaperItemGlyphArrays() {
@@ -755,24 +769,6 @@
     delete[] mShaperItem.attributes;
     delete[] mShaperItem.advances;
     delete[] mShaperItem.offsets;
-}
-
-void TextLayoutEngine::ensureShaperItemLogClustersArray(size_t size) {
-    if (size > mShaperItemLogClustersArraySize) {
-        deleteShaperItemLogClustersArray();
-        createShaperItemLogClustersArray(size);
-    }
-}
-
-void TextLayoutEngine::createShaperItemLogClustersArray(size_t size) {
-#if DEBUG_GLYPHS
-    LOGD("Creating LogClusters Array with size = %d", size);
-#endif
-    mShaperItemLogClustersArraySize = size;
-    mShaperItem.log_clusters = new unsigned short[size];
-}
-
-void TextLayoutEngine::deleteShaperItemLogClustersArray() {
     delete[] mShaperItem.log_clusters;
 }
 
diff --git a/core/jni/android/graphics/TextLayoutCache.h b/core/jni/android/graphics/TextLayoutCache.h
index afb46f5..fd9ccb1 100644
--- a/core/jni/android/graphics/TextLayoutCache.h
+++ b/core/jni/android/graphics/TextLayoutCache.h
@@ -252,7 +252,6 @@
     KeyedVector<SkFontID, HB_Face> mCachedHBFaces;
 
     size_t mShaperItemGlyphArraySize;
-    size_t mShaperItemLogClustersArraySize;
 
     size_t shapeFontRun(SkPaint* paint, bool isRTL);
 
@@ -273,10 +272,6 @@
     void createShaperItemGlyphArrays(size_t size);
     void deleteShaperItemGlyphArrays();
 
-    void ensureShaperItemLogClustersArray(size_t size);
-    void createShaperItemLogClustersArray(size_t size);
-    void deleteShaperItemLogClustersArray();
-
 }; // TextLayoutEngine
 
 
diff --git a/core/jni/android_view_DisplayEventReceiver.cpp b/core/jni/android_view_DisplayEventReceiver.cpp
new file mode 100644
index 0000000..f61795d
--- /dev/null
+++ b/core/jni/android_view_DisplayEventReceiver.cpp
@@ -0,0 +1,269 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "DisplayEventReceiver"
+
+//#define LOG_NDEBUG 0
+
+
+#include "JNIHelp.h"
+
+#include <android_runtime/AndroidRuntime.h>
+#include <utils/Log.h>
+#include <utils/Looper.h>
+#include <utils/threads.h>
+#include <gui/DisplayEventReceiver.h>
+#include "android_os_MessageQueue.h"
+
+namespace android {
+
+// Number of events to read at a time from the DisplayEventReceiver pipe.
+// The value should be large enough that we can quickly drain the pipe
+// using just a few large reads.
+static const size_t EVENT_BUFFER_SIZE = 100;
+
+static struct {
+    jclass clazz;
+
+    jmethodID dispatchVsync;
+} gDisplayEventReceiverClassInfo;
+
+
+class NativeDisplayEventReceiver : public RefBase {
+public:
+    NativeDisplayEventReceiver(JNIEnv* env,
+            jobject receiverObj, const sp<Looper>& looper);
+
+    status_t initialize();
+    status_t scheduleVsync();
+    static int handleReceiveCallback(int receiveFd, int events, void* data);
+
+protected:
+    virtual ~NativeDisplayEventReceiver();
+
+private:
+    jobject mReceiverObjGlobal;
+    sp<Looper> mLooper;
+    DisplayEventReceiver mReceiver;
+    bool mWaitingForVsync;
+    bool mFdCallbackRegistered;
+};
+
+
+NativeDisplayEventReceiver::NativeDisplayEventReceiver(JNIEnv* env,
+        jobject receiverObj, const sp<Looper>& looper) :
+        mReceiverObjGlobal(env->NewGlobalRef(receiverObj)),
+        mLooper(looper), mWaitingForVsync(false), mFdCallbackRegistered(false) {
+    ALOGV("receiver %p ~ Initializing input event receiver.", this);
+}
+
+NativeDisplayEventReceiver::~NativeDisplayEventReceiver() {
+    ALOGV("receiver %p ~ Disposing display event receiver.", this);
+
+    if (mFdCallbackRegistered) {
+        mLooper->removeFd(mReceiver.getFd());
+    }
+
+    JNIEnv* env = AndroidRuntime::getJNIEnv();
+    env->DeleteGlobalRef(mReceiverObjGlobal);
+}
+
+status_t NativeDisplayEventReceiver::initialize() {
+    status_t result = mReceiver.initCheck();
+    if (result) {
+        LOGW("Failed to initialize display event receiver, status=%d", result);
+        return result;
+    }
+
+    return OK;
+}
+
+status_t NativeDisplayEventReceiver::scheduleVsync() {
+    if (!mWaitingForVsync) {
+        ALOGV("receiver %p ~ Scheduling vsync.", this);
+
+        // Drain all pending events.
+        DisplayEventReceiver::Event buf[EVENT_BUFFER_SIZE];
+        ssize_t n;
+        while ((n = mReceiver.getEvents(buf, EVENT_BUFFER_SIZE)) > 0) {
+            ALOGV("receiver %p ~ Drained %d events.", this, int(n));
+        }
+
+        if (n < 0) {
+            LOGW("Failed to drain events from display event receiver, status=%d", status_t(n));
+            return status_t(n);
+        }
+
+        status_t status = mReceiver.requestNextVsync();
+        if (status) {
+            LOGW("Failed to request next vsync, status=%d", status);
+            return status;
+        }
+
+        if (!mFdCallbackRegistered) {
+            int rc = mLooper->addFd(mReceiver.getFd(), 0, ALOOPER_EVENT_INPUT,
+                    handleReceiveCallback, this);
+            if (rc < 0) {
+                return UNKNOWN_ERROR;
+            }
+            mFdCallbackRegistered = true;
+        }
+
+        mWaitingForVsync = true;
+    }
+    return OK;
+}
+
+int NativeDisplayEventReceiver::handleReceiveCallback(int receiveFd, int events, void* data) {
+    sp<NativeDisplayEventReceiver> r = static_cast<NativeDisplayEventReceiver*>(data);
+
+    if (events & (ALOOPER_EVENT_ERROR | ALOOPER_EVENT_HANGUP)) {
+        LOGE("Display event receiver pipe was closed or an error occurred.  "
+                "events=0x%x", events);
+        r->mFdCallbackRegistered = false;
+        return 0; // remove the callback
+    }
+
+    if (!(events & ALOOPER_EVENT_INPUT)) {
+        LOGW("Received spurious callback for unhandled poll event.  "
+                "events=0x%x", events);
+        return 1; // keep the callback
+    }
+
+    // Drain all pending events, keep the last vsync.
+    nsecs_t vsyncTimestamp = -1;
+    uint32_t vsyncCount = 0;
+
+    DisplayEventReceiver::Event buf[EVENT_BUFFER_SIZE];
+    ssize_t n;
+    while ((n = r->mReceiver.getEvents(buf, EVENT_BUFFER_SIZE)) > 0) {
+        ALOGV("receiver %p ~ Read %d events.", this, int(n));
+        while (n-- > 0) {
+            if (buf[n].header.type == DisplayEventReceiver::DISPLAY_EVENT_VSYNC) {
+                vsyncTimestamp = buf[n].header.timestamp;
+                vsyncCount = buf[n].vsync.count;
+                break; // stop at last vsync in the buffer
+            }
+        }
+    }
+
+    if (vsyncTimestamp < 0) {
+        ALOGV("receiver %p ~ Woke up but there was no vsync pulse!", this);
+        return 1; // keep the callback, did not obtain a vsync pulse
+    }
+
+    ALOGV("receiver %p ~ Vsync pulse: timestamp=%lld, count=%d",
+            this, vsyncTimestamp, vsyncCount);
+    r->mWaitingForVsync = false;
+
+    JNIEnv* env = AndroidRuntime::getJNIEnv();
+
+    ALOGV("receiver %p ~ Invoking vsync handler.", this);
+    env->CallVoidMethod(r->mReceiverObjGlobal,
+            gDisplayEventReceiverClassInfo.dispatchVsync, vsyncTimestamp, vsyncCount);
+    ALOGV("receiver %p ~ Returned from vsync handler.", this);
+
+    if (env->ExceptionCheck()) {
+        LOGE("An exception occurred while dispatching a vsync event.");
+        LOGE_EX(env);
+        env->ExceptionClear();
+    }
+
+    // Check whether dispatchVsync called scheduleVsync reentrantly and set mWaitingForVsync.
+    // If so, keep the callback, otherwise remove it.
+    if (r->mWaitingForVsync) {
+        return 1; // keep the callback
+    }
+    r->mFdCallbackRegistered = false;
+    return 0; // remove the callback
+}
+
+
+static jint nativeInit(JNIEnv* env, jclass clazz, jobject receiverObj,
+        jobject messageQueueObj) {
+    sp<Looper> looper = android_os_MessageQueue_getLooper(env, messageQueueObj);
+    if (looper == NULL) {
+        jniThrowRuntimeException(env, "MessageQueue is not initialized.");
+        return 0;
+    }
+
+    sp<NativeDisplayEventReceiver> receiver = new NativeDisplayEventReceiver(env,
+            receiverObj, looper);
+    status_t status = receiver->initialize();
+    if (status) {
+        String8 message;
+        message.appendFormat("Failed to initialize display event receiver.  status=%d", status);
+        jniThrowRuntimeException(env, message.string());
+        return 0;
+    }
+
+    receiver->incStrong(gDisplayEventReceiverClassInfo.clazz); // retain a reference for the object
+    return reinterpret_cast<jint>(receiver.get());
+}
+
+static void nativeDispose(JNIEnv* env, jclass clazz, jint receiverPtr) {
+    sp<NativeDisplayEventReceiver> receiver =
+            reinterpret_cast<NativeDisplayEventReceiver*>(receiverPtr);
+    receiver->decStrong(gDisplayEventReceiverClassInfo.clazz); // drop reference held by the object
+}
+
+static void nativeScheduleVsync(JNIEnv* env, jclass clazz, jint receiverPtr) {
+    sp<NativeDisplayEventReceiver> receiver =
+            reinterpret_cast<NativeDisplayEventReceiver*>(receiverPtr);
+    status_t status = receiver->scheduleVsync();
+    if (status) {
+        String8 message;
+        message.appendFormat("Failed to schedule next vertical sync pulse.  status=%d", status);
+        jniThrowRuntimeException(env, message.string());
+    }
+}
+
+
+static JNINativeMethod gMethods[] = {
+    /* name, signature, funcPtr */
+    { "nativeInit",
+            "(Landroid/view/DisplayEventReceiver;Landroid/os/MessageQueue;)I",
+            (void*)nativeInit },
+    { "nativeDispose",
+            "(I)V",
+            (void*)nativeDispose },
+    { "nativeScheduleVsync", "(I)V",
+            (void*)nativeScheduleVsync }
+};
+
+#define FIND_CLASS(var, className) \
+        var = env->FindClass(className); \
+        LOG_FATAL_IF(! var, "Unable to find class " className); \
+        var = jclass(env->NewGlobalRef(var));
+
+#define GET_METHOD_ID(var, clazz, methodName, methodDescriptor) \
+        var = env->GetMethodID(clazz, methodName, methodDescriptor); \
+        LOG_FATAL_IF(! var, "Unable to find method " methodName);
+
+int register_android_view_DisplayEventReceiver(JNIEnv* env) {
+    int res = jniRegisterNativeMethods(env, "android/view/DisplayEventReceiver",
+            gMethods, NELEM(gMethods));
+    LOG_FATAL_IF(res < 0, "Unable to register native methods.");
+
+    FIND_CLASS(gDisplayEventReceiverClassInfo.clazz, "android/view/DisplayEventReceiver");
+
+    GET_METHOD_ID(gDisplayEventReceiverClassInfo.dispatchVsync,
+            gDisplayEventReceiverClassInfo.clazz,
+            "dispatchVsync", "(JI)V");
+    return 0;
+}
+
+} // namespace android
diff --git a/core/jni/android_view_GLES20Canvas.cpp b/core/jni/android_view_GLES20Canvas.cpp
index 426f4f7..5860658 100644
--- a/core/jni/android_view_GLES20Canvas.cpp
+++ b/core/jni/android_view_GLES20Canvas.cpp
@@ -44,7 +44,7 @@
 #include <SkiaColorFilter.h>
 #include <Rect.h>
 
-#include <TextLayout.h>
+#include <TextLayoutCache.h>
 
 namespace android {
 
@@ -487,66 +487,45 @@
 
 static void renderText(OpenGLRenderer* renderer, const jchar* text, int count,
         jfloat x, jfloat y, int flags, SkPaint* paint) {
-#if RTL_USE_HARFBUZZ
     sp<TextLayoutCacheValue> value;
 #if USE_TEXT_LAYOUT_CACHE
     value = TextLayoutCache::getInstance().getValue(paint, text, 0, count, count, flags);
     if (value == NULL) {
-        LOGE("Cannot get TextLayoutCache value");
-        return ;
+        LOGE("Cannot get TextLayoutCache value for text = '%s'",
+                String8(text, count).string());
+        return;
     }
 #else
-    value = new TextLayoutCacheValue();
-    value->computeValues(paint, text, 0, count, count, flags);
+    value = new TextLayoutCacheValue(count);
+    TextLayoutEngine::getInstance().computeValues(value.get(), paint,
+            text, 0, count, count, flags);
 #endif
     const jchar* glyphs = value->getGlyphs();
     size_t glyphsCount = value->getGlyphsCount();
     int bytesCount = glyphsCount * sizeof(jchar);
     renderer->drawText((const char*) glyphs, bytesCount, glyphsCount, x, y, paint);
-#else
-    const jchar *workText;
-    jchar* buffer = NULL;
-    int32_t workBytes;
-    if (TextLayout::prepareText(paint, text, count, flags, &workText, &workBytes, &buffer)) {
-        renderer->drawText((const char*) workText, workBytes, count, x, y, paint);
-        free(buffer);
-    }
-#endif
 }
 
 static void renderTextRun(OpenGLRenderer* renderer, const jchar* text,
         jint start, jint count, jint contextCount, jfloat x, jfloat y,
         int flags, SkPaint* paint) {
-#if RTL_USE_HARFBUZZ
     sp<TextLayoutCacheValue> value;
 #if USE_TEXT_LAYOUT_CACHE
     value = TextLayoutCache::getInstance().getValue(paint, text, start, count, contextCount, flags);
     if (value == NULL) {
-        LOGE("Cannot get TextLayoutCache value");
-        return ;
+        LOGE("Cannot get TextLayoutCache value for text = '%s'",
+                String8(text + start, count).string());
+        return;
     }
 #else
-    value = new TextLayoutCacheValue();
-    value->computeValues(paint, text, start, count, contextCount, flags);
+    value = new TextLayoutCacheValue(count);
+    TextLayoutEngine::getInstance().computeValues(value.get(), paint,
+            text, start, count, contextCount, flags);
 #endif
     const jchar* glyphs = value->getGlyphs();
     size_t glyphsCount = value->getGlyphsCount();
     int bytesCount = glyphsCount * sizeof(jchar);
     renderer->drawText((const char*) glyphs, bytesCount, glyphsCount, x, y, paint);
-#else
-    uint8_t rtl = flags & 0x1;
-    if (rtl) {
-        SkAutoSTMalloc<80, jchar> buffer(contextCount);
-        jchar* shaped = buffer.get();
-        if (TextLayout::prepareRtlTextRun(text, start, count, contextCount, shaped)) {
-            renderer->drawText((const char*) shaped, count << 1, count, x, y, paint);
-        } else {
-            LOGW("drawTextRun error");
-        }
-    } else {
-        renderer->drawText((const char*) (text + start), count << 1, count, x, y, paint);
-    }
-#endif
 }
 
 static void android_view_GLES20Canvas_drawTextArray(JNIEnv* env, jobject clazz,
@@ -719,6 +698,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 +852,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/core/jni/android_view_InputEventReceiver.cpp b/core/jni/android_view_InputEventReceiver.cpp
index 9ae63dd..523baf1 100644
--- a/core/jni/android_view_InputEventReceiver.cpp
+++ b/core/jni/android_view_InputEventReceiver.cpp
@@ -27,7 +27,6 @@
 #include <android_runtime/AndroidRuntime.h>
 #include <utils/Log.h>
 #include <utils/Looper.h>
-#include <utils/KeyedVector.h>
 #include <utils/threads.h>
 #include <ui/InputTransport.h>
 #include "android_os_MessageQueue.h"
diff --git a/core/res/res/drawable-hdpi/numberpicker_selection_divider.9.png b/core/res/res/drawable-hdpi/numberpicker_selection_divider.9.png
index fb5e54f..c9c72ba 100644
--- a/core/res/res/drawable-hdpi/numberpicker_selection_divider.9.png
+++ b/core/res/res/drawable-hdpi/numberpicker_selection_divider.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/numberpicker_selection_divider.9.png b/core/res/res/drawable-mdpi/numberpicker_selection_divider.9.png
index d49cf7a..076fc16 100644
--- a/core/res/res/drawable-mdpi/numberpicker_selection_divider.9.png
+++ b/core/res/res/drawable-mdpi/numberpicker_selection_divider.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/numberpicker_selection_divider.9.png b/core/res/res/drawable-xhdpi/numberpicker_selection_divider.9.png
index 200e581..97eb5fe 100644
--- a/core/res/res/drawable-xhdpi/numberpicker_selection_divider.9.png
+++ b/core/res/res/drawable-xhdpi/numberpicker_selection_divider.9.png
Binary files differ
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-sw600dp/keyguard_screen_password_landscape.xml b/core/res/res/layout-sw600dp/keyguard_screen_password_landscape.xml
index f972843..7a5bb6a 100644
--- a/core/res/res/layout-sw600dp/keyguard_screen_password_landscape.xml
+++ b/core/res/res/layout-sw600dp/keyguard_screen_password_landscape.xml
@@ -134,6 +134,7 @@
                 android:layout_marginTop="5dip"
                 android:keyBackground="@drawable/btn_keyboard_key_ics"
                 android:visibility="gone"
+                android:clickable="true"
             />
 
             <!-- Emergency call button. Generally not used on tablet devices. -->
diff --git a/core/res/res/layout-sw600dp/keyguard_screen_password_portrait.xml b/core/res/res/layout-sw600dp/keyguard_screen_password_portrait.xml
index 8b65b22..6df22ca 100644
--- a/core/res/res/layout-sw600dp/keyguard_screen_password_portrait.xml
+++ b/core/res/res/layout-sw600dp/keyguard_screen_password_portrait.xml
@@ -133,6 +133,7 @@
             android:background="#40000000"
             android:keyBackground="@drawable/btn_keyboard_key_ics"
             android:layout_marginBottom="80dip"
+            android:clickable="true"
         />
 
         <!-- emergency call button -->
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..18b4715
--- /dev/null
+++ b/core/res/res/layout/global_actions_silent_mode.xml
@@ -0,0 +1,103 @@
+<?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"
+        android:contentDescription="@string/silent_mode_silent"
+        android:focusable="true"
+        >
+        <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"
+        android:contentDescription="@string/silent_mode_vibrate"
+        android:focusable="true"
+        >
+        <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"
+        android:contentDescription="@string/silent_mode_ring"
+        android:focusable="true"
+        >
+        <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/layout/keyguard_screen_password_landscape.xml b/core/res/res/layout/keyguard_screen_password_landscape.xml
index ba0c22f..e95553f 100644
--- a/core/res/res/layout/keyguard_screen_password_landscape.xml
+++ b/core/res/res/layout/keyguard_screen_password_landscape.xml
@@ -193,6 +193,7 @@
         android:keyBackground="@*android:drawable/btn_keyboard_key_ics"
         android:visibility="gone"
         android:layout_rowSpan="7"
+        android:clickable="true"
     />
 
     <!-- Music transport control -->
diff --git a/core/res/res/layout/keyguard_screen_password_portrait.xml b/core/res/res/layout/keyguard_screen_password_portrait.xml
index f6933c3..053acb2 100644
--- a/core/res/res/layout/keyguard_screen_password_portrait.xml
+++ b/core/res/res/layout/keyguard_screen_password_portrait.xml
@@ -157,6 +157,7 @@
         android:background="#40000000"
         android:keyBackground="@*android:drawable/btn_keyboard_key_ics"
         android:visibility="gone"
+        android:clickable="true"
     />
 
     <TextView
diff --git a/core/res/res/values-af/donottranslate-cldr.xml b/core/res/res/values-af/donottranslate-cldr.xml
new file mode 100644
index 0000000..9d38717
--- /dev/null
+++ b/core/res/res/values-af/donottranslate-cldr.xml
@@ -0,0 +1,146 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="month_long_standalone_january">Januarie</string>
+    <string name="month_long_standalone_february">Februarie</string>
+    <string name="month_long_standalone_march">Maart</string>
+    <string name="month_long_standalone_april">April</string>
+    <string name="month_long_standalone_may">Mei</string>
+    <string name="month_long_standalone_june">Junie</string>
+    <string name="month_long_standalone_july">Julie</string>
+    <string name="month_long_standalone_august">Augustus</string>
+    <string name="month_long_standalone_september">September</string>
+    <string name="month_long_standalone_october">Oktober</string>
+    <string name="month_long_standalone_november">November</string>
+    <string name="month_long_standalone_december">Desember</string>
+
+    <string name="month_long_january">Januarie</string>
+    <string name="month_long_february">Februarie</string>
+    <string name="month_long_march">Maart</string>
+    <string name="month_long_april">April</string>
+    <string name="month_long_may">Mei</string>
+    <string name="month_long_june">Junie</string>
+    <string name="month_long_july">Julie</string>
+    <string name="month_long_august">Augustus</string>
+    <string name="month_long_september">September</string>
+    <string name="month_long_october">Oktober</string>
+    <string name="month_long_november">November</string>
+    <string name="month_long_december">Desember</string>
+
+    <string name="month_medium_january">Jan</string>
+    <string name="month_medium_february">Feb</string>
+    <string name="month_medium_march">Mar</string>
+    <string name="month_medium_april">Apr</string>
+    <string name="month_medium_may">Mei</string>
+    <string name="month_medium_june">Jun</string>
+    <string name="month_medium_july">Jul</string>
+    <string name="month_medium_august">Aug</string>
+    <string name="month_medium_september">Sep</string>
+    <string name="month_medium_october">Okt</string>
+    <string name="month_medium_november">Nov</string>
+    <string name="month_medium_december">Des</string>
+
+    <string name="month_shortest_january">1</string>
+    <string name="month_shortest_february">2</string>
+    <string name="month_shortest_march">3</string>
+    <string name="month_shortest_april">4</string>
+    <string name="month_shortest_may">5</string>
+    <string name="month_shortest_june">6</string>
+    <string name="month_shortest_july">7</string>
+    <string name="month_shortest_august">8</string>
+    <string name="month_shortest_september">9</string>
+    <string name="month_shortest_october">10</string>
+    <string name="month_shortest_november">11</string>
+    <string name="month_shortest_december">12</string>
+
+    <string name="day_of_week_long_sunday">Sondag</string>
+    <string name="day_of_week_long_monday">Maandag</string>
+    <string name="day_of_week_long_tuesday">Dinsdag</string>
+    <string name="day_of_week_long_wednesday">Woensdag</string>
+    <string name="day_of_week_long_thursday">Donderdag</string>
+    <string name="day_of_week_long_friday">Vrydag</string>
+    <string name="day_of_week_long_saturday">Saterdag</string>
+
+    <string name="day_of_week_medium_sunday">So</string>
+    <string name="day_of_week_medium_monday">Ma</string>
+    <string name="day_of_week_medium_tuesday">Di</string>
+    <string name="day_of_week_medium_wednesday">Wo</string>
+    <string name="day_of_week_medium_thursday">Do</string>
+    <string name="day_of_week_medium_friday">Vr</string>
+    <string name="day_of_week_medium_saturday">Sa</string>
+
+    <string name="day_of_week_short_sunday">So</string>
+    <string name="day_of_week_short_monday">Ma</string>
+    <string name="day_of_week_short_tuesday">Di</string>
+    <string name="day_of_week_short_wednesday">Wo</string>
+    <string name="day_of_week_short_thursday">Do</string>
+    <string name="day_of_week_short_friday">Vr</string>
+    <string name="day_of_week_short_saturday">Sa</string>
+
+    <string name="day_of_week_shortest_sunday">1</string>
+    <string name="day_of_week_shortest_monday">2</string>
+    <string name="day_of_week_shortest_tuesday">3</string>
+    <string name="day_of_week_shortest_wednesday">4</string>
+    <string name="day_of_week_shortest_thursday">5</string>
+    <string name="day_of_week_shortest_friday">6</string>
+    <string name="day_of_week_shortest_saturday">7</string>
+
+    <string name="am">vm.</string>
+    <string name="pm">nm.</string>
+
+    <string name="hour_minute_24">%-k:%M</string>
+    <string name="hour_minute_ampm">%-l:%M %p</string>
+    <string name="hour_minute_cap_ampm">%-l:%M %^p</string>
+    <string name="twelve_hour_time_format">h:mm a</string>
+    <string name="twenty_four_hour_time_format">H:mm</string>
+    <string name="numeric_date">%Y/%m/%d</string>
+    <string name="numeric_date_format">yyyy/MM/dd</string>
+    <string name="numeric_date_template">"%s/%s/%s"</string>
+    <string name="month_day_year">%d %B %Y</string>
+    <string name="time_of_day">%-l:%M:%S %p</string>
+    <string name="date_and_time">%-l:%M:%S %p %d %b %Y</string>
+    <string name="date_time">%2$s %1$s</string>
+    <string name="time_date">%1$s %3$s</string>
+    <string name="abbrev_month_day_year">%d %b %Y</string>
+    <string name="month_day">%-e %B</string>
+    <string name="month">%-B</string>
+    <string name="month_year">%B %Y</string>
+    <string name="abbrev_month_day">%b %-e</string>
+    <string name="abbrev_month">%b</string>
+    <string name="abbrev_month_year">%Y %b</string>
+    <string name="time1_time2">%1$s - %2$s</string>
+    <string name="date1_date2">%2$s - %5$s</string>
+    <string name="numeric_md1_md2">%2$s-%3$s - %7$s-%8$s</string>
+    <string name="numeric_wday1_md1_wday2_md2">%1$s, %2$s-%3$s - %6$s, %7$s-%8$s</string>
+    <string name="numeric_mdy1_mdy2">%4$s-%2$s-%3$s - %9$s-%7$s-%8$s</string>
+    <string name="numeric_wday1_mdy1_wday2_mdy2">%1$s, %4$s-%2$s-%3$s - %6$s, %9$s-%7$s-%8$s</string>
+    <string name="numeric_wday1_mdy1_time1_wday2_mdy2_time2">%5$s %1$s, %4$s-%2$s-%3$s - %10$s %6$s, %9$s-%7$s-%8$s</string>
+    <string name="numeric_md1_time1_md2_time2">%5$s %2$s-%3$s - %10$s %7$s-%8$s</string>
+    <string name="numeric_wday1_md1_time1_wday2_md2_time2">%5$s %1$s, %2$s-%3$s - %10$s %6$s, %7$s-%8$s</string>
+    <string name="numeric_mdy1_time1_mdy2_time2">%5$s %4$s/%2$s/%3$s - %10$s %9$s/%7$s/%8$s</string>
+    <string name="wday1_date1_time1_wday2_date2_time2">%3$s %1$s, %2$s - %6$s %4$s, %5$s</string>
+    <string name="wday1_date1_wday2_date2">%1$s, %2$s - %4$s, %5$s</string>
+    <string name="date1_time1_date2_time2">%3$s %2$s - %6$s %5$s</string>
+    <string name="time_wday_date">%1$s %2$s, %3$s</string>
+    <string name="wday_date">%2$s, %3$s</string>
+    <string name="time_wday">%1$s %2$s</string>
+    <string name="same_year_md1_md2">%3$s %2$s - %8$s %7$s</string>
+    <string name="same_year_wday1_md1_wday2_md2">%1$s %2$s %3$s - %6$s %7$s %8$s</string>
+    <string name="same_year_md1_time1_md2_time2">%5$s %3$s %2$s - %10$s %8$s %7$s</string>
+    <string name="same_month_md1_time1_md2_time2">%5$s %3$s %2$s - %10$s %8$s %7$s</string>
+    <string name="same_year_wday1_md1_time1_wday2_md2_time2">%5$s %1$s %2$s %3$s - %10$s %6$s %7$s %8$s</string>
+    <string name="same_month_wday1_md1_time1_wday2_md2_time2">%5$s %1$s %2$s %3$s - %10$s %6$s %7$s %8$s</string>
+    <string name="same_year_mdy1_time1_mdy2_time2">%5$s %4$s %2$s %3$s - %10$s %9$s %7$s %8$s</string>
+    <string name="same_month_mdy1_time1_mdy2_time2">%5$s %4$s %2$s %3$s - %10$s %9$s %7$s %8$s</string>
+    <string name="same_year_wday1_mdy1_time1_wday2_mdy2_time2">%5$s %1$s, %4$s %2$s %3$s - %10$s %6$s, %9$s %7$s %8$s</string>
+    <string name="same_month_wday1_mdy1_time1_wday2_mdy2_time2">%5$s %1$s, %4$s %2$s %3$s - %10$s %6$s, %9$s %7$s %8$s</string>
+    <string name="same_month_wday1_mdy1_wday2_mdy2">%1$s, %4$s %2$s %3$s - %6$s, %9$s %7$s %8$s</string>
+    <string name="same_month_md1_md2">%2$s %3$s-%8$s</string>
+    <string name="same_month_wday1_md1_wday2_md2">%1$s %2$s %3$s - %6$s %7$s %8$s</string>
+    <string name="same_year_mdy1_mdy2">%9$s %2$s %3$s - %7$s %8$s</string>
+    <string name="same_month_mdy1_mdy2">%9$s %2$s %3$s-%8$s</string>
+    <string name="same_year_wday1_mdy1_wday2_mdy2">%1$s, %9$s %2$s %3$s - %6$s, y %7$s %8$s</string>
+    <string name="short_format_month">%b</string>
+    <string name="full_wday_month_day_no_year">E MMMM d</string>
+    <string name="abbrev_wday_month_day_year">E, y MMM dd</string>
+</resources>
diff --git a/core/res/res/values-am/donottranslate-cldr.xml b/core/res/res/values-am/donottranslate-cldr.xml
new file mode 100644
index 0000000..2319fbf
--- /dev/null
+++ b/core/res/res/values-am/donottranslate-cldr.xml
@@ -0,0 +1,146 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="month_long_standalone_january">ጃንዩወሪ</string>
+    <string name="month_long_standalone_february">ፌብሩወሪ</string>
+    <string name="month_long_standalone_march">ማርች</string>
+    <string name="month_long_standalone_april">ኤፕረል</string>
+    <string name="month_long_standalone_may">ሜይ</string>
+    <string name="month_long_standalone_june">ጁን</string>
+    <string name="month_long_standalone_july">ጁላይ</string>
+    <string name="month_long_standalone_august">ኦገስት</string>
+    <string name="month_long_standalone_september">ሴፕቴምበር</string>
+    <string name="month_long_standalone_october">ኦክተውበር</string>
+    <string name="month_long_standalone_november">ኖቬምበር</string>
+    <string name="month_long_standalone_december">ዲሴምበር</string>
+
+    <string name="month_long_january">ጃንዩወሪ</string>
+    <string name="month_long_february">ፌብሩወሪ</string>
+    <string name="month_long_march">ማርች</string>
+    <string name="month_long_april">ኤፕረል</string>
+    <string name="month_long_may">ሜይ</string>
+    <string name="month_long_june">ጁን</string>
+    <string name="month_long_july">ጁላይ</string>
+    <string name="month_long_august">ኦገስት</string>
+    <string name="month_long_september">ሴፕቴምበር</string>
+    <string name="month_long_october">ኦክተውበር</string>
+    <string name="month_long_november">ኖቬምበር</string>
+    <string name="month_long_december">ዲሴምበር</string>
+
+    <string name="month_medium_january">ጃንዩ</string>
+    <string name="month_medium_february">ፌብሩ</string>
+    <string name="month_medium_march">ማርች</string>
+    <string name="month_medium_april">ኤፕረ</string>
+    <string name="month_medium_may">ሜይ</string>
+    <string name="month_medium_june">ጁን</string>
+    <string name="month_medium_july">ጁላይ</string>
+    <string name="month_medium_august">ኦገስ</string>
+    <string name="month_medium_september">ሴፕቴ</string>
+    <string name="month_medium_october">ኦክተ</string>
+    <string name="month_medium_november">ኖቬም</string>
+    <string name="month_medium_december">ዲሴም</string>
+
+    <string name="month_shortest_january">ጃ</string>
+    <string name="month_shortest_february">ፌ</string>
+    <string name="month_shortest_march">ማ</string>
+    <string name="month_shortest_april">ኤ</string>
+    <string name="month_shortest_may">ሜ</string>
+    <string name="month_shortest_june">ጁ</string>
+    <string name="month_shortest_july">ጁ</string>
+    <string name="month_shortest_august">ኦ</string>
+    <string name="month_shortest_september">ሴ</string>
+    <string name="month_shortest_october">ኦ</string>
+    <string name="month_shortest_november">ኖ</string>
+    <string name="month_shortest_december">ዲ</string>
+
+    <string name="day_of_week_long_sunday">እሑድ</string>
+    <string name="day_of_week_long_monday">ሰኞ</string>
+    <string name="day_of_week_long_tuesday">ማክሰኞ</string>
+    <string name="day_of_week_long_wednesday">ረቡዕ</string>
+    <string name="day_of_week_long_thursday">ሐሙስ</string>
+    <string name="day_of_week_long_friday">ዓርብ</string>
+    <string name="day_of_week_long_saturday">ቅዳሜ</string>
+
+    <string name="day_of_week_medium_sunday">እሑድ</string>
+    <string name="day_of_week_medium_monday">ሰኞ</string>
+    <string name="day_of_week_medium_tuesday">ማክሰ</string>
+    <string name="day_of_week_medium_wednesday">ረቡዕ</string>
+    <string name="day_of_week_medium_thursday">ሐሙስ</string>
+    <string name="day_of_week_medium_friday">ዓርብ</string>
+    <string name="day_of_week_medium_saturday">ቅዳሜ</string>
+
+    <string name="day_of_week_short_sunday">እሑድ</string>
+    <string name="day_of_week_short_monday">ሰኞ</string>
+    <string name="day_of_week_short_tuesday">ማክሰ</string>
+    <string name="day_of_week_short_wednesday">ረቡዕ</string>
+    <string name="day_of_week_short_thursday">ሐሙስ</string>
+    <string name="day_of_week_short_friday">ዓርብ</string>
+    <string name="day_of_week_short_saturday">ቅዳሜ</string>
+
+    <string name="day_of_week_shortest_sunday">እ</string>
+    <string name="day_of_week_shortest_monday">ሰ</string>
+    <string name="day_of_week_shortest_tuesday">ማ</string>
+    <string name="day_of_week_shortest_wednesday">ረ</string>
+    <string name="day_of_week_shortest_thursday">ሐ</string>
+    <string name="day_of_week_shortest_friday">ዓ</string>
+    <string name="day_of_week_shortest_saturday">ቅ</string>
+
+    <string name="am">ጡዋት</string>
+    <string name="pm">ከሳዓት</string>
+
+    <string name="hour_minute_24">%-k:%M</string>
+    <string name="hour_minute_ampm">%-l:%M %p</string>
+    <string name="hour_minute_cap_ampm">%-l:%M %p</string>
+    <string name="twelve_hour_time_format">h:mm a</string>
+    <string name="twenty_four_hour_time_format">H:mm</string>
+    <string name="numeric_date">%d/%m/%Y</string>
+    <string name="numeric_date_format">dd/MM/yyyy</string>
+    <string name="numeric_date_template">"%s/%s/%s"</string>
+    <string name="month_day_year">%d %B %Y</string>
+    <string name="time_of_day">%-l:%M:%S %p</string>
+    <string name="date_and_time">%-l:%M:%S %p %b %-e %Y</string>
+    <string name="date_time">%2$s %1$s</string>
+    <string name="time_date">%1$s %3$s</string>
+    <string name="abbrev_month_day_year">%b %-e %Y</string>
+    <string name="month_day">%B %-e</string>
+    <string name="month">%-B</string>
+    <string name="month_year">%B %Y</string>
+    <string name="abbrev_month_day">%b %-e</string>
+    <string name="abbrev_month">%b</string>
+    <string name="abbrev_month_year">%Y %b</string>
+    <string name="time1_time2">%1$s - %2$s</string>
+    <string name="date1_date2">%2$s - %5$s</string>
+    <string name="numeric_md1_md2">%2$s-%3$s - %7$s-%8$s</string>
+    <string name="numeric_wday1_md1_wday2_md2">%1$s, %2$s-%3$s - %6$s, %7$s-%8$s</string>
+    <string name="numeric_mdy1_mdy2">%4$s-%2$s-%3$s - %9$s-%7$s-%8$s</string>
+    <string name="numeric_wday1_mdy1_wday2_mdy2">%1$s, %4$s-%2$s-%3$s - %6$s, %9$s-%7$s-%8$s</string>
+    <string name="numeric_wday1_mdy1_time1_wday2_mdy2_time2">%5$s %1$s, %4$s-%2$s-%3$s - %10$s %6$s, %9$s-%7$s-%8$s</string>
+    <string name="numeric_md1_time1_md2_time2">%5$s %2$s-%3$s - %10$s %7$s-%8$s</string>
+    <string name="numeric_wday1_md1_time1_wday2_md2_time2">%5$s %1$s, %2$s-%3$s - %10$s %6$s, %7$s-%8$s</string>
+    <string name="numeric_mdy1_time1_mdy2_time2">%5$s %3$s/%2$s/%4$s - %10$s %8$s/%7$s/%9$s</string>
+    <string name="wday1_date1_time1_wday2_date2_time2">%3$s %1$s, %2$s - %6$s %4$s, %5$s</string>
+    <string name="wday1_date1_wday2_date2">%1$s, %2$s - %4$s, %5$s</string>
+    <string name="date1_time1_date2_time2">%3$s %2$s - %6$s %5$s</string>
+    <string name="time_wday_date">%1$s %2$s, %3$s</string>
+    <string name="wday_date">%2$s, %3$s</string>
+    <string name="time_wday">%1$s %2$s</string>
+    <string name="same_year_md1_md2">%2$s %3$s - %7$s %8$s</string>
+    <string name="same_year_wday1_md1_wday2_md2">%1$s %2$s %3$s - %6$s %7$s %8$s</string>
+    <string name="same_year_md1_time1_md2_time2">%5$s %2$s %3$s - %10$s %7$s %8$s</string>
+    <string name="same_month_md1_time1_md2_time2">%5$s %2$s %3$s - %10$s %7$s %8$s</string>
+    <string name="same_year_wday1_md1_time1_wday2_md2_time2">%5$s %1$s %2$s %3$s - %10$s %6$s %7$s %8$s</string>
+    <string name="same_month_wday1_md1_time1_wday2_md2_time2">%5$s %1$s %2$s %3$s - %10$s %6$s %7$s %8$s</string>
+    <string name="same_year_mdy1_time1_mdy2_time2">%5$s %4$s %2$s %3$s - %10$s %9$s %7$s %8$s</string>
+    <string name="same_month_mdy1_time1_mdy2_time2">%5$s %4$s %2$s %3$s - %10$s %9$s %7$s %8$s</string>
+    <string name="same_year_wday1_mdy1_time1_wday2_mdy2_time2">%5$s %1$s, %4$s %2$s %3$s - %10$s %6$s, %9$s %7$s %8$s</string>
+    <string name="same_month_wday1_mdy1_time1_wday2_mdy2_time2">%5$s %1$s, %4$s %2$s %3$s - %10$s %6$s, %9$s %7$s %8$s</string>
+    <string name="same_month_wday1_mdy1_wday2_mdy2">%1$s, %4$s %2$s %3$s - %6$s, %9$s %7$s %8$s</string>
+    <string name="same_month_md1_md2">%2$s %3$s-%8$s</string>
+    <string name="same_month_wday1_md1_wday2_md2">%1$s %2$s %3$s - %6$s %7$s %8$s</string>
+    <string name="same_year_mdy1_mdy2">%9$s %2$s %3$s - %7$s %8$s</string>
+    <string name="same_month_mdy1_mdy2">%9$s %2$s %3$s-%8$s</string>
+    <string name="same_year_wday1_mdy1_wday2_mdy2">%1$s, %9$s %2$s %3$s - %6$s, y %7$s %8$s</string>
+    <string name="short_format_month">%b</string>
+    <string name="full_wday_month_day_no_year">E MMMM d</string>
+    <string name="abbrev_wday_month_day_year">E, y MMM dd</string>
+</resources>
diff --git a/core/res/res/values-be/donottranslate-cldr.xml b/core/res/res/values-be/donottranslate-cldr.xml
new file mode 100644
index 0000000..365e60d
--- /dev/null
+++ b/core/res/res/values-be/donottranslate-cldr.xml
@@ -0,0 +1,138 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="month_long_standalone_may">травень</string>
+
+    <string name="month_long_january">студзень</string>
+    <string name="month_long_february">люты</string>
+    <string name="month_long_march">сакавік</string>
+    <string name="month_long_april">красавік</string>
+    <string name="month_long_may">май</string>
+    <string name="month_long_june">чэрвень</string>
+    <string name="month_long_july">ліпень</string>
+    <string name="month_long_august">жнівень</string>
+    <string name="month_long_september">верасень</string>
+    <string name="month_long_october">кастрычнік</string>
+    <string name="month_long_november">лістапад</string>
+    <string name="month_long_december">снежань</string>
+
+    <string name="month_medium_january">сту</string>
+    <string name="month_medium_february">лют</string>
+    <string name="month_medium_march">сак</string>
+    <string name="month_medium_april">кра</string>
+    <string name="month_medium_may">май</string>
+    <string name="month_medium_june">чэр</string>
+    <string name="month_medium_july">ліп</string>
+    <string name="month_medium_august">жні</string>
+    <string name="month_medium_september">вер</string>
+    <string name="month_medium_october">кас</string>
+    <string name="month_medium_november">ліс</string>
+    <string name="month_medium_december">сне</string>
+
+    <string name="month_shortest_january">с</string>
+    <string name="month_shortest_february">л</string>
+    <string name="month_shortest_march">с</string>
+    <string name="month_shortest_april">к</string>
+    <string name="month_shortest_may">м</string>
+    <string name="month_shortest_june">ч</string>
+    <string name="month_shortest_july">л</string>
+    <string name="month_shortest_august">ж</string>
+    <string name="month_shortest_september">в</string>
+    <string name="month_shortest_october">к</string>
+    <string name="month_shortest_november">л</string>
+    <string name="month_shortest_december">с</string>
+
+    <string name="day_of_week_long_sunday">нядзеля</string>
+    <string name="day_of_week_long_monday">панядзелак</string>
+    <string name="day_of_week_long_tuesday">аўторак</string>
+    <string name="day_of_week_long_wednesday">серада</string>
+    <string name="day_of_week_long_thursday">чацвер</string>
+    <string name="day_of_week_long_friday">пятніца</string>
+    <string name="day_of_week_long_saturday">субота</string>
+
+    <string name="day_of_week_medium_sunday">нд</string>
+    <string name="day_of_week_medium_monday">пн</string>
+    <string name="day_of_week_medium_tuesday">аў</string>
+    <string name="day_of_week_medium_wednesday">ср</string>
+    <string name="day_of_week_medium_thursday">чц</string>
+    <string name="day_of_week_medium_friday">пт</string>
+    <string name="day_of_week_medium_saturday">сб</string>
+
+    <string name="day_of_week_short_sunday">нд</string>
+    <string name="day_of_week_short_monday">пн</string>
+    <string name="day_of_week_short_tuesday">аў</string>
+    <string name="day_of_week_short_wednesday">ср</string>
+    <string name="day_of_week_short_thursday">чц</string>
+    <string name="day_of_week_short_friday">пт</string>
+    <string name="day_of_week_short_saturday">сб</string>
+
+    <string name="day_of_week_shortest_sunday">н</string>
+    <string name="day_of_week_shortest_monday">п</string>
+    <string name="day_of_week_shortest_tuesday">а</string>
+    <string name="day_of_week_shortest_wednesday">с</string>
+    <string name="day_of_week_shortest_thursday">ч</string>
+    <string name="day_of_week_shortest_friday">п</string>
+    <string name="day_of_week_shortest_saturday">с</string>
+
+    <string name="am">да палудня</string>
+    <string name="pm">пасля палудня</string>
+    <string name="yesterday">учора</string>
+    <string name="today">сёння</string>
+    <string name="tomorrow">заўтра</string>
+
+    <string name="hour_minute_24">%-k.%M</string>
+    <string name="hour_minute_ampm">%-l.%M %p</string>
+    <string name="hour_minute_cap_ampm">%-l.%M %p</string>
+    <string name="twelve_hour_time_format">h.mm a</string>
+    <string name="twenty_four_hour_time_format">H.mm</string>
+    <string name="numeric_date">%-e.%-m.%Y</string>
+    <string name="numeric_date_format">d.M.yyyy</string>
+    <string name="numeric_date_template">"%s.%s.%s"</string>
+    <string name="month_day_year">%-e %B %Y</string>
+    <string name="time_of_day">%H.%M.%S</string>
+    <string name="date_and_time">%H.%M.%S %-e.%-m.%Y</string>
+    <string name="date_time">%2$s %1$s</string>
+    <string name="time_date">%1$s %3$s</string>
+    <string name="abbrev_month_day_year">%-e.%-m.%Y</string>
+    <string name="month_day">%B %-e</string>
+    <string name="month">%-B</string>
+    <string name="month_year">%B %Y</string>
+    <string name="abbrev_month_day">%-e %b</string>
+    <string name="abbrev_month">%-b</string>
+    <string name="abbrev_month_year">%b %Y</string>
+    <string name="time1_time2">%1$s - %2$s</string>
+    <string name="date1_date2">%2$s - %5$s</string>
+    <string name="numeric_md1_md2">%3$s.%2$s - %8$s.%7$s</string>
+    <string name="numeric_wday1_md1_wday2_md2">%1$s, %3$s.%2$s - %6$s, %8$s.%7$s</string>
+    <string name="numeric_mdy1_mdy2">%3$s.%2$s.%4$s - %8$s.%7$s.%9$s</string>
+    <string name="numeric_wday1_mdy1_wday2_mdy2">%1$s, %3$s.%2$s.%4$s - %6$s, %8$s.%7$s.%9$s</string>
+    <string name="numeric_wday1_mdy1_time1_wday2_mdy2_time2">%5$s %1$s, %3$s/%2$s/%4$s - %10$s %6$s, %8$s/%7$s/%9$s</string>
+    <string name="numeric_md1_time1_md2_time2">%5$s %3$s.%2$s - %10$s %8$s.%7$s</string>
+    <string name="numeric_wday1_md1_time1_wday2_md2_time2">%5$s %1$s, %3$s %2$s - %10$s %6$s, %8$s %7$s</string>
+    <string name="numeric_mdy1_time1_mdy2_time2">%5$s %3$s.%2$s.%4$s - %10$s %8$s.%7$s.%9$s</string>
+    <string name="wday1_date1_time1_wday2_date2_time2">%3$s %1$s, %2$s - %6$s %4$s, %5$s</string>
+    <string name="wday1_date1_wday2_date2">%1$s, %2$s - %4$s, %5$s</string>
+    <string name="date1_time1_date2_time2">%3$s %2$s - %6$s %5$s</string>
+    <string name="time_wday_date">%1$s %2$s, %3$s</string>
+    <string name="wday_date">%2$s, %3$s</string>
+    <string name="time_wday">%1$s %2$s</string>
+    <string name="same_year_md1_md2">%2$s %3$s - %7$s %8$s</string>
+    <string name="same_year_wday1_md1_wday2_md2">%2$s %3$s, %1$s - %7$s %8$s, %6$s</string>
+    <string name="same_year_md1_time1_md2_time2">%5$s %2$s %3$s - %10$s %7$s %8$s</string>
+    <string name="same_month_md1_time1_md2_time2">%5$s %2$s %3$s - %10$s %7$s %8$s</string>
+    <string name="same_year_wday1_md1_time1_wday2_md2_time2">%5$s %2$s %3$s, %1$s - %10$s %7$s %8$s, %6$s</string>
+    <string name="same_month_wday1_md1_time1_wday2_md2_time2">%5$s %2$s %3$s, %1$s - %10$s %7$s %8$s, %6$s</string>
+    <string name="same_year_mdy1_time1_mdy2_time2">%5$s %3$s %2$s %4$s - %10$s %8$s %7$s %9$s</string>
+    <string name="same_month_mdy1_time1_mdy2_time2">%5$s %3$s %2$s %4$s - %10$s %8$s %7$s %9$s</string>
+    <string name="same_year_wday1_mdy1_time1_wday2_mdy2_time2">%5$s %1$s, %3$s %2$s %4$s - %10$s %6$s, %8$s %7$s %9$s</string>
+    <string name="same_month_wday1_mdy1_time1_wday2_mdy2_time2">%5$s %1$s, %3$s %2$s %4$s - %10$s %6$s, %8$s %7$s %9$s</string>
+    <string name="same_month_wday1_mdy1_wday2_mdy2">%1$s, %3$s %2$s %4$s - %6$s, %8$s %7$s %9$s</string>
+    <string name="same_month_md1_md2">%3$s-%8$s %2$s</string>
+    <string name="same_month_wday1_md1_wday2_md2">%2$s %3$s, %1$s - %7$s %8$s, %6$s</string>
+    <string name="same_year_mdy1_mdy2">%3$s %2$s - %8$s %7$s %9$s</string>
+    <string name="same_month_mdy1_mdy2">%3$s-%8$s %2$s %9$s</string>
+    <string name="same_year_wday1_mdy1_wday2_mdy2">%1$s, %3$s %2$s - %6$s, %8$s %7$s %9$s</string>
+    <string name="short_format_month">%b</string>
+    <string name="full_wday_month_day_no_year">MMMM d, EEEE</string>
+    <string name="abbrev_wday_month_day_year">EEE, d MMM y</string>
+</resources>
diff --git a/core/res/res/values-et/donottranslate-cldr.xml b/core/res/res/values-et/donottranslate-cldr.xml
new file mode 100644
index 0000000..d50d041
--- /dev/null
+++ b/core/res/res/values-et/donottranslate-cldr.xml
@@ -0,0 +1,149 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="month_long_standalone_january">jaanuar</string>
+    <string name="month_long_standalone_february">veebruar</string>
+    <string name="month_long_standalone_march">märts</string>
+    <string name="month_long_standalone_april">aprill</string>
+    <string name="month_long_standalone_may">mai</string>
+    <string name="month_long_standalone_june">juuni</string>
+    <string name="month_long_standalone_july">juuli</string>
+    <string name="month_long_standalone_august">august</string>
+    <string name="month_long_standalone_september">september</string>
+    <string name="month_long_standalone_october">oktoober</string>
+    <string name="month_long_standalone_november">november</string>
+    <string name="month_long_standalone_december">detsember</string>
+
+    <string name="month_long_january">jaanuar</string>
+    <string name="month_long_february">veebruar</string>
+    <string name="month_long_march">märts</string>
+    <string name="month_long_april">aprill</string>
+    <string name="month_long_may">mai</string>
+    <string name="month_long_june">juuni</string>
+    <string name="month_long_july">juuli</string>
+    <string name="month_long_august">august</string>
+    <string name="month_long_september">september</string>
+    <string name="month_long_october">oktoober</string>
+    <string name="month_long_november">november</string>
+    <string name="month_long_december">detsember</string>
+
+    <string name="month_medium_january">jaan</string>
+    <string name="month_medium_february">veebr</string>
+    <string name="month_medium_march">märts</string>
+    <string name="month_medium_april">apr</string>
+    <string name="month_medium_may">mai</string>
+    <string name="month_medium_june">juuni</string>
+    <string name="month_medium_july">juuli</string>
+    <string name="month_medium_august">aug</string>
+    <string name="month_medium_september">sept</string>
+    <string name="month_medium_october">okt</string>
+    <string name="month_medium_november">nov</string>
+    <string name="month_medium_december">dets</string>
+
+    <string name="month_shortest_january">1</string>
+    <string name="month_shortest_february">2</string>
+    <string name="month_shortest_march">3</string>
+    <string name="month_shortest_april">4</string>
+    <string name="month_shortest_may">5</string>
+    <string name="month_shortest_june">6</string>
+    <string name="month_shortest_july">7</string>
+    <string name="month_shortest_august">8</string>
+    <string name="month_shortest_september">9</string>
+    <string name="month_shortest_october">10</string>
+    <string name="month_shortest_november">11</string>
+    <string name="month_shortest_december">12</string>
+
+    <string name="day_of_week_long_sunday">pühapäev</string>
+    <string name="day_of_week_long_monday">esmaspäev</string>
+    <string name="day_of_week_long_tuesday">teisipäev</string>
+    <string name="day_of_week_long_wednesday">kolmapäev</string>
+    <string name="day_of_week_long_thursday">neljapäev</string>
+    <string name="day_of_week_long_friday">reede</string>
+    <string name="day_of_week_long_saturday">laupäev</string>
+
+    <string name="day_of_week_medium_sunday">P</string>
+    <string name="day_of_week_medium_monday">E</string>
+    <string name="day_of_week_medium_tuesday">T</string>
+    <string name="day_of_week_medium_wednesday">K</string>
+    <string name="day_of_week_medium_thursday">N</string>
+    <string name="day_of_week_medium_friday">R</string>
+    <string name="day_of_week_medium_saturday">L</string>
+
+    <string name="day_of_week_short_sunday">P</string>
+    <string name="day_of_week_short_monday">E</string>
+    <string name="day_of_week_short_tuesday">T</string>
+    <string name="day_of_week_short_wednesday">K</string>
+    <string name="day_of_week_short_thursday">N</string>
+    <string name="day_of_week_short_friday">R</string>
+    <string name="day_of_week_short_saturday">L</string>
+
+    <string name="day_of_week_shortest_sunday">1</string>
+    <string name="day_of_week_shortest_monday">2</string>
+    <string name="day_of_week_shortest_tuesday">3</string>
+    <string name="day_of_week_shortest_wednesday">4</string>
+    <string name="day_of_week_shortest_thursday">5</string>
+    <string name="day_of_week_shortest_friday">6</string>
+    <string name="day_of_week_shortest_saturday">7</string>
+
+    <string name="am">AM</string>
+    <string name="pm">PM</string>
+    <string name="yesterday">Yesterday</string>
+    <string name="today">Today</string>
+    <string name="tomorrow">Tomorrow</string>
+
+    <string name="hour_minute_24">%-k:%M</string>
+    <string name="hour_minute_ampm">%-l:%M %p</string>
+    <string name="hour_minute_cap_ampm">%-l:%M %^p</string>
+    <string name="twelve_hour_time_format">h:mm a</string>
+    <string name="twenty_four_hour_time_format">H:mm</string>
+    <string name="numeric_date">%d.%m.%Y</string>
+    <string name="numeric_date_format">dd.MM.yyyy</string>
+    <string name="numeric_date_template">"%s.%s.%s"</string>
+    <string name="month_day_year">%-e %B %Y</string>
+    <string name="time_of_day">%-k:%M:%S</string>
+    <string name="date_and_time">%-k:%M:%S %d.%m.%Y</string>
+    <string name="date_time">%2$s %1$s</string>
+    <string name="time_date">%1$s %3$s</string>
+    <string name="abbrev_month_day_year">%d.%m.%Y</string>
+    <string name="month_day">%-e %B</string>
+    <string name="month">%-B</string>
+    <string name="month_year">%B %Y</string>
+    <string name="abbrev_month_day">%-e %b</string>
+    <string name="abbrev_month">%b</string>
+    <string name="abbrev_month_year">%b %Y</string>
+    <string name="time1_time2">%1$s - %2$s</string>
+    <string name="date1_date2">%2$s - %5$s</string>
+    <string name="numeric_md1_md2">%3$s.%2$s - %8$s.%7$s</string>
+    <string name="numeric_wday1_md1_wday2_md2">%1$s, %3$s.%2$s - %6$s, %8$s.%7$s</string>
+    <string name="numeric_mdy1_mdy2">%3$s.%2$s.%4$s - %8$s.%7$s.%9$s</string>
+    <string name="numeric_wday1_mdy1_wday2_mdy2">%1$s, %3$s.%2$s.%4$s - %6$s, %8$s.%7$s.%9$s</string>
+    <string name="numeric_wday1_mdy1_time1_wday2_mdy2_time2">%5$s %1$s, %3$s.%2$s.%4$s - %10$s %6$s, %8$s.%7$s.%9$s</string>
+    <string name="numeric_md1_time1_md2_time2">%5$s %3$s.%2$s - %10$s %8$s.%7$s</string>
+    <string name="numeric_wday1_md1_time1_wday2_md2_time2">%5$s %1$s, %3$s.%2$s - %10$s %6$s, %8$s.%7$s</string>
+    <string name="numeric_mdy1_time1_mdy2_time2">%5$s %3$s.%2$s.%4$s - %10$s %8$s.%7$s.%9$s</string>
+    <string name="wday1_date1_time1_wday2_date2_time2">%3$s %1$s, %2$s - %6$s %4$s, %5$s</string>
+    <string name="wday1_date1_wday2_date2">%1$s, %2$s - %4$s, %5$s</string>
+    <string name="date1_time1_date2_time2">%3$s %2$s - %6$s %5$s</string>
+    <string name="time_wday_date">%1$s %2$s, %3$s</string>
+    <string name="wday_date">%2$s, %3$s</string>
+    <string name="time_wday">%1$s %2$s</string>
+    <string name="same_year_md1_md2">%3$s %2$s - %8$s %7$s</string>
+    <string name="same_year_wday1_md1_wday2_md2">%1$s %2$s %3$s - %6$s %7$s %8$s</string>
+    <string name="same_year_md1_time1_md2_time2">%5$s %3$s %2$s - %10$s %8$s %7$s</string>
+    <string name="same_month_md1_time1_md2_time2">%5$s %3$s %2$s - %10$s %8$s %7$s</string>
+    <string name="same_year_wday1_md1_time1_wday2_md2_time2">%5$s %1$s %2$s %3$s - %10$s %6$s %7$s %8$s</string>
+    <string name="same_month_wday1_md1_time1_wday2_md2_time2">%5$s %1$s %2$s %3$s - %10$s %6$s %7$s %8$s</string>
+    <string name="same_year_mdy1_time1_mdy2_time2">%5$s %3$s %2$s %4$s - %10$s %8$s %7$s %9$s</string>
+    <string name="same_month_mdy1_time1_mdy2_time2">%5$s %3$s %2$s %4$s - %10$s %8$s %7$s %9$s</string>
+    <string name="same_year_wday1_mdy1_time1_wday2_mdy2_time2">%5$s %1$s, %3$s, %2$s %4$s - %10$s %6$s, %8$s, %7$s %9$s</string>
+    <string name="same_month_wday1_mdy1_time1_wday2_mdy2_time2">%5$s %1$s, %3$s, %2$s %4$s - %10$s %6$s, %8$s, %7$s %9$s</string>
+    <string name="same_month_wday1_mdy1_wday2_mdy2">%1$s, %3$s, %2$s %4$s - %6$s, %8$s, %7$s %9$s</string>
+    <string name="same_month_md1_md2">%3$s-%8$s %2$s</string>
+    <string name="same_month_wday1_md1_wday2_md2">%1$s %2$s %3$s - %6$s %7$s %8$s</string>
+    <string name="same_year_mdy1_mdy2">%3$s %2$s - %8$s %7$s %9$s</string>
+    <string name="same_month_mdy1_mdy2">%3$s-%8$s %2$s %9$s</string>
+    <string name="same_year_wday1_mdy1_wday2_mdy2">%1$s, %3$s, %2$s - %6$s, %8$s, %7$s %9$s</string>
+    <string name="short_format_month">%b</string>
+    <string name="full_wday_month_day_no_year">E MMMM d</string>
+    <string name="abbrev_wday_month_day_year">E, d, MMM y</string>
+</resources>
diff --git a/core/res/res/values-hi/donottranslate-cldr.xml b/core/res/res/values-hi/donottranslate-cldr.xml
new file mode 100644
index 0000000..d9405d8
--- /dev/null
+++ b/core/res/res/values-hi/donottranslate-cldr.xml
@@ -0,0 +1,149 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="month_long_standalone_january">जनवरी</string>
+    <string name="month_long_standalone_february">फरवरी</string>
+    <string name="month_long_standalone_march">मार्च</string>
+    <string name="month_long_standalone_april">अप्रैल</string>
+    <string name="month_long_standalone_may">मई</string>
+    <string name="month_long_standalone_june">जून</string>
+    <string name="month_long_standalone_july">जुलाई</string>
+    <string name="month_long_standalone_august">अगस्त</string>
+    <string name="month_long_standalone_september">सितम्बर</string>
+    <string name="month_long_standalone_october">अक्तूबर</string>
+    <string name="month_long_standalone_november">नवम्बर</string>
+    <string name="month_long_standalone_december">दिसम्बर</string>
+
+    <string name="month_long_january">जनवरी</string>
+    <string name="month_long_february">फरवरी</string>
+    <string name="month_long_march">मार्च</string>
+    <string name="month_long_april">अप्रैल</string>
+    <string name="month_long_may">मई</string>
+    <string name="month_long_june">जून</string>
+    <string name="month_long_july">जुलाई</string>
+    <string name="month_long_august">अगस्त</string>
+    <string name="month_long_september">सितम्बर</string>
+    <string name="month_long_october">अक्तूबर</string>
+    <string name="month_long_november">नवम्बर</string>
+    <string name="month_long_december">दिसम्बर</string>
+
+    <string name="month_medium_january">जनवरी</string>
+    <string name="month_medium_february">फरवरी</string>
+    <string name="month_medium_march">मार्च</string>
+    <string name="month_medium_april">अप्रैल</string>
+    <string name="month_medium_may">मई</string>
+    <string name="month_medium_june">जून</string>
+    <string name="month_medium_july">जुलाई</string>
+    <string name="month_medium_august">अगस्त</string>
+    <string name="month_medium_september">सितम्बर</string>
+    <string name="month_medium_october">अक्तूबर</string>
+    <string name="month_medium_november">नवम्बर</string>
+    <string name="month_medium_december">दिसम्बर</string>
+
+    <string name="month_shortest_january">ज</string>
+    <string name="month_shortest_february">फ़</string>
+    <string name="month_shortest_march">मा</string>
+    <string name="month_shortest_april">अ</string>
+    <string name="month_shortest_may">म</string>
+    <string name="month_shortest_june">जू</string>
+    <string name="month_shortest_july">जु</string>
+    <string name="month_shortest_august">अ</string>
+    <string name="month_shortest_september">सि</string>
+    <string name="month_shortest_october">अ</string>
+    <string name="month_shortest_november">न</string>
+    <string name="month_shortest_december">दि</string>
+
+    <string name="day_of_week_long_sunday">रविवार</string>
+    <string name="day_of_week_long_monday">सोमवार</string>
+    <string name="day_of_week_long_tuesday">मंगलवार</string>
+    <string name="day_of_week_long_wednesday">बुधवार</string>
+    <string name="day_of_week_long_thursday">गुरुवार</string>
+    <string name="day_of_week_long_friday">शुक्रवार</string>
+    <string name="day_of_week_long_saturday">शनिवार</string>
+
+    <string name="day_of_week_medium_sunday">रवि</string>
+    <string name="day_of_week_medium_monday">सोम</string>
+    <string name="day_of_week_medium_tuesday">मंगल</string>
+    <string name="day_of_week_medium_wednesday">बुध</string>
+    <string name="day_of_week_medium_thursday">गुरु</string>
+    <string name="day_of_week_medium_friday">शुक्र</string>
+    <string name="day_of_week_medium_saturday">शनि</string>
+
+    <string name="day_of_week_short_sunday">रवि</string>
+    <string name="day_of_week_short_monday">सोम</string>
+    <string name="day_of_week_short_tuesday">मंगल</string>
+    <string name="day_of_week_short_wednesday">बुध</string>
+    <string name="day_of_week_short_thursday">गुरु</string>
+    <string name="day_of_week_short_friday">शुक्र</string>
+    <string name="day_of_week_short_saturday">शनि</string>
+
+    <string name="day_of_week_shortest_sunday">र</string>
+    <string name="day_of_week_shortest_monday">सो</string>
+    <string name="day_of_week_shortest_tuesday">मं</string>
+    <string name="day_of_week_shortest_wednesday">बु</string>
+    <string name="day_of_week_shortest_thursday">गु</string>
+    <string name="day_of_week_shortest_friday">शु</string>
+    <string name="day_of_week_shortest_saturday">श</string>
+
+    <string name="am">AM</string>
+    <string name="pm">PM</string>
+    <string name="yesterday">Yesterday</string>
+    <string name="today">Today</string>
+    <string name="tomorrow">Tomorrow</string>
+
+    <string name="hour_minute_24">%-k:%M</string>
+    <string name="hour_minute_ampm">%-l:%M %p</string>
+    <string name="hour_minute_cap_ampm">%-l:%M %^p</string>
+    <string name="twelve_hour_time_format">h:mm a</string>
+    <string name="twenty_four_hour_time_format">H:mm</string>
+    <string name="numeric_date">%-e-%-m-%Y</string>
+    <string name="numeric_date_format">d-M-yyyy</string>
+    <string name="numeric_date_template">"%s-%s-%s"</string>
+    <string name="month_day_year">%-e %B %Y</string>
+    <string name="time_of_day">%-l:%M:%S %p</string>
+    <string name="date_and_time">%-l:%M:%S %p %d-%m-%Y</string>
+    <string name="date_time">%2$s %1$s</string>
+    <string name="time_date">%1$s %3$s</string>
+    <string name="abbrev_month_day_year">%d-%m-%Y</string>
+    <string name="month_day">%-e %B</string>
+    <string name="month">%-B</string>
+    <string name="month_year">%B %Y</string>
+    <string name="abbrev_month_day">%-e %b</string>
+    <string name="abbrev_month">%-b</string>
+    <string name="abbrev_month_year">%b %Y</string>
+    <string name="time1_time2">%1$s – %2$s</string>
+    <string name="date1_date2">%2$s – %5$s</string>
+    <string name="numeric_md1_md2">%2$s-%3$s – %7$s-%8$s</string>
+    <string name="numeric_wday1_md1_wday2_md2">%1$s, %2$s-%3$s – %6$s, %7$s-%8$s</string>
+    <string name="numeric_mdy1_mdy2">%4$s-%2$s-%3$s – %9$s-%7$s-%8$s</string>
+    <string name="numeric_wday1_mdy1_wday2_mdy2">%1$s, %4$s-%2$s-%3$s – %6$s, %9$s-%7$s-%8$s</string>
+    <string name="numeric_wday1_mdy1_time1_wday2_mdy2_time2">%5$s %1$s, %4$s-%2$s-%3$s – %10$s %6$s, %9$s-%7$s-%8$s</string>
+    <string name="numeric_md1_time1_md2_time2">%5$s %3$s/%2$s – %10$s %8$s/%7$s</string>
+    <string name="numeric_wday1_md1_time1_wday2_md2_time2">%5$s %1$s, %3$s/%2$s – %10$s %6$s, %8$s/%7$s</string>
+    <string name="numeric_mdy1_time1_mdy2_time2">%5$s %3$s-%2$s-%4$s – %10$s %8$s-%7$s-%9$s</string>
+    <string name="wday1_date1_time1_wday2_date2_time2">%3$s %1$s, %2$s – %6$s %4$s, %5$s</string>
+    <string name="wday1_date1_wday2_date2">%1$s, %2$s – %4$s, %5$s</string>
+    <string name="date1_time1_date2_time2">%3$s %2$s – %6$s %5$s</string>
+    <string name="time_wday_date">%1$s %2$s, %3$s</string>
+    <string name="wday_date">%2$s, %3$s</string>
+    <string name="time_wday">%1$s %2$s</string>
+    <string name="same_year_md1_md2">%3$s %2$s – %8$s %7$s</string>
+    <string name="same_year_wday1_md1_wday2_md2">%1$s, %3$s %2$s – %6$s, %8$s %7$s</string>
+    <string name="same_year_md1_time1_md2_time2">%5$s %3$s %2$s – %10$s %8$s %7$s</string>
+    <string name="same_month_md1_time1_md2_time2">%5$s %3$s %2$s – %10$s %8$s %7$s</string>
+    <string name="same_year_wday1_md1_time1_wday2_md2_time2">%5$s %1$s, %3$s %2$s – %10$s %6$s, %8$s %7$s</string>
+    <string name="same_month_wday1_md1_time1_wday2_md2_time2">%5$s %1$s, %3$s %2$s – %10$s %6$s, %8$s %7$s</string>
+    <string name="same_year_mdy1_time1_mdy2_time2">%5$s %4$s-%2$s-%3$s – %10$s %9$s-%7$s-%8$s</string>
+    <string name="same_month_mdy1_time1_mdy2_time2">%5$s %4$s-%2$s-%3$s – %10$s %9$s-%7$s-%8$s</string>
+    <string name="same_year_wday1_mdy1_time1_wday2_mdy2_time2">%5$s %1$s, %3$s %2$s %4$s – %10$s %6$s, %8$s %7$s %9$s</string>
+    <string name="same_month_wday1_mdy1_time1_wday2_mdy2_time2">%5$s %1$s, %3$s %2$s %4$s – %10$s %6$s, %8$s %7$s %9$s</string>
+    <string name="same_month_wday1_mdy1_wday2_mdy2">%1$s, %3$s %2$s %4$s – %6$s, %8$s %7$s %9$s</string>
+    <string name="same_month_md1_md2">%2$s-%3$s – %8$s</string>
+    <string name="same_month_wday1_md1_wday2_md2">%1$s, %3$s %2$s – %6$s, %8$s %7$s</string>
+    <string name="same_year_mdy1_mdy2">%9$s-%2$s-%3$s – %7$s-%8$s</string>
+    <string name="same_month_mdy1_mdy2">%9$s-%2$s-%3$s – %8$s</string>
+    <string name="same_year_wday1_mdy1_wday2_mdy2">%1$s, %9$s-%2$s-%3$s – %6$s, yyyy-%7$s-%8$s</string>
+    <string name="short_format_month">%b</string>
+    <string name="full_wday_month_day_no_year">E, d MMMM</string>
+    <string name="abbrev_wday_month_day_year">EEE, d MMM y</string>
+</resources>
diff --git a/core/res/res/values-ms/donottranslate-cldr.xml b/core/res/res/values-ms/donottranslate-cldr.xml
new file mode 100644
index 0000000..09d461c
--- /dev/null
+++ b/core/res/res/values-ms/donottranslate-cldr.xml
@@ -0,0 +1,149 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="month_long_standalone_january">Januari</string>
+    <string name="month_long_standalone_february">Februari</string>
+    <string name="month_long_standalone_march">Mac</string>
+    <string name="month_long_standalone_april">April</string>
+    <string name="month_long_standalone_may">Mei</string>
+    <string name="month_long_standalone_june">Jun</string>
+    <string name="month_long_standalone_july">Julai</string>
+    <string name="month_long_standalone_august">Ogos</string>
+    <string name="month_long_standalone_september">September</string>
+    <string name="month_long_standalone_october">Oktober</string>
+    <string name="month_long_standalone_november">November</string>
+    <string name="month_long_standalone_december">Disember</string>
+
+    <string name="month_long_january">Januari</string>
+    <string name="month_long_february">Februari</string>
+    <string name="month_long_march">Mac</string>
+    <string name="month_long_april">April</string>
+    <string name="month_long_may">Mei</string>
+    <string name="month_long_june">Jun</string>
+    <string name="month_long_july">Julai</string>
+    <string name="month_long_august">Ogos</string>
+    <string name="month_long_september">September</string>
+    <string name="month_long_october">Oktober</string>
+    <string name="month_long_november">November</string>
+    <string name="month_long_december">Disember</string>
+
+    <string name="month_medium_january">Jan</string>
+    <string name="month_medium_february">Feb</string>
+    <string name="month_medium_march">Mac</string>
+    <string name="month_medium_april">Apr</string>
+    <string name="month_medium_may">Mei</string>
+    <string name="month_medium_june">Jun</string>
+    <string name="month_medium_july">Jul</string>
+    <string name="month_medium_august">Ogos</string>
+    <string name="month_medium_september">Sep</string>
+    <string name="month_medium_october">Okt</string>
+    <string name="month_medium_november">Nov</string>
+    <string name="month_medium_december">Dis</string>
+
+    <string name="month_shortest_january">1</string>
+    <string name="month_shortest_february">2</string>
+    <string name="month_shortest_march">3</string>
+    <string name="month_shortest_april">4</string>
+    <string name="month_shortest_may">5</string>
+    <string name="month_shortest_june">6</string>
+    <string name="month_shortest_july">7</string>
+    <string name="month_shortest_august">8</string>
+    <string name="month_shortest_september">9</string>
+    <string name="month_shortest_october">10</string>
+    <string name="month_shortest_november">11</string>
+    <string name="month_shortest_december">12</string>
+
+    <string name="day_of_week_long_sunday">Ahad</string>
+    <string name="day_of_week_long_monday">Isnin</string>
+    <string name="day_of_week_long_tuesday">Selasa</string>
+    <string name="day_of_week_long_wednesday">Rabu</string>
+    <string name="day_of_week_long_thursday">Khamis</string>
+    <string name="day_of_week_long_friday">Jumaat</string>
+    <string name="day_of_week_long_saturday">Sabtu</string>
+
+    <string name="day_of_week_medium_sunday">Ahd</string>
+    <string name="day_of_week_medium_monday">Isn</string>
+    <string name="day_of_week_medium_tuesday">Sel</string>
+    <string name="day_of_week_medium_wednesday">Rab</string>
+    <string name="day_of_week_medium_thursday">Kha</string>
+    <string name="day_of_week_medium_friday">Jum</string>
+    <string name="day_of_week_medium_saturday">Sab</string>
+
+    <string name="day_of_week_short_sunday">Ahd</string>
+    <string name="day_of_week_short_monday">Isn</string>
+    <string name="day_of_week_short_tuesday">Sel</string>
+    <string name="day_of_week_short_wednesday">Rab</string>
+    <string name="day_of_week_short_thursday">Kha</string>
+    <string name="day_of_week_short_friday">Jum</string>
+    <string name="day_of_week_short_saturday">Sab</string>
+
+    <string name="day_of_week_shortest_sunday">1</string>
+    <string name="day_of_week_shortest_monday">2</string>
+    <string name="day_of_week_shortest_tuesday">3</string>
+    <string name="day_of_week_shortest_wednesday">4</string>
+    <string name="day_of_week_shortest_thursday">5</string>
+    <string name="day_of_week_shortest_friday">6</string>
+    <string name="day_of_week_shortest_saturday">7</string>
+
+    <string name="am">AM</string>
+    <string name="pm">PM</string>
+    <string name="yesterday">Yesterday</string>
+    <string name="today">Today</string>
+    <string name="tomorrow">Tomorrow</string>
+
+    <string name="hour_minute_24">%-k:%M</string>
+    <string name="hour_minute_ampm">%-l:%M %p</string>
+    <string name="hour_minute_cap_ampm">%-l:%M %^p</string>
+    <string name="twelve_hour_time_format">h:mm a</string>
+    <string name="twenty_four_hour_time_format">H:mm</string>
+    <string name="numeric_date">%d/%m/%Y</string>
+    <string name="numeric_date_format">dd/MM/yyyy</string>
+    <string name="numeric_date_template">"%s/%s/%s"</string>
+    <string name="month_day_year">%d %B %Y</string>
+    <string name="time_of_day">%-l:%M:%S %p</string>
+    <string name="date_and_time">%-l:%M:%S %p %d %b %Y</string>
+    <string name="date_time">%2$s %1$s</string>
+    <string name="time_date">%1$s %3$s</string>
+    <string name="abbrev_month_day_year">%d %b %Y</string>
+    <string name="month_day">%B %-e</string>
+    <string name="month">%-B</string>
+    <string name="month_year">%B %Y</string>
+    <string name="abbrev_month_day">%b %-e</string>
+    <string name="abbrev_month">%-b</string>
+    <string name="abbrev_month_year">%Y %b</string>
+    <string name="time1_time2">%1$s – %2$s</string>
+    <string name="date1_date2">%2$s – %5$s</string>
+    <string name="numeric_md1_md2">%2$s-%3$s – %7$s-%8$s</string>
+    <string name="numeric_wday1_md1_wday2_md2">%1$s, %2$s-%3$s – %6$s, %7$s-%8$s</string>
+    <string name="numeric_mdy1_mdy2">%4$s-%2$s-%3$s – %9$s-%7$s-%8$s</string>
+    <string name="numeric_wday1_mdy1_wday2_mdy2">%1$s, %4$s-%2$s-%3$s – %6$s, %9$s-%7$s-%8$s</string>
+    <string name="numeric_wday1_mdy1_time1_wday2_mdy2_time2">%5$s %1$s, %4$s-%2$s-%3$s – %10$s %6$s, %9$s-%7$s-%8$s</string>
+    <string name="numeric_md1_time1_md2_time2">%5$s %2$s-%3$s – %10$s %7$s-%8$s</string>
+    <string name="numeric_wday1_md1_time1_wday2_md2_time2">%5$s %1$s, %2$s-%3$s – %10$s %6$s, %7$s-%8$s</string>
+    <string name="numeric_mdy1_time1_mdy2_time2">%5$s %3$s/%2$s/%4$s – %10$s %8$s/%7$s/%9$s</string>
+    <string name="wday1_date1_time1_wday2_date2_time2">%3$s %1$s %2$s – %6$s %4$s %5$s</string>
+    <string name="wday1_date1_wday2_date2">%1$s %2$s – %4$s %5$s</string>
+    <string name="date1_time1_date2_time2">%3$s %2$s – %6$s %5$s</string>
+    <string name="time_wday_date">%1$s %2$s %3$s</string>
+    <string name="wday_date">%2$s %3$s</string>
+    <string name="time_wday">%1$s %2$s</string>
+    <string name="same_year_md1_md2">%2$s %3$s – %7$s %8$s</string>
+    <string name="same_year_wday1_md1_wday2_md2">%1$s %2$s %3$s – %6$s %7$s %8$s</string>
+    <string name="same_year_md1_time1_md2_time2">%5$s %2$s %3$s – %10$s %7$s %8$s</string>
+    <string name="same_month_md1_time1_md2_time2">%5$s %2$s %3$s – %10$s %7$s %8$s</string>
+    <string name="same_year_wday1_md1_time1_wday2_md2_time2">%5$s %1$s %2$s %3$s – %10$s %6$s %7$s %8$s</string>
+    <string name="same_month_wday1_md1_time1_wday2_md2_time2">%5$s %1$s %2$s %3$s – %10$s %6$s %7$s %8$s</string>
+    <string name="same_year_mdy1_time1_mdy2_time2">%5$s %4$s-%2$s-%3$s – %10$s %9$s-%7$s-%8$s</string>
+    <string name="same_month_mdy1_time1_mdy2_time2">%5$s %4$s-%2$s-%3$s – %10$s %9$s-%7$s-%8$s</string>
+    <string name="same_year_wday1_mdy1_time1_wday2_mdy2_time2">%5$s %1$s, %4$s %2$s %3$s – %10$s %6$s, %9$s %7$s %8$s</string>
+    <string name="same_month_wday1_mdy1_time1_wday2_mdy2_time2">%5$s %1$s, %4$s %2$s %3$s – %10$s %6$s, %9$s %7$s %8$s</string>
+    <string name="same_month_wday1_mdy1_wday2_mdy2">%1$s, %4$s %2$s %3$s – %6$s, %9$s %7$s %8$s</string>
+    <string name="same_month_md1_md2">%2$s-%3$s – %8$s</string>
+    <string name="same_month_wday1_md1_wday2_md2">%1$s %2$s %3$s – %6$s %7$s %8$s</string>
+    <string name="same_year_mdy1_mdy2">%9$s-%2$s-%3$s – %7$s-%8$s</string>
+    <string name="same_month_mdy1_mdy2">%9$s-%2$s-%3$s – %8$s</string>
+    <string name="same_year_wday1_mdy1_wday2_mdy2">%1$s, %9$s-%2$s-%3$s – %6$s, yyyy-%7$s-%8$s</string>
+    <string name="short_format_month">%b</string>
+    <string name="full_wday_month_day_no_year">E MMMM d</string>
+    <string name="abbrev_wday_month_day_year">EEE, y MMM d</string>
+</resources>
diff --git a/core/res/res/values-sw/donottranslate-cldr.xml b/core/res/res/values-sw/donottranslate-cldr.xml
new file mode 100644
index 0000000..2bc07c1
--- /dev/null
+++ b/core/res/res/values-sw/donottranslate-cldr.xml
@@ -0,0 +1,149 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="month_long_standalone_january">Januari</string>
+    <string name="month_long_standalone_february">Februari</string>
+    <string name="month_long_standalone_march">Machi</string>
+    <string name="month_long_standalone_april">Aprili</string>
+    <string name="month_long_standalone_may">Mei</string>
+    <string name="month_long_standalone_june">Juni</string>
+    <string name="month_long_standalone_july">Julai</string>
+    <string name="month_long_standalone_august">Agosti</string>
+    <string name="month_long_standalone_september">Septemba</string>
+    <string name="month_long_standalone_october">Oktoba</string>
+    <string name="month_long_standalone_november">Novemba</string>
+    <string name="month_long_standalone_december">Desemba</string>
+
+    <string name="month_long_january">Januari</string>
+    <string name="month_long_february">Februari</string>
+    <string name="month_long_march">Machi</string>
+    <string name="month_long_april">Aprili</string>
+    <string name="month_long_may">Mei</string>
+    <string name="month_long_june">Juni</string>
+    <string name="month_long_july">Julai</string>
+    <string name="month_long_august">Agosti</string>
+    <string name="month_long_september">Septemba</string>
+    <string name="month_long_october">Oktoba</string>
+    <string name="month_long_november">Novemba</string>
+    <string name="month_long_december">Desemba</string>
+
+    <string name="month_medium_january">Jan</string>
+    <string name="month_medium_february">Feb</string>
+    <string name="month_medium_march">Mac</string>
+    <string name="month_medium_april">Apr</string>
+    <string name="month_medium_may">Mei</string>
+    <string name="month_medium_june">Jun</string>
+    <string name="month_medium_july">Jul</string>
+    <string name="month_medium_august">Ago</string>
+    <string name="month_medium_september">Sep</string>
+    <string name="month_medium_october">Okt</string>
+    <string name="month_medium_november">Nov</string>
+    <string name="month_medium_december">Des</string>
+
+    <string name="month_shortest_january">1</string>
+    <string name="month_shortest_february">2</string>
+    <string name="month_shortest_march">3</string>
+    <string name="month_shortest_april">4</string>
+    <string name="month_shortest_may">5</string>
+    <string name="month_shortest_june">6</string>
+    <string name="month_shortest_july">7</string>
+    <string name="month_shortest_august">8</string>
+    <string name="month_shortest_september">9</string>
+    <string name="month_shortest_october">10</string>
+    <string name="month_shortest_november">11</string>
+    <string name="month_shortest_december">12</string>
+
+    <string name="day_of_week_long_sunday">Jumapili</string>
+    <string name="day_of_week_long_monday">Jumatatu</string>
+    <string name="day_of_week_long_tuesday">Jumanne</string>
+    <string name="day_of_week_long_wednesday">Jumatano</string>
+    <string name="day_of_week_long_thursday">Alhamisi</string>
+    <string name="day_of_week_long_friday">Ijumaa</string>
+    <string name="day_of_week_long_saturday">Jumamosi</string>
+
+    <string name="day_of_week_medium_sunday">Jpi</string>
+    <string name="day_of_week_medium_monday">Jtt</string>
+    <string name="day_of_week_medium_tuesday">Jnn</string>
+    <string name="day_of_week_medium_wednesday">Jtn</string>
+    <string name="day_of_week_medium_thursday">Alh</string>
+    <string name="day_of_week_medium_friday">Iju</string>
+    <string name="day_of_week_medium_saturday">Jmo</string>
+
+    <string name="day_of_week_short_sunday">Jpi</string>
+    <string name="day_of_week_short_monday">Jtt</string>
+    <string name="day_of_week_short_tuesday">Jnn</string>
+    <string name="day_of_week_short_wednesday">Jtn</string>
+    <string name="day_of_week_short_thursday">Alh</string>
+    <string name="day_of_week_short_friday">Iju</string>
+    <string name="day_of_week_short_saturday">Jmo</string>
+
+    <string name="day_of_week_shortest_sunday">1</string>
+    <string name="day_of_week_shortest_monday">2</string>
+    <string name="day_of_week_shortest_tuesday">3</string>
+    <string name="day_of_week_shortest_wednesday">4</string>
+    <string name="day_of_week_shortest_thursday">5</string>
+    <string name="day_of_week_shortest_friday">6</string>
+    <string name="day_of_week_shortest_saturday">7</string>
+
+    <string name="am">AM</string>
+    <string name="pm">PM</string>
+    <string name="yesterday">Yesterday</string>
+    <string name="today">Today</string>
+    <string name="tomorrow">Tomorrow</string>
+
+    <string name="hour_minute_24">%-k:%M</string>
+    <string name="hour_minute_ampm">%-l:%M %p</string>
+    <string name="hour_minute_cap_ampm">%-l:%M %^p</string>
+    <string name="twelve_hour_time_format">h:mm a</string>
+    <string name="twenty_four_hour_time_format">H:mm</string>
+    <string name="numeric_date">%Y/%m/%d</string>
+    <string name="numeric_date_format">yyyy/MM/dd</string>
+    <string name="numeric_date_template">"%s/%s/%s"</string>
+    <string name="month_day_year">%Y %B %-e</string>
+    <string name="time_of_day">%H:%M:%S</string>
+    <string name="date_and_time">%H:%M:%S %Y %b %-e</string>
+    <string name="date_time">%2$s %1$s</string>
+    <string name="time_date">%1$s %3$s</string>
+    <string name="abbrev_month_day_year">%Y %b %-e</string>
+    <string name="month_day">%B %-e</string>
+    <string name="month">%-B</string>
+    <string name="month_year">%Y %B</string>
+    <string name="abbrev_month_day">%b %-e</string>
+    <string name="abbrev_month">%-b</string>
+    <string name="abbrev_month_year">%Y %b</string>
+    <string name="time1_time2">%1$s – %2$s</string>
+    <string name="date1_date2">%2$s – %5$s</string>
+    <string name="numeric_md1_md2">%2$s-%3$s – %7$s-%8$s</string>
+    <string name="numeric_wday1_md1_wday2_md2">%1$s, %2$s-%3$s – %6$s, %7$s-%8$s</string>
+    <string name="numeric_mdy1_mdy2">%4$s-%2$s-%3$s – %9$s-%7$s-%8$s</string>
+    <string name="numeric_wday1_mdy1_wday2_mdy2">%1$s, %4$s-%2$s-%3$s – %6$s, %9$s-%7$s-%8$s</string>
+    <string name="numeric_wday1_mdy1_time1_wday2_mdy2_time2">%5$s %1$s, %4$s-%2$s-%3$s – %10$s %6$s, %9$s-%7$s-%8$s</string>
+    <string name="numeric_md1_time1_md2_time2">%5$s %2$s-%3$s – %10$s %7$s-%8$s</string>
+    <string name="numeric_wday1_md1_time1_wday2_md2_time2">%5$s %1$s, %2$s-%3$s – %10$s %6$s, %7$s-%8$s</string>
+    <string name="numeric_mdy1_time1_mdy2_time2">%5$s %4$s/%2$s/%3$s – %10$s %9$s/%7$s/%8$s</string>
+    <string name="wday1_date1_time1_wday2_date2_time2">%3$s %1$s %2$s – %6$s %4$s %5$s</string>
+    <string name="wday1_date1_wday2_date2">%1$s %2$s – %4$s %5$s</string>
+    <string name="date1_time1_date2_time2">%3$s %2$s – %6$s %5$s</string>
+    <string name="time_wday_date">%1$s %2$s %3$s</string>
+    <string name="wday_date">%2$s %3$s</string>
+    <string name="time_wday">%1$s %2$s</string>
+    <string name="same_year_md1_md2">%2$s %3$s – %7$s %8$s</string>
+    <string name="same_year_wday1_md1_wday2_md2">%1$s %2$s %3$s – %6$s %7$s %8$s</string>
+    <string name="same_year_md1_time1_md2_time2">%5$s %2$s %3$s – %10$s %7$s %8$s</string>
+    <string name="same_month_md1_time1_md2_time2">%5$s %2$s %3$s – %10$s %7$s %8$s</string>
+    <string name="same_year_wday1_md1_time1_wday2_md2_time2">%5$s %1$s %2$s %3$s – %10$s %6$s %7$s %8$s</string>
+    <string name="same_month_wday1_md1_time1_wday2_md2_time2">%5$s %1$s %2$s %3$s – %10$s %6$s %7$s %8$s</string>
+    <string name="same_year_mdy1_time1_mdy2_time2">%5$s %4$s-%2$s-%3$s – %10$s %9$s-%7$s-%8$s</string>
+    <string name="same_month_mdy1_time1_mdy2_time2">%5$s %4$s-%2$s-%3$s – %10$s %9$s-%7$s-%8$s</string>
+    <string name="same_year_wday1_mdy1_time1_wday2_mdy2_time2">%5$s %1$s, %4$s %2$s %3$s – %10$s %6$s, %9$s %7$s %8$s</string>
+    <string name="same_month_wday1_mdy1_time1_wday2_mdy2_time2">%5$s %1$s, %4$s %2$s %3$s – %10$s %6$s, %9$s %7$s %8$s</string>
+    <string name="same_month_wday1_mdy1_wday2_mdy2">%1$s, %4$s %2$s %3$s – %6$s, %9$s %7$s %8$s</string>
+    <string name="same_month_md1_md2">%2$s-%3$s – %8$s</string>
+    <string name="same_month_wday1_md1_wday2_md2">%1$s %2$s %3$s – %6$s %7$s %8$s</string>
+    <string name="same_year_mdy1_mdy2">%9$s-%2$s-%3$s – %7$s-%8$s</string>
+    <string name="same_month_mdy1_mdy2">%9$s-%2$s-%3$s – %8$s</string>
+    <string name="same_year_wday1_mdy1_wday2_mdy2">%1$s, %9$s-%2$s-%3$s – %6$s, yyyy-%7$s-%8$s</string>
+    <string name="short_format_month">%b</string>
+    <string name="full_wday_month_day_no_year">E MMMM d</string>
+    <string name="abbrev_wday_month_day_year">EEE, y MMM d</string>
+</resources>
diff --git a/core/res/res/values-zu/donottranslate-cldr.xml b/core/res/res/values-zu/donottranslate-cldr.xml
new file mode 100644
index 0000000..df578ed
--- /dev/null
+++ b/core/res/res/values-zu/donottranslate-cldr.xml
@@ -0,0 +1,149 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="month_long_standalone_january">uJanuwari</string>
+    <string name="month_long_standalone_february">uFebruwari</string>
+    <string name="month_long_standalone_march">uMashi</string>
+    <string name="month_long_standalone_april">u-Apreli</string>
+    <string name="month_long_standalone_may">uMeyi</string>
+    <string name="month_long_standalone_june">uJuni</string>
+    <string name="month_long_standalone_july">uJulayi</string>
+    <string name="month_long_standalone_august">uAgasti</string>
+    <string name="month_long_standalone_september">uSepthemba</string>
+    <string name="month_long_standalone_october">u-Okthoba</string>
+    <string name="month_long_standalone_november">uNovemba</string>
+    <string name="month_long_standalone_december">uDisemba</string>
+
+    <string name="month_long_january">Januwari</string>
+    <string name="month_long_february">Februwari</string>
+    <string name="month_long_march">Mashi</string>
+    <string name="month_long_april">Apreli</string>
+    <string name="month_long_may">Meyi</string>
+    <string name="month_long_june">Juni</string>
+    <string name="month_long_july">Julayi</string>
+    <string name="month_long_august">Agasti</string>
+    <string name="month_long_september">Septhemba</string>
+    <string name="month_long_october">Okthoba</string>
+    <string name="month_long_november">Novemba</string>
+    <string name="month_long_december">Disemba</string>
+
+    <string name="month_medium_january">Jan</string>
+    <string name="month_medium_february">Feb</string>
+    <string name="month_medium_march">Mas</string>
+    <string name="month_medium_april">Apr</string>
+    <string name="month_medium_may">Mey</string>
+    <string name="month_medium_june">Jun</string>
+    <string name="month_medium_july">Jul</string>
+    <string name="month_medium_august">Aga</string>
+    <string name="month_medium_september">Sep</string>
+    <string name="month_medium_october">Okt</string>
+    <string name="month_medium_november">Nov</string>
+    <string name="month_medium_december">Dis</string>
+
+    <string name="month_shortest_january">J</string>
+    <string name="month_shortest_february">F</string>
+    <string name="month_shortest_march">M</string>
+    <string name="month_shortest_april">A</string>
+    <string name="month_shortest_may">M</string>
+    <string name="month_shortest_june">J</string>
+    <string name="month_shortest_july">J</string>
+    <string name="month_shortest_august">A</string>
+    <string name="month_shortest_september">S</string>
+    <string name="month_shortest_october">O</string>
+    <string name="month_shortest_november">N</string>
+    <string name="month_shortest_december">D</string>
+
+    <string name="day_of_week_long_sunday">Sonto</string>
+    <string name="day_of_week_long_monday">Msombuluko</string>
+    <string name="day_of_week_long_tuesday">Lwesibili</string>
+    <string name="day_of_week_long_wednesday">Lwesithathu</string>
+    <string name="day_of_week_long_thursday">uLwesine</string>
+    <string name="day_of_week_long_friday">Lwesihlanu</string>
+    <string name="day_of_week_long_saturday">Mgqibelo</string>
+
+    <string name="day_of_week_medium_sunday">Son</string>
+    <string name="day_of_week_medium_monday">Mso</string>
+    <string name="day_of_week_medium_tuesday">Bil</string>
+    <string name="day_of_week_medium_wednesday">Tha</string>
+    <string name="day_of_week_medium_thursday">Sin</string>
+    <string name="day_of_week_medium_friday">Hla</string>
+    <string name="day_of_week_medium_saturday">Mgq</string>
+
+    <string name="day_of_week_short_sunday">Son</string>
+    <string name="day_of_week_short_monday">Mso</string>
+    <string name="day_of_week_short_tuesday">Bil</string>
+    <string name="day_of_week_short_wednesday">Tha</string>
+    <string name="day_of_week_short_thursday">Sin</string>
+    <string name="day_of_week_short_friday">Hla</string>
+    <string name="day_of_week_short_saturday">Mgq</string>
+
+    <string name="day_of_week_shortest_sunday">S</string>
+    <string name="day_of_week_shortest_monday">M</string>
+    <string name="day_of_week_shortest_tuesday">B</string>
+    <string name="day_of_week_shortest_wednesday">T</string>
+    <string name="day_of_week_shortest_thursday">S</string>
+    <string name="day_of_week_shortest_friday">H</string>
+    <string name="day_of_week_shortest_saturday">M</string>
+
+    <string name="am">AM</string>
+    <string name="pm">PM</string>
+    <string name="yesterday">Yesterday</string>
+    <string name="today">Today</string>
+    <string name="tomorrow">Tomorrow</string>
+
+    <string name="hour_minute_24">%-k:%M</string>
+    <string name="hour_minute_ampm">%-l:%M %p</string>
+    <string name="hour_minute_cap_ampm">%-l:%M %^p</string>
+    <string name="twelve_hour_time_format">h:mm a</string>
+    <string name="twenty_four_hour_time_format">H:mm</string>
+    <string name="numeric_date">%Y-%m-%d</string>
+    <string name="numeric_date_format">yyyy-MM-dd</string>
+    <string name="numeric_date_template">"%s-%s-%s"</string>
+    <string name="month_day_year">%-e %B %Y</string>
+    <string name="time_of_day">%-l:%M:%S %p</string>
+    <string name="date_and_time">%-l:%M:%S %p %-e %b %Y</string>
+    <string name="date_time">%2$s %1$s</string>
+    <string name="time_date">%1$s %3$s</string>
+    <string name="abbrev_month_day_year">%-e %b %Y</string>
+    <string name="month_day">%B %-e</string>
+    <string name="month">%-B</string>
+    <string name="month_year">%Y %B</string>
+    <string name="abbrev_month_day">%b %-e</string>
+    <string name="abbrev_month">%-b</string>
+    <string name="abbrev_month_year">%Y %b</string>
+    <string name="time1_time2">%1$s – %2$s</string>
+    <string name="date1_date2">%2$s – %5$s</string>
+    <string name="numeric_md1_md2">%2$s-%3$s – %7$s-%8$s</string>
+    <string name="numeric_wday1_md1_wday2_md2">%1$s, %2$s-%3$s – %6$s, %7$s-%8$s</string>
+    <string name="numeric_mdy1_mdy2">%4$s-%2$s-%3$s – %9$s-%7$s-%8$s</string>
+    <string name="numeric_wday1_mdy1_wday2_mdy2">%1$s, %4$s-%2$s-%3$s – %6$s, %9$s-%7$s-%8$s</string>
+    <string name="numeric_wday1_mdy1_time1_wday2_mdy2_time2">%5$s %1$s, %4$s-%2$s-%3$s – %10$s %6$s, %9$s-%7$s-%8$s</string>
+    <string name="numeric_md1_time1_md2_time2">%5$s %2$s-%3$s – %10$s %7$s-%8$s</string>
+    <string name="numeric_wday1_md1_time1_wday2_md2_time2">%5$s %1$s, %2$s-%3$s – %10$s %6$s, %7$s-%8$s</string>
+    <string name="numeric_mdy1_time1_mdy2_time2">%5$s %4$s-%2$s-%3$s – %10$s %9$s-%7$s-%8$s</string>
+    <string name="wday1_date1_time1_wday2_date2_time2">%3$s %1$s %2$s – %6$s %4$s %5$s</string>
+    <string name="wday1_date1_wday2_date2">%1$s %2$s – %4$s %5$s</string>
+    <string name="date1_time1_date2_time2">%3$s %2$s – %6$s %5$s</string>
+    <string name="time_wday_date">%1$s %2$s %3$s</string>
+    <string name="wday_date">%2$s %3$s</string>
+    <string name="time_wday">%1$s %2$s</string>
+    <string name="same_year_md1_md2">%2$s %3$s – %7$s %8$s</string>
+    <string name="same_year_wday1_md1_wday2_md2">%1$s %2$s %3$s – %6$s %7$s %8$s</string>
+    <string name="same_year_md1_time1_md2_time2">%5$s %2$s %3$s – %10$s %7$s %8$s</string>
+    <string name="same_month_md1_time1_md2_time2">%5$s %2$s %3$s – %10$s %7$s %8$s</string>
+    <string name="same_year_wday1_md1_time1_wday2_md2_time2">%5$s %1$s %2$s %3$s – %10$s %6$s %7$s %8$s</string>
+    <string name="same_month_wday1_md1_time1_wday2_md2_time2">%5$s %1$s %2$s %3$s – %10$s %6$s %7$s %8$s</string>
+    <string name="same_year_mdy1_time1_mdy2_time2">%5$s %4$s-%2$s-%3$s – %10$s %9$s-%7$s-%8$s</string>
+    <string name="same_month_mdy1_time1_mdy2_time2">%5$s %4$s-%2$s-%3$s – %10$s %9$s-%7$s-%8$s</string>
+    <string name="same_year_wday1_mdy1_time1_wday2_mdy2_time2">%5$s %1$s, %4$s %2$s %3$s – %10$s %6$s, %9$s %7$s %8$s</string>
+    <string name="same_month_wday1_mdy1_time1_wday2_mdy2_time2">%5$s %1$s, %4$s %2$s %3$s – %10$s %6$s, %9$s %7$s %8$s</string>
+    <string name="same_month_wday1_mdy1_wday2_mdy2">%1$s, %4$s %2$s %3$s – %6$s, %9$s %7$s %8$s</string>
+    <string name="same_month_md1_md2">%2$s-%3$s – %8$s</string>
+    <string name="same_month_wday1_md1_wday2_md2">%1$s %2$s %3$s – %6$s %7$s %8$s</string>
+    <string name="same_year_mdy1_mdy2">%9$s-%2$s-%3$s – %7$s-%8$s</string>
+    <string name="same_month_mdy1_mdy2">%9$s-%2$s-%3$s – %8$s</string>
+    <string name="same_year_wday1_mdy1_wday2_mdy2">%1$s, %9$s-%2$s-%3$s – %6$s, yyyy-%7$s-%8$s</string>
+    <string name="short_format_month">%b</string>
+    <string name="full_wday_month_day_no_year">E MMMM d</string>
+    <string name="abbrev_wday_month_day_year">EEE, y MMM d</string>
+</resources>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 326f186..3ab72f4 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">8dp</dimen>
+
 </resources>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 5219fcc..f702657 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. -->
@@ -286,6 +286,12 @@
     <string name="screen_lock">Screen lock</string>
     <!-- Button to turn off the phone, within the Phone Options dialog -->
     <string name="power_off">Power off</string>
+    <!-- Spoken description for ringer silent option. [CHAR LIMIT=NONE] -->
+    <string name="silent_mode_silent">Ringer off</string>
+    <!-- Spoken description for ringer vibrate option. [CHAR LIMIT=NONE] -->
+    <string name="silent_mode_vibrate">Ringer vibrate</string>
+    <!-- Spoken description for ringer normal option. [CHAR LIMIT=NONE] -->
+    <string name="silent_mode_ring">Ringer on</string>
 
     <!-- Shutdown Progress Dialog. This is shown if the user chooses to power off the phone. -->
     <string name="shutdown_progress">Shutting down\u2026</string>
@@ -359,8 +365,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 +384,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 +438,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 +528,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 +663,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 +677,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 +828,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 +1021,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 +1061,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 +1104,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 +1193,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 +1205,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 +1252,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 +1343,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 +1450,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 +1471,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 +1490,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 +1736,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 +1917,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 +1929,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 +1981,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 +1995,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>
-    <!-- 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="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=19] -->
+    <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 +2424,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 +2539,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 +2625,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 +2634,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 +2681,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 +2689,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 +2706,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 +2737,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 +2764,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 +2819,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 +2868,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 +2904,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 +2924,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 +2966,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 +2987,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 +3008,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 +3025,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 +3052,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 +3105,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 +3128,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 +3237,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 +3249,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 +3274,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 +3285,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 +3339,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/core/res/res/values/themes.xml b/core/res/res/values/themes.xml
index b18d88f..fe5388b 100644
--- a/core/res/res/values/themes.xml
+++ b/core/res/res/values/themes.xml
@@ -810,7 +810,7 @@
     
     <!-- Special theme for the recent apps dialog, to allow customization
          with overlays. -->
-    <style name="Theme.Dialog.RecentApplications">
+    <style name="Theme.Dialog.RecentApplications" parent="Theme.DeviceDefault.Dialog">
         <item name="windowFrame">@null</item>
         <item name="windowBackground">@android:color/transparent</item>
         <item name="android:windowAnimationStyle">@android:style/Animation.RecentApplications</item>
diff --git a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/stress/WifiStressTest.java b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/stress/WifiStressTest.java
index 0b32fde..2069789 100644
--- a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/stress/WifiStressTest.java
+++ b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/stress/WifiStressTest.java
@@ -63,10 +63,12 @@
     private final static long WIFI_IDLE_MS = 60 * 1000;
 
     /**
-     * The delay for Wi-Fi to get into idle, after screen off + WIFI_IDEL_MS + WIFI_IDLE_DELAY
-     * the Wi-Fi should be in idle mode and device should be in cellular mode.
+     * Delay after issuing wifi shutdown.
+     * The framework keep driver up for at leat 2 minutes to avoid problems
+     * that a quick shutdown could cause on wext driver and protentially
+     * on cfg based driver
      */
-    private final static long WIFI_IDLE_DELAY = 3 * 1000;
+    private final static long WIFI_SHUTDOWN_DELAY = 2 * 60 * 1000;
 
     private final static String OUTPUT_FILE = "WifiStressTestOutput.txt";
     private ConnectivityManagerTestActivity mAct;
@@ -265,7 +267,7 @@
             PowerManager pm =
                 (PowerManager)mRunner.getContext().getSystemService(Context.POWER_SERVICE);
             assertFalse(pm.isScreenOn());
-            sleep(WIFI_IDLE_MS, "Interruped while wait for wifi to be idle");
+            sleep(WIFI_IDLE_MS + WIFI_SHUTDOWN_DELAY, "Interruped while wait for wifi to be idle");
             assertTrue("Wait for Wi-Fi to idle timeout",
                     mAct.waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.DISCONNECTED,
                     6 * ConnectivityManagerTestActivity.SHORT_TIMEOUT));
@@ -273,9 +275,9 @@
                 // use long timeout as the pppd startup may take several retries.
                 assertTrue("Wait for cellular connection timeout",
                         mAct.waitForNetworkState(ConnectivityManager.TYPE_MOBILE, State.CONNECTED,
-                        ConnectivityManagerTestActivity.LONG_TIMEOUT));
+                        2 * ConnectivityManagerTestActivity.LONG_TIMEOUT));
             }
-            sleep(mWifiSleepTime + WIFI_IDLE_DELAY, "Interrupted while device is in sleep mode");
+            sleep(mWifiSleepTime, "Interrupted while device is in sleep mode");
             // Verify the wi-fi is still off and data connection is on
             assertEquals("Wi-Fi is reconnected", State.DISCONNECTED,
                     mAct.mCM.getNetworkInfo(ConnectivityManager.TYPE_WIFI).getState());
diff --git a/data/fonts/DroidSansArmenian.ttf b/data/fonts/DroidSansArmenian.ttf
index 62f67e0..6fafa54 100644
--- a/data/fonts/DroidSansArmenian.ttf
+++ b/data/fonts/DroidSansArmenian.ttf
Binary files differ
diff --git a/data/fonts/DroidSansGeorgian.ttf b/data/fonts/DroidSansGeorgian.ttf
index 743ae66..3a2e9fb 100644
--- a/data/fonts/DroidSansGeorgian.ttf
+++ b/data/fonts/DroidSansGeorgian.ttf
Binary files differ
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/docs/html/shareables/adl/2011Q3_Android_Market_for_Developers.pdf b/docs/html/shareables/adl/2011Q3_Android_Market_for_Developers.pdf
new file mode 100644
index 0000000..598a27e
--- /dev/null
+++ b/docs/html/shareables/adl/2011Q3_Android_Market_for_Developers.pdf
Binary files differ
diff --git a/docs/html/shareables/adl/2011Q3_Designing_UIs_for_Phones_and_Tablets.pdf b/docs/html/shareables/adl/2011Q3_Designing_UIs_for_Phones_and_Tablets.pdf
new file mode 100644
index 0000000..6ef41dd
--- /dev/null
+++ b/docs/html/shareables/adl/2011Q3_Designing_UIs_for_Phones_and_Tablets.pdf
Binary files differ
diff --git a/docs/html/shareables/adl/2011Q3_Introduction_to_Honeycomb_APIs.pdf b/docs/html/shareables/adl/2011Q3_Introduction_to_Honeycomb_APIs.pdf
new file mode 100755
index 0000000..e56d2377
--- /dev/null
+++ b/docs/html/shareables/adl/2011Q3_Introduction_to_Honeycomb_APIs.pdf
Binary files differ
diff --git a/include/gui/DisplayEventReceiver.h b/include/gui/DisplayEventReceiver.h
index 8d07c0e..dccc164 100644
--- a/include/gui/DisplayEventReceiver.h
+++ b/include/gui/DisplayEventReceiver.h
@@ -94,6 +94,20 @@
      */
     ssize_t getEvents(Event* events, size_t count);
 
+    /*
+     * setVsyncRate() sets the Event::VSync delivery rate. A value of
+     * 1 returns every Event::VSync. A value of 2 returns every other event,
+     * etc... a value of 0 returns no event unless  requestNextVsync() has
+     * been called.
+     */
+    status_t setVsyncRate(uint32_t count);
+
+    /*
+     * requestNextVsync() schedules the next Event::VSync. It has no effect
+     * if the vsync rate is > 0.
+     */
+    status_t requestNextVsync();
+
 private:
     sp<IDisplayEventConnection> mEventConnection;
     sp<BitTube> mDataChannel;
diff --git a/include/gui/IDisplayEventConnection.h b/include/gui/IDisplayEventConnection.h
index 8728bb5..86247de 100644
--- a/include/gui/IDisplayEventConnection.h
+++ b/include/gui/IDisplayEventConnection.h
@@ -33,9 +33,27 @@
 class IDisplayEventConnection : public IInterface
 {
 public:
+
     DECLARE_META_INTERFACE(DisplayEventConnection);
 
+    /*
+     * getDataChannel() returns a BitTube where to receive the events from
+     */
     virtual sp<BitTube> getDataChannel() const = 0;
+
+    /*
+     * setVsyncRate() sets the vsync event delivery rate. A value of
+     * 1 returns every vsync events. A value of 2 returns every other events,
+     * etc... a value of 0 returns no event unless  requestNextVsync() has
+     * been called.
+     */
+    virtual void setVsyncRate(uint32_t count) = 0;
+
+    /*
+     * requestNextVsync() schedules the next vsync event. It has no effect
+     * if the vsync rate is > 0.
+     */
+    virtual void requestNextVsync() = 0;    // asynchronous
 };
 
 // ----------------------------------------------------------------------------
diff --git a/include/utils/GenerationCache.h b/include/utils/GenerationCache.h
index 83cda86..da85a9a 100644
--- a/include/utils/GenerationCache.h
+++ b/include/utils/GenerationCache.h
@@ -88,11 +88,13 @@
 
     void attachToCache(const sp<Entry<K, V> >& entry);
     void detachFromCache(const sp<Entry<K, V> >& entry);
+
+    const V mNullValue;
 }; // class GenerationCache
 
 template<typename K, typename V>
 GenerationCache<K, V>::GenerationCache(uint32_t maxCapacity): mMaxCapacity(maxCapacity),
-    mListener(NULL) {
+    mListener(NULL), mNullValue(NULL) {
 };
 
 template<typename K, typename V>
@@ -154,7 +156,7 @@
         return entry->value;
     }
 
-    return NULL;
+    return mNullValue;
 }
 
 template<typename K, typename V>
diff --git a/libs/gui/DisplayEventReceiver.cpp b/libs/gui/DisplayEventReceiver.cpp
index 3b29a11..fee1feb 100644
--- a/libs/gui/DisplayEventReceiver.cpp
+++ b/libs/gui/DisplayEventReceiver.cpp
@@ -58,6 +58,26 @@
     return mDataChannel->getFd();
 }
 
+status_t DisplayEventReceiver::setVsyncRate(uint32_t count) {
+    if (int32_t(count) < 0)
+        return BAD_VALUE;
+
+    if (mEventConnection != NULL) {
+        mEventConnection->setVsyncRate(count);
+        return NO_ERROR;
+    }
+    return NO_INIT;
+}
+
+status_t DisplayEventReceiver::requestNextVsync() {
+    if (mEventConnection != NULL) {
+        mEventConnection->requestNextVsync();
+        return NO_ERROR;
+    }
+    return NO_INIT;
+}
+
+
 ssize_t DisplayEventReceiver::getEvents(DisplayEventReceiver::Event* events,
         size_t count) {
     ssize_t size = mDataChannel->read(events, sizeof(events[0])*count);
diff --git a/libs/gui/IDisplayEventConnection.cpp b/libs/gui/IDisplayEventConnection.cpp
index 44127fb..887d176 100644
--- a/libs/gui/IDisplayEventConnection.cpp
+++ b/libs/gui/IDisplayEventConnection.cpp
@@ -32,6 +32,8 @@
 
 enum {
     GET_DATA_CHANNEL = IBinder::FIRST_CALL_TRANSACTION,
+    SET_VSYNC_RATE,
+    REQUEST_NEXT_VSYNC
 };
 
 class BpDisplayEventConnection : public BpInterface<IDisplayEventConnection>
@@ -49,6 +51,19 @@
         remote()->transact(GET_DATA_CHANNEL, data, &reply);
         return new BitTube(reply);
     }
+
+    virtual void setVsyncRate(uint32_t count) {
+        Parcel data, reply;
+        data.writeInterfaceToken(IDisplayEventConnection::getInterfaceDescriptor());
+        data.writeInt32(count);
+        remote()->transact(SET_VSYNC_RATE, data, &reply);
+    }
+
+    virtual void requestNextVsync() {
+        Parcel data, reply;
+        data.writeInterfaceToken(IDisplayEventConnection::getInterfaceDescriptor());
+        remote()->transact(REQUEST_NEXT_VSYNC, data, &reply, IBinder::FLAG_ONEWAY);
+    }
 };
 
 IMPLEMENT_META_INTERFACE(DisplayEventConnection, "android.gui.DisplayEventConnection");
@@ -65,6 +80,16 @@
             channel->writeToParcel(reply);
             return NO_ERROR;
         } break;
+        case SET_VSYNC_RATE: {
+            CHECK_INTERFACE(IDisplayEventConnection, data, reply);
+            setVsyncRate(data.readInt32());
+            return NO_ERROR;
+        } break;
+        case REQUEST_NEXT_VSYNC: {
+            CHECK_INTERFACE(IDisplayEventConnection, data, reply);
+            requestNextVsync();
+            return NO_ERROR;
+        } break;
     }
     return BBinder::onTransact(code, data, reply, flags);
 }
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/java/android/media/MediaPlayer.java b/media/java/android/media/MediaPlayer.java
index 8d71dcf..4c70e9d 100644
--- a/media/java/android/media/MediaPlayer.java
+++ b/media/java/android/media/MediaPlayer.java
@@ -1735,6 +1735,9 @@
         /**
          * Called to indicate the video size
          *
+         * The video size (width and height) could be 0 if there was no video,
+         * no display surface was set, or the value was not determined yet.
+         *
          * @param mp        the MediaPlayer associated with this callback
          * @param width     the width of the video
          * @param height    the height of the video
diff --git a/media/libstagefright/AwesomePlayer.cpp b/media/libstagefright/AwesomePlayer.cpp
index 1f225a7..8405264 100644
--- a/media/libstagefright/AwesomePlayer.cpp
+++ b/media/libstagefright/AwesomePlayer.cpp
@@ -1949,6 +1949,8 @@
         mUri = newURI;
     }
 
+    AString sniffedMIME;
+
     if (!strncasecmp("http://", mUri.string(), 7)
             || !strncasecmp("https://", mUri.string(), 8)
             || isWidevineStreaming) {
@@ -1998,7 +2000,6 @@
 
         mConnectingDataSource.clear();
 
-
         String8 contentType = dataSource->getMIMEType();
 
         if (strncasecmp(contentType.string(), "audio/", 6)) {
@@ -2020,16 +2021,51 @@
 
                 mLock.unlock();
 
+                // Initially make sure we have at least 192 KB for the sniff
+                // to complete without blocking.
+                static const size_t kMinBytesForSniffing = 192 * 1024;
+
+                off64_t metaDataSize = -1ll;
                 for (;;) {
                     status_t finalStatus;
                     size_t cachedDataRemaining =
                         mCachedSource->approxDataRemaining(&finalStatus);
 
-                    if (finalStatus != OK || cachedDataRemaining >= kHighWaterMarkBytes
+                    if (finalStatus != OK
+                            || (metaDataSize >= 0
+                                && cachedDataRemaining >= metaDataSize)
                             || (mFlags & PREPARE_CANCELLED)) {
                         break;
                     }
 
+                    ALOGV("now cached %d bytes of data", cachedDataRemaining);
+
+                    if (metaDataSize < 0
+                            && cachedDataRemaining >= kMinBytesForSniffing) {
+                        String8 tmp;
+                        float confidence;
+                        sp<AMessage> meta;
+                        if (!dataSource->sniff(&tmp, &confidence, &meta)) {
+                            mLock.lock();
+                            return UNKNOWN_ERROR;
+                        }
+
+                        // We successfully identified the file's extractor to
+                        // be, remember this mime type so we don't have to
+                        // sniff it again when we call MediaExtractor::Create()
+                        // below.
+                        sniffedMIME = tmp.string();
+
+                        if (meta == NULL
+                                || !meta->findInt64(
+                                    "meta-data-size", &metaDataSize)) {
+                            metaDataSize = kHighWaterMarkBytes;
+                        }
+
+                        CHECK_GE(metaDataSize, 0ll);
+                        ALOGV("metaDataSize = %lld bytes", metaDataSize);
+                    }
+
                     usleep(200000);
                 }
 
@@ -2055,7 +2091,7 @@
         String8 mimeType;
         float confidence;
         sp<AMessage> dummy;
-        bool success = SniffDRM(dataSource, &mimeType, &confidence, &dummy);
+        bool success = SniffWVM(dataSource, &mimeType, &confidence, &dummy);
 
         if (!success
                 || strcasecmp(
@@ -2063,11 +2099,14 @@
             return ERROR_UNSUPPORTED;
         }
 
+        dataSource->DrmInitialization();
+
         mWVMExtractor = new WVMExtractor(dataSource);
         mWVMExtractor->setAdaptiveStreamingMode(true);
         extractor = mWVMExtractor;
     } else {
-        extractor = MediaExtractor::Create(dataSource);
+        extractor = MediaExtractor::Create(
+                dataSource, sniffedMIME.empty() ? NULL : sniffedMIME.c_str());
 
         if (extractor == NULL) {
             return UNKNOWN_ERROR;
diff --git a/media/libstagefright/DRMExtractor.cpp b/media/libstagefright/DRMExtractor.cpp
index 1f3d581..afc4a80 100644
--- a/media/libstagefright/DRMExtractor.cpp
+++ b/media/libstagefright/DRMExtractor.cpp
@@ -282,13 +282,13 @@
     if (decryptHandle != NULL) {
         if (decryptHandle->decryptApiType == DecryptApiType::CONTAINER_BASED) {
             *mimeType = String8("drm+container_based+") + decryptHandle->mimeType;
+            *confidence = 10.0f;
         } else if (decryptHandle->decryptApiType == DecryptApiType::ELEMENTARY_STREAM_BASED) {
             *mimeType = String8("drm+es_based+") + decryptHandle->mimeType;
-        } else if (decryptHandle->decryptApiType == DecryptApiType::WV_BASED) {
-            *mimeType = MEDIA_MIMETYPE_CONTAINER_WVM;
-            LOGW("SniffWVM: found match\n");
+            *confidence = 10.0f;
+        } else {
+            return false;
         }
-        *confidence = 10.0f;
 
         return true;
     }
diff --git a/media/libstagefright/DataSource.cpp b/media/libstagefright/DataSource.cpp
index 70523c1..d0a7880 100644
--- a/media/libstagefright/DataSource.cpp
+++ b/media/libstagefright/DataSource.cpp
@@ -16,6 +16,11 @@
 
 #include "include/AMRExtractor.h"
 #include "include/AVIExtractor.h"
+
+#if CHROMIUM_AVAILABLE
+#include "include/DataUriSource.h"
+#endif
+
 #include "include/MP3Extractor.h"
 #include "include/MPEG4Extractor.h"
 #include "include/WAVExtractor.h"
@@ -27,6 +32,7 @@
 #include "include/DRMExtractor.h"
 #include "include/FLACExtractor.h"
 #include "include/AACExtractor.h"
+#include "include/WVMExtractor.h"
 
 #include "matroska/MatroskaExtractor.h"
 
@@ -115,6 +121,7 @@
     RegisterSniffer(SniffAAC);
     RegisterSniffer(SniffAVI);
     RegisterSniffer(SniffMPEG2PS);
+    RegisterSniffer(SniffWVM);
 
     char value[PROPERTY_VALUE_MAX];
     if (property_get("drm.service.enabled", value, NULL)
@@ -136,6 +143,10 @@
             return NULL;
         }
         source = new NuCachedSource2(httpSource);
+# if CHROMIUM_AVAILABLE
+    } else if (!strncasecmp("data:", uri, 5)) {
+        source = new DataUriSource(uri);
+#endif
     } else {
         // Assume it's a filename.
         source = new FileSource(uri);
diff --git a/media/libstagefright/MPEG4Extractor.cpp b/media/libstagefright/MPEG4Extractor.cpp
index 7b6fa38..0a69df4 100644
--- a/media/libstagefright/MPEG4Extractor.cpp
+++ b/media/libstagefright/MPEG4Extractor.cpp
@@ -30,6 +30,7 @@
 #include <string.h>
 
 #include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/foundation/AMessage.h>
 #include <media/stagefright/DataSource.h>
 #include <media/stagefright/MediaBuffer.h>
 #include <media/stagefright/MediaBufferGroup.h>
@@ -2302,51 +2303,121 @@
 
 // Attempt to actually parse the 'ftyp' atom and determine if a suitable
 // compatible brand is present.
+// Also try to identify where this file's metadata ends
+// (end of the 'moov' atom) and report it to the caller as part of
+// the metadata.
 static bool BetterSniffMPEG4(
-        const sp<DataSource> &source, String8 *mimeType, float *confidence) {
-    uint8_t header[12];
-    if (source->readAt(0, header, 12) != 12
-            || memcmp("ftyp", &header[4], 4)) {
-        return false;
-    }
+        const sp<DataSource> &source, String8 *mimeType, float *confidence,
+        sp<AMessage> *meta) {
+    // We scan up to 128 bytes to identify this file as an MP4.
+    static const off64_t kMaxScanOffset = 128ll;
 
-    size_t atomSize = U32_AT(&header[0]);
-    if (atomSize < 16 || (atomSize % 4) != 0) {
-        return false;
-    }
+    off64_t offset = 0ll;
+    bool foundGoodFileType = false;
+    off64_t moovAtomEndOffset = -1ll;
+    bool done = false;
 
-    bool success = false;
-    if (isCompatibleBrand(U32_AT(&header[8]))) {
-        success = true;
-    } else {
-        size_t numCompatibleBrands = (atomSize - 16) / 4;
-        for (size_t i = 0; i < numCompatibleBrands; ++i) {
-            uint8_t tmp[4];
-            if (source->readAt(16 + i * 4, tmp, 4) != 4) {
+    while (!done && offset < kMaxScanOffset) {
+        uint32_t hdr[2];
+        if (source->readAt(offset, hdr, 8) < 8) {
+            return false;
+        }
+
+        uint64_t chunkSize = ntohl(hdr[0]);
+        uint32_t chunkType = ntohl(hdr[1]);
+        off64_t chunkDataOffset = offset + 8;
+
+        if (chunkSize == 1) {
+            if (source->readAt(offset + 8, &chunkSize, 8) < 8) {
                 return false;
             }
 
-            if (isCompatibleBrand(U32_AT(&tmp[0]))) {
-                success = true;
+            chunkSize = ntoh64(chunkSize);
+            chunkDataOffset += 8;
+
+            if (chunkSize < 16) {
+                // The smallest valid chunk is 16 bytes long in this case.
+                return false;
+            }
+        } else if (chunkSize < 8) {
+            // The smallest valid chunk is 8 bytes long.
+            return false;
+        }
+
+        off64_t chunkDataSize = offset + chunkSize - chunkDataOffset;
+
+        switch (chunkType) {
+            case FOURCC('f', 't', 'y', 'p'):
+            {
+                if (chunkDataSize < 8) {
+                    return false;
+                }
+
+                uint32_t numCompatibleBrands = (chunkDataSize - 8) / 4;
+                for (size_t i = 0; i < numCompatibleBrands + 2; ++i) {
+                    if (i == 1) {
+                        // Skip this index, it refers to the minorVersion,
+                        // not a brand.
+                        continue;
+                    }
+
+                    uint32_t brand;
+                    if (source->readAt(
+                                chunkDataOffset + 4 * i, &brand, 4) < 4) {
+                        return false;
+                    }
+
+                    brand = ntohl(brand);
+
+                    if (isCompatibleBrand(brand)) {
+                        foundGoodFileType = true;
+                        break;
+                    }
+                }
+
+                if (!foundGoodFileType) {
+                    return false;
+                }
+
                 break;
             }
+
+            case FOURCC('m', 'o', 'o', 'v'):
+            {
+                moovAtomEndOffset = offset + chunkSize;
+
+                done = true;
+                break;
+            }
+
+            default:
+                break;
         }
+
+        offset += chunkSize;
     }
 
-    if (!success) {
+    if (!foundGoodFileType) {
         return false;
     }
 
     *mimeType = MEDIA_MIMETYPE_CONTAINER_MPEG4;
     *confidence = 0.4f;
 
+    if (moovAtomEndOffset >= 0) {
+        *meta = new AMessage;
+        (*meta)->setInt64("meta-data-size", moovAtomEndOffset);
+
+        ALOGV("found metadata size: %lld", moovAtomEndOffset);
+    }
+
     return true;
 }
 
 bool SniffMPEG4(
         const sp<DataSource> &source, String8 *mimeType, float *confidence,
-        sp<AMessage> *) {
-    if (BetterSniffMPEG4(source, mimeType, confidence)) {
+        sp<AMessage> *meta) {
+    if (BetterSniffMPEG4(source, mimeType, confidence, meta)) {
         return true;
     }
 
diff --git a/media/libstagefright/WVMExtractor.cpp b/media/libstagefright/WVMExtractor.cpp
index 26eda0c..79dedca 100644
--- a/media/libstagefright/WVMExtractor.cpp
+++ b/media/libstagefright/WVMExtractor.cpp
@@ -45,17 +45,12 @@
 static Mutex gWVMutex;
 
 WVMExtractor::WVMExtractor(const sp<DataSource> &source)
-    : mDataSource(source) {
-    {
-        Mutex::Autolock autoLock(gWVMutex);
-        if (gVendorLibHandle == NULL) {
-            gVendorLibHandle = dlopen("libwvm.so", RTLD_NOW);
-        }
+    : mDataSource(source)
+{
+    Mutex::Autolock autoLock(gWVMutex);
 
-        if (gVendorLibHandle == NULL) {
-            LOGE("Failed to open libwvm.so");
-            return;
-        }
+    if (!getVendorLibHandle()) {
+        return;
     }
 
     typedef WVMLoadableExtractor *(*GetInstanceFunc)(sp<DataSource>);
@@ -71,6 +66,19 @@
     }
 }
 
+bool WVMExtractor::getVendorLibHandle()
+{
+    if (gVendorLibHandle == NULL) {
+        gVendorLibHandle = dlopen("libwvm.so", RTLD_NOW);
+    }
+
+    if (gVendorLibHandle == NULL) {
+        LOGE("Failed to open libwvm.so");
+    }
+
+    return gVendorLibHandle != NULL;
+}
+
 WVMExtractor::~WVMExtractor() {
 }
 
@@ -113,5 +121,33 @@
     }
 }
 
+bool SniffWVM(
+    const sp<DataSource> &source, String8 *mimeType, float *confidence,
+        sp<AMessage> *) {
+
+    Mutex::Autolock autoLock(gWVMutex);
+
+    if (!WVMExtractor::getVendorLibHandle()) {
+        return false;
+    }
+
+    typedef WVMLoadableExtractor *(*SnifferFunc)(sp<DataSource>);
+    SnifferFunc snifferFunc =
+        (SnifferFunc) dlsym(gVendorLibHandle,
+                            "_ZN7android15IsWidevineMediaENS_2spINS_10DataSourceEEE");
+
+    if (snifferFunc) {
+        if ((*snifferFunc)(source)) {
+            *mimeType = MEDIA_MIMETYPE_CONTAINER_WVM;
+            *confidence = 10.0f;
+            return true;
+        }
+    } else {
+        LOGE("IsWidevineMedia not found in libwvm.so");
+    }
+
+    return false;
+}
+
 } //namespace android
 
diff --git a/media/libstagefright/chromium_http/Android.mk b/media/libstagefright/chromium_http/Android.mk
index 6573e3c..63775f1 100644
--- a/media/libstagefright/chromium_http/Android.mk
+++ b/media/libstagefright/chromium_http/Android.mk
@@ -3,8 +3,9 @@
 include $(CLEAR_VARS)
 
 LOCAL_SRC_FILES:=       \
-        ChromiumHTTPDataSource.cpp        \
-        support.cpp                     \
+        DataUriSource.cpp \
+        ChromiumHTTPDataSource.cpp \
+        support.cpp
 
 LOCAL_C_INCLUDES:= \
         $(JNI_H_INCLUDE) \
diff --git a/media/libstagefright/chromium_http/DataUriSource.cpp b/media/libstagefright/chromium_http/DataUriSource.cpp
new file mode 100644
index 0000000..ecf3fa1
--- /dev/null
+++ b/media/libstagefright/chromium_http/DataUriSource.cpp
@@ -0,0 +1,68 @@
+/*
+ * 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.
+ */
+
+#include <include/DataUriSource.h>
+
+#include <net/base/data_url.h>
+#include <googleurl/src/gurl.h>
+
+
+namespace android {
+
+DataUriSource::DataUriSource(const char *uri) :
+    mDataUri(uri),
+    mInited(NO_INIT) {
+
+    // Copy1: const char *uri -> String8 mDataUri.
+    std::string mimeTypeStr, unusedCharsetStr, dataStr;
+    // Copy2: String8 mDataUri -> std::string
+    const bool ret = net::DataURL::Parse(
+            GURL(std::string(mDataUri.string())),
+            &mimeTypeStr, &unusedCharsetStr, &dataStr);
+    // Copy3: std::string dataStr -> AString mData
+    mData.setTo(dataStr.data(), dataStr.length());
+    mInited = ret ? OK : UNKNOWN_ERROR;
+
+    // The chromium data url implementation defaults to using "text/plain"
+    // if no mime type is specified. We prefer to leave this unspecified
+    // instead, since the mime type is sniffed in most cases.
+    if (mimeTypeStr != "text/plain") {
+        mMimeType = mimeTypeStr.c_str();
+    }
+}
+
+ssize_t DataUriSource::readAt(off64_t offset, void *out, size_t size) {
+    if (mInited != OK) {
+        return mInited;
+    }
+
+    const off64_t length = mData.size();
+    if (offset >= length) {
+        return UNKNOWN_ERROR;
+    }
+
+    const char *dataBuf = mData.c_str();
+    const size_t bytesToCopy =
+            offset + size >= length ? (length - offset) : size;
+
+    if (bytesToCopy > 0) {
+        memcpy(out, dataBuf + offset, bytesToCopy);
+    }
+
+    return bytesToCopy;
+}
+
+}  // namespace android
diff --git a/media/libstagefright/include/DataUriSource.h b/media/libstagefright/include/DataUriSource.h
new file mode 100644
index 0000000..d223c06
--- /dev/null
+++ b/media/libstagefright/include/DataUriSource.h
@@ -0,0 +1,76 @@
+/*
+ * 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.
+ */
+
+#ifndef DATA_URI_SOURCE_H_
+
+#define DATA_URI_SOURCE_H_
+
+#include <stdio.h>
+
+#include <media/stagefright/DataSource.h>
+#include <media/stagefright/MediaErrors.h>
+#include <media/stagefright/foundation/AString.h>
+
+namespace android {
+
+class DataUriSource : public DataSource {
+public:
+    DataUriSource(const char *uri);
+
+    virtual status_t initCheck() const {
+        return mInited;
+    }
+
+    virtual ssize_t readAt(off64_t offset, void *data, size_t size);
+
+    virtual status_t getSize(off64_t *size) {
+        if (mInited != OK) {
+            return mInited;
+        }
+
+        *size = mData.size();
+        return OK;
+    }
+
+    virtual String8 getUri() {
+        return mDataUri;
+    }
+
+    virtual String8 getMIMEType() const {
+        return mMimeType;
+    }
+
+protected:
+    virtual ~DataUriSource() {
+        // Nothing to delete.
+    }
+
+private:
+    const String8 mDataUri;
+
+    String8 mMimeType;
+    // Use AString because individual bytes may not be valid UTF8 chars.
+    AString mData;
+    status_t mInited;
+
+    // Disallow copy and assign.
+    DataUriSource(const DataUriSource &);
+    DataUriSource &operator=(const DataUriSource &);
+};
+
+}  // namespace android
+
+#endif  // DATA_URI_SOURCE_H_
diff --git a/media/libstagefright/include/WVMExtractor.h b/media/libstagefright/include/WVMExtractor.h
index deecd25..9f763f9 100644
--- a/media/libstagefright/include/WVMExtractor.h
+++ b/media/libstagefright/include/WVMExtractor.h
@@ -23,6 +23,8 @@
 
 namespace android {
 
+struct AMessage;
+class String8;
 class DataSource;
 
 class WVMLoadableExtractor : public MediaExtractor {
@@ -58,6 +60,8 @@
     // is used.
     void setAdaptiveStreamingMode(bool adaptive);
 
+    static bool getVendorLibHandle();
+
 protected:
     virtual ~WVMExtractor();
 
@@ -69,6 +73,10 @@
     WVMExtractor &operator=(const WVMExtractor &);
 };
 
+bool SniffWVM(
+        const sp<DataSource> &source, String8 *mimeType, float *confidence,
+        sp<AMessage> *);
+
 }  // namespace android
 
 #endif  // DRM_EXTRACTOR_H_
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/audio/MediaEnvReverbTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/audio/MediaEnvReverbTest.java
index 3c8d05a..e788c17 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/audio/MediaEnvReverbTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/audio/MediaEnvReverbTest.java
@@ -353,6 +353,8 @@
         AudioEffect vc = null;
         MediaPlayer mp = null;
         AudioManager am = (AudioManager) getActivity().getSystemService(Context.AUDIO_SERVICE);
+        int ringerMode = am.getRingerMode();
+        am.setRingerMode(AudioManager.RINGER_MODE_NORMAL);
         int volume = am.getStreamMaxVolume(AudioManager.STREAM_MUSIC);
         am.setStreamVolume(AudioManager.STREAM_MUSIC,
                            am.getStreamMaxVolume(AudioManager.STREAM_MUSIC),
@@ -411,6 +413,7 @@
                 probe.release();
             }
             am.setStreamVolume(AudioManager.STREAM_MUSIC, volume, 0);
+            am.setRingerMode(ringerMode);
         }
         assertTrue(msg, result);
     }
@@ -425,6 +428,8 @@
         MediaPlayer mp = null;
         AudioEffect rvb = null;
         AudioManager am = (AudioManager) getActivity().getSystemService(Context.AUDIO_SERVICE);
+        int ringerMode = am.getRingerMode();
+        am.setRingerMode(AudioManager.RINGER_MODE_NORMAL);
         int volume = am.getStreamMaxVolume(AudioManager.STREAM_MUSIC);
         am.setStreamVolume(AudioManager.STREAM_MUSIC,
                            am.getStreamMaxVolume(AudioManager.STREAM_MUSIC),
@@ -495,6 +500,7 @@
                 probe.release();
             }
             am.setStreamVolume(AudioManager.STREAM_MUSIC, volume, 0);
+            am.setRingerMode(ringerMode);
         }
         assertTrue(msg, result);
     }
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/audio/MediaPresetReverbTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/audio/MediaPresetReverbTest.java
index 757bbc5..bc9c48d 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/audio/MediaPresetReverbTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/audio/MediaPresetReverbTest.java
@@ -198,6 +198,8 @@
         AudioEffect vc = null;
         MediaPlayer mp = null;
         AudioManager am = (AudioManager) getActivity().getSystemService(Context.AUDIO_SERVICE);
+        int ringerMode = am.getRingerMode();
+        am.setRingerMode(AudioManager.RINGER_MODE_NORMAL);
         int volume = am.getStreamMaxVolume(AudioManager.STREAM_MUSIC);
         am.setStreamVolume(AudioManager.STREAM_MUSIC,
                            am.getStreamMaxVolume(AudioManager.STREAM_MUSIC),
@@ -254,6 +256,7 @@
                 probe.release();
             }
             am.setStreamVolume(AudioManager.STREAM_MUSIC, volume, 0);
+            am.setRingerMode(ringerMode);
         }
         assertTrue(msg, result);
     }
@@ -268,6 +271,8 @@
         MediaPlayer mp = null;
         AudioEffect rvb = null;
         AudioManager am = (AudioManager) getActivity().getSystemService(Context.AUDIO_SERVICE);
+        int ringerMode = am.getRingerMode();
+        am.setRingerMode(AudioManager.RINGER_MODE_NORMAL);
         int volume = am.getStreamMaxVolume(AudioManager.STREAM_MUSIC);
         am.setStreamVolume(AudioManager.STREAM_MUSIC,
                            am.getStreamMaxVolume(AudioManager.STREAM_MUSIC),
@@ -336,6 +341,7 @@
                 probe.release();
             }
             am.setStreamVolume(AudioManager.STREAM_MUSIC, volume, 0);
+            am.setRingerMode(ringerMode);
         }
         assertTrue(msg, result);
     }
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/audio/MediaVisualizerTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/audio/MediaVisualizerTest.java
index e0cf51d..b0bf654 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/audio/MediaVisualizerTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/audio/MediaVisualizerTest.java
@@ -200,6 +200,8 @@
         AudioEffect vc = null;
         MediaPlayer mp = null;
         AudioManager am = (AudioManager) getActivity().getSystemService(Context.AUDIO_SERVICE);
+        int ringerMode = am.getRingerMode();
+        am.setRingerMode(AudioManager.RINGER_MODE_NORMAL);
         int volume = am.getStreamMaxVolume(AudioManager.STREAM_MUSIC);
         am.setStreamVolume(AudioManager.STREAM_MUSIC,
                            am.getStreamMaxVolume(AudioManager.STREAM_MUSIC),
@@ -264,6 +266,7 @@
                 vc.release();
             }
             am.setStreamVolume(AudioManager.STREAM_MUSIC, volume, 0);
+            am.setRingerMode(ringerMode);
         }
         assertTrue(msg, result);
     }
@@ -276,6 +279,8 @@
         AudioEffect vc = null;
         MediaPlayer mp = null;
         AudioManager am = (AudioManager) getActivity().getSystemService(Context.AUDIO_SERVICE);
+        int ringerMode = am.getRingerMode();
+        am.setRingerMode(AudioManager.RINGER_MODE_NORMAL);
         int volume = am.getStreamMaxVolume(AudioManager.STREAM_MUSIC);
         am.setStreamVolume(AudioManager.STREAM_MUSIC,
                            am.getStreamMaxVolume(AudioManager.STREAM_MUSIC),
@@ -393,6 +398,7 @@
                 vc.release();
             }
             am.setStreamVolume(AudioManager.STREAM_MUSIC, volume, 0);
+            am.setRingerMode(ringerMode);
         }
         assertTrue(msg, result);
     }
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/opengl/libs/ETC1/etc1.cpp b/opengl/libs/ETC1/etc1.cpp
index 5ed2c3c..97d1085 100644
--- a/opengl/libs/ETC1/etc1.cpp
+++ b/opengl/libs/ETC1/etc1.cpp
@@ -149,13 +149,13 @@
 static
 inline int convert8To4(int b) {
     int c = b & 0xff;
-    return divideBy255(b * 15);
+    return divideBy255(c * 15);
 }
 
 static
 inline int convert8To5(int b) {
     int c = b & 0xff;
-    return divideBy255(b * 31);
+    return divideBy255(c * 31);
 }
 
 static
diff --git a/opengl/libs/GLES_trace/gltrace.proto b/opengl/libs/GLES_trace/gltrace.proto
index 59f80e3..12d8e7c 100644
--- a/opengl/libs/GLES_trace/gltrace.proto
+++ b/opengl/libs/GLES_trace/gltrace.proto
@@ -459,7 +459,7 @@
             BYTE = 3;       // GLbyte, GLubyte
             INT = 4;        // GLbitfield, GLshort, GLint, GLsizei, GLushort, GLuint, GLfixed
             FLOAT = 5;      // GLfloat, GLclampf
-            BOOL = 6;    // GLboolean
+            BOOL = 6;       // GLboolean
             ENUM = 7;       // GLenum
         };
 
@@ -473,9 +473,16 @@
         repeated bool   boolValue = 7;
     }
 
+    message FrameBuffer {
+        required int32  width = 1;
+        required int32  height = 2;
+        repeated bytes  contents = 3;
+    }
+
     required int32      context_id = 1;                     // GL context ID
     required Function   function = 2 [default = invalid];   // GL function called
     repeated DataType   args = 3;                           // GL function's arguments
     optional DataType   returnValue = 4;                    // GL function's return value
     optional float      duration = 5;                       // duration of GL call
+    optional FrameBuffer fb = 6;                            // contents of the framebuffer
 };
diff --git a/opengl/libs/GLES_trace/src/gltrace.pb.cpp b/opengl/libs/GLES_trace/src/gltrace.pb.cpp
index 160afbf..6c1bb91 100644
--- a/opengl/libs/GLES_trace/src/gltrace.pb.cpp
+++ b/opengl/libs/GLES_trace/src/gltrace.pb.cpp
@@ -13,6 +13,7 @@
 void protobuf_ShutdownFile_gltrace_2eproto() {
   delete GLMessage::default_instance_;
   delete GLMessage_DataType::default_instance_;
+  delete GLMessage_FrameBuffer::default_instance_;
 }
 
 void protobuf_AddDesc_gltrace_2eproto() {
@@ -23,8 +24,10 @@
 
   GLMessage::default_instance_ = new GLMessage();
   GLMessage_DataType::default_instance_ = new GLMessage_DataType();
+  GLMessage_FrameBuffer::default_instance_ = new GLMessage_FrameBuffer();
   GLMessage::default_instance_->InitAsDefaultInstance();
   GLMessage_DataType::default_instance_->InitAsDefaultInstance();
+  GLMessage_FrameBuffer::default_instance_->InitAsDefaultInstance();
   ::google::protobuf::internal::OnShutdown(&protobuf_ShutdownFile_gltrace_2eproto);
 }
 
@@ -1306,11 +1309,238 @@
 // -------------------------------------------------------------------
 
 #ifndef _MSC_VER
+const int GLMessage_FrameBuffer::kWidthFieldNumber;
+const int GLMessage_FrameBuffer::kHeightFieldNumber;
+const int GLMessage_FrameBuffer::kContentsFieldNumber;
+#endif  // !_MSC_VER
+
+GLMessage_FrameBuffer::GLMessage_FrameBuffer()
+  : ::google::protobuf::MessageLite() {
+  SharedCtor();
+}
+
+void GLMessage_FrameBuffer::InitAsDefaultInstance() {
+}
+
+GLMessage_FrameBuffer::GLMessage_FrameBuffer(const GLMessage_FrameBuffer& from)
+  : ::google::protobuf::MessageLite() {
+  SharedCtor();
+  MergeFrom(from);
+}
+
+void GLMessage_FrameBuffer::SharedCtor() {
+  _cached_size_ = 0;
+  width_ = 0;
+  height_ = 0;
+  ::memset(_has_bits_, 0, sizeof(_has_bits_));
+}
+
+GLMessage_FrameBuffer::~GLMessage_FrameBuffer() {
+  SharedDtor();
+}
+
+void GLMessage_FrameBuffer::SharedDtor() {
+  if (this != default_instance_) {
+  }
+}
+
+void GLMessage_FrameBuffer::SetCachedSize(int size) const {
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+}
+const GLMessage_FrameBuffer& GLMessage_FrameBuffer::default_instance() {
+  if (default_instance_ == NULL) protobuf_AddDesc_gltrace_2eproto();  return *default_instance_;
+}
+
+GLMessage_FrameBuffer* GLMessage_FrameBuffer::default_instance_ = NULL;
+
+GLMessage_FrameBuffer* GLMessage_FrameBuffer::New() const {
+  return new GLMessage_FrameBuffer;
+}
+
+void GLMessage_FrameBuffer::Clear() {
+  if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) {
+    width_ = 0;
+    height_ = 0;
+  }
+  contents_.Clear();
+  ::memset(_has_bits_, 0, sizeof(_has_bits_));
+}
+
+bool GLMessage_FrameBuffer::MergePartialFromCodedStream(
+    ::google::protobuf::io::CodedInputStream* input) {
+#define DO_(EXPRESSION) if (!(EXPRESSION)) return false
+  ::google::protobuf::uint32 tag;
+  while ((tag = input->ReadTag()) != 0) {
+    switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) {
+      // required int32 width = 1;
+      case 1: {
+        if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+            ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) {
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   ::google::protobuf::int32, ::google::protobuf::internal::WireFormatLite::TYPE_INT32>(
+                 input, &width_)));
+          _set_bit(0);
+        } else {
+          goto handle_uninterpreted;
+        }
+        if (input->ExpectTag(16)) goto parse_height;
+        break;
+      }
+      
+      // required int32 height = 2;
+      case 2: {
+        if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+            ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) {
+         parse_height:
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   ::google::protobuf::int32, ::google::protobuf::internal::WireFormatLite::TYPE_INT32>(
+                 input, &height_)));
+          _set_bit(1);
+        } else {
+          goto handle_uninterpreted;
+        }
+        if (input->ExpectTag(26)) goto parse_contents;
+        break;
+      }
+      
+      // repeated bytes contents = 3;
+      case 3: {
+        if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+            ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) {
+         parse_contents:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadBytes(
+                input, this->add_contents()));
+        } else {
+          goto handle_uninterpreted;
+        }
+        if (input->ExpectTag(26)) goto parse_contents;
+        if (input->ExpectAtEnd()) return true;
+        break;
+      }
+      
+      default: {
+      handle_uninterpreted:
+        if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+            ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) {
+          return true;
+        }
+        DO_(::google::protobuf::internal::WireFormatLite::SkipField(input, tag));
+        break;
+      }
+    }
+  }
+  return true;
+#undef DO_
+}
+
+void GLMessage_FrameBuffer::SerializeWithCachedSizes(
+    ::google::protobuf::io::CodedOutputStream* output) const {
+  // required int32 width = 1;
+  if (_has_bit(0)) {
+    ::google::protobuf::internal::WireFormatLite::WriteInt32(1, this->width(), output);
+  }
+  
+  // required int32 height = 2;
+  if (_has_bit(1)) {
+    ::google::protobuf::internal::WireFormatLite::WriteInt32(2, this->height(), output);
+  }
+  
+  // repeated bytes contents = 3;
+  for (int i = 0; i < this->contents_size(); i++) {
+    ::google::protobuf::internal::WireFormatLite::WriteBytes(
+      3, this->contents(i), output);
+  }
+  
+}
+
+int GLMessage_FrameBuffer::ByteSize() const {
+  int total_size = 0;
+  
+  if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) {
+    // required int32 width = 1;
+    if (has_width()) {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::Int32Size(
+          this->width());
+    }
+    
+    // required int32 height = 2;
+    if (has_height()) {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::Int32Size(
+          this->height());
+    }
+    
+  }
+  // repeated bytes contents = 3;
+  total_size += 1 * this->contents_size();
+  for (int i = 0; i < this->contents_size(); i++) {
+    total_size += ::google::protobuf::internal::WireFormatLite::BytesSize(
+      this->contents(i));
+  }
+  
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = total_size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+  return total_size;
+}
+
+void GLMessage_FrameBuffer::CheckTypeAndMergeFrom(
+    const ::google::protobuf::MessageLite& from) {
+  MergeFrom(*::google::protobuf::down_cast<const GLMessage_FrameBuffer*>(&from));
+}
+
+void GLMessage_FrameBuffer::MergeFrom(const GLMessage_FrameBuffer& from) {
+  GOOGLE_CHECK_NE(&from, this);
+  contents_.MergeFrom(from.contents_);
+  if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) {
+    if (from._has_bit(0)) {
+      set_width(from.width());
+    }
+    if (from._has_bit(1)) {
+      set_height(from.height());
+    }
+  }
+}
+
+void GLMessage_FrameBuffer::CopyFrom(const GLMessage_FrameBuffer& from) {
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+bool GLMessage_FrameBuffer::IsInitialized() const {
+  if ((_has_bits_[0] & 0x00000003) != 0x00000003) return false;
+  
+  return true;
+}
+
+void GLMessage_FrameBuffer::Swap(GLMessage_FrameBuffer* other) {
+  if (other != this) {
+    std::swap(width_, other->width_);
+    std::swap(height_, other->height_);
+    contents_.Swap(&other->contents_);
+    std::swap(_has_bits_[0], other->_has_bits_[0]);
+    std::swap(_cached_size_, other->_cached_size_);
+  }
+}
+
+::std::string GLMessage_FrameBuffer::GetTypeName() const {
+  return "android.gltrace.GLMessage.FrameBuffer";
+}
+
+
+// -------------------------------------------------------------------
+
+#ifndef _MSC_VER
 const int GLMessage::kContextIdFieldNumber;
 const int GLMessage::kFunctionFieldNumber;
 const int GLMessage::kArgsFieldNumber;
 const int GLMessage::kReturnValueFieldNumber;
 const int GLMessage::kDurationFieldNumber;
+const int GLMessage::kFbFieldNumber;
 #endif  // !_MSC_VER
 
 GLMessage::GLMessage()
@@ -1320,6 +1550,7 @@
 
 void GLMessage::InitAsDefaultInstance() {
   returnvalue_ = const_cast< ::android::gltrace::GLMessage_DataType*>(&::android::gltrace::GLMessage_DataType::default_instance());
+  fb_ = const_cast< ::android::gltrace::GLMessage_FrameBuffer*>(&::android::gltrace::GLMessage_FrameBuffer::default_instance());
 }
 
 GLMessage::GLMessage(const GLMessage& from)
@@ -1334,6 +1565,7 @@
   function_ = 3000;
   returnvalue_ = NULL;
   duration_ = 0;
+  fb_ = NULL;
   ::memset(_has_bits_, 0, sizeof(_has_bits_));
 }
 
@@ -1344,6 +1576,7 @@
 void GLMessage::SharedDtor() {
   if (this != default_instance_) {
     delete returnvalue_;
+    delete fb_;
   }
 }
 
@@ -1370,6 +1603,9 @@
       if (returnvalue_ != NULL) returnvalue_->::android::gltrace::GLMessage_DataType::Clear();
     }
     duration_ = 0;
+    if (_has_bit(5)) {
+      if (fb_ != NULL) fb_->::android::gltrace::GLMessage_FrameBuffer::Clear();
+    }
   }
   args_.Clear();
   ::memset(_has_bits_, 0, sizeof(_has_bits_));
@@ -1456,6 +1692,20 @@
         } else {
           goto handle_uninterpreted;
         }
+        if (input->ExpectTag(50)) goto parse_fb;
+        break;
+      }
+      
+      // optional .android.gltrace.GLMessage.FrameBuffer fb = 6;
+      case 6: {
+        if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+            ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) {
+         parse_fb:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
+               input, mutable_fb()));
+        } else {
+          goto handle_uninterpreted;
+        }
         if (input->ExpectAtEnd()) return true;
         break;
       }
@@ -1505,6 +1755,12 @@
     ::google::protobuf::internal::WireFormatLite::WriteFloat(5, this->duration(), output);
   }
   
+  // optional .android.gltrace.GLMessage.FrameBuffer fb = 6;
+  if (_has_bit(5)) {
+    ::google::protobuf::internal::WireFormatLite::WriteMessage(
+      6, this->fb(), output);
+  }
+  
 }
 
 int GLMessage::ByteSize() const {
@@ -1536,6 +1792,13 @@
       total_size += 1 + 4;
     }
     
+    // optional .android.gltrace.GLMessage.FrameBuffer fb = 6;
+    if (has_fb()) {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
+          this->fb());
+    }
+    
   }
   // repeated .android.gltrace.GLMessage.DataType args = 3;
   total_size += 1 * this->args_size();
@@ -1572,6 +1835,9 @@
     if (from._has_bit(4)) {
       set_duration(from.duration());
     }
+    if (from._has_bit(5)) {
+      mutable_fb()->::android::gltrace::GLMessage_FrameBuffer::MergeFrom(from.fb());
+    }
   }
 }
 
@@ -1590,6 +1856,9 @@
   if (has_returnvalue()) {
     if (!this->returnvalue().IsInitialized()) return false;
   }
+  if (has_fb()) {
+    if (!this->fb().IsInitialized()) return false;
+  }
   return true;
 }
 
@@ -1600,6 +1869,7 @@
     args_.Swap(&other->args_);
     std::swap(returnvalue_, other->returnvalue_);
     std::swap(duration_, other->duration_);
+    std::swap(fb_, other->fb_);
     std::swap(_has_bits_[0], other->_has_bits_[0]);
     std::swap(_cached_size_, other->_cached_size_);
   }
diff --git a/opengl/libs/GLES_trace/src/gltrace.pb.h b/opengl/libs/GLES_trace/src/gltrace.pb.h
index be5ca2a..c39e1b2 100644
--- a/opengl/libs/GLES_trace/src/gltrace.pb.h
+++ b/opengl/libs/GLES_trace/src/gltrace.pb.h
@@ -34,6 +34,7 @@
 
 class GLMessage;
 class GLMessage_DataType;
+class GLMessage_FrameBuffer;
 
 enum GLMessage_DataType_Type {
   GLMessage_DataType_Type_VOID = 1,
@@ -658,6 +659,108 @@
 };
 // -------------------------------------------------------------------
 
+class GLMessage_FrameBuffer : public ::google::protobuf::MessageLite {
+ public:
+  GLMessage_FrameBuffer();
+  virtual ~GLMessage_FrameBuffer();
+  
+  GLMessage_FrameBuffer(const GLMessage_FrameBuffer& from);
+  
+  inline GLMessage_FrameBuffer& operator=(const GLMessage_FrameBuffer& from) {
+    CopyFrom(from);
+    return *this;
+  }
+  
+  static const GLMessage_FrameBuffer& default_instance();
+  
+  void Swap(GLMessage_FrameBuffer* other);
+  
+  // implements Message ----------------------------------------------
+  
+  GLMessage_FrameBuffer* New() const;
+  void CheckTypeAndMergeFrom(const ::google::protobuf::MessageLite& from);
+  void CopyFrom(const GLMessage_FrameBuffer& from);
+  void MergeFrom(const GLMessage_FrameBuffer& from);
+  void Clear();
+  bool IsInitialized() const;
+  
+  int ByteSize() const;
+  bool MergePartialFromCodedStream(
+      ::google::protobuf::io::CodedInputStream* input);
+  void SerializeWithCachedSizes(
+      ::google::protobuf::io::CodedOutputStream* output) const;
+  int GetCachedSize() const { return _cached_size_; }
+  private:
+  void SharedCtor();
+  void SharedDtor();
+  void SetCachedSize(int size) const;
+  public:
+  
+  ::std::string GetTypeName() const;
+  
+  // nested types ----------------------------------------------------
+  
+  // accessors -------------------------------------------------------
+  
+  // required int32 width = 1;
+  inline bool has_width() const;
+  inline void clear_width();
+  static const int kWidthFieldNumber = 1;
+  inline ::google::protobuf::int32 width() const;
+  inline void set_width(::google::protobuf::int32 value);
+  
+  // required int32 height = 2;
+  inline bool has_height() const;
+  inline void clear_height();
+  static const int kHeightFieldNumber = 2;
+  inline ::google::protobuf::int32 height() const;
+  inline void set_height(::google::protobuf::int32 value);
+  
+  // repeated bytes contents = 3;
+  inline int contents_size() const;
+  inline void clear_contents();
+  static const int kContentsFieldNumber = 3;
+  inline const ::std::string& contents(int index) const;
+  inline ::std::string* mutable_contents(int index);
+  inline void set_contents(int index, const ::std::string& value);
+  inline void set_contents(int index, const char* value);
+  inline void set_contents(int index, const void* value, size_t size);
+  inline ::std::string* add_contents();
+  inline void add_contents(const ::std::string& value);
+  inline void add_contents(const char* value);
+  inline void add_contents(const void* value, size_t size);
+  inline const ::google::protobuf::RepeatedPtrField< ::std::string>& contents() const;
+  inline ::google::protobuf::RepeatedPtrField< ::std::string>* mutable_contents();
+  
+  // @@protoc_insertion_point(class_scope:android.gltrace.GLMessage.FrameBuffer)
+ private:
+  mutable int _cached_size_;
+  
+  ::google::protobuf::int32 width_;
+  ::google::protobuf::int32 height_;
+  ::google::protobuf::RepeatedPtrField< ::std::string> contents_;
+  friend void  protobuf_AddDesc_gltrace_2eproto();
+  friend void protobuf_AssignDesc_gltrace_2eproto();
+  friend void protobuf_ShutdownFile_gltrace_2eproto();
+  
+  ::google::protobuf::uint32 _has_bits_[(3 + 31) / 32];
+  
+  // WHY DOES & HAVE LOWER PRECEDENCE THAN != !?
+  inline bool _has_bit(int index) const {
+    return (_has_bits_[index / 32] & (1u << (index % 32))) != 0;
+  }
+  inline void _set_bit(int index) {
+    _has_bits_[index / 32] |= (1u << (index % 32));
+  }
+  inline void _clear_bit(int index) {
+    _has_bits_[index / 32] &= ~(1u << (index % 32));
+  }
+  
+  void InitAsDefaultInstance();
+  static GLMessage_FrameBuffer* default_instance_;
+};
+// -------------------------------------------------------------------
+
 class GLMessage : public ::google::protobuf::MessageLite {
  public:
   GLMessage();
@@ -700,6 +803,7 @@
   // nested types ----------------------------------------------------
   
   typedef GLMessage_DataType DataType;
+  typedef GLMessage_FrameBuffer FrameBuffer;
   
   typedef GLMessage_Function Function;
   static const Function glActiveTexture = GLMessage_Function_glActiveTexture;
@@ -1178,6 +1282,13 @@
   inline float duration() const;
   inline void set_duration(float value);
   
+  // optional .android.gltrace.GLMessage.FrameBuffer fb = 6;
+  inline bool has_fb() const;
+  inline void clear_fb();
+  static const int kFbFieldNumber = 6;
+  inline const ::android::gltrace::GLMessage_FrameBuffer& fb() const;
+  inline ::android::gltrace::GLMessage_FrameBuffer* mutable_fb();
+  
   // @@protoc_insertion_point(class_scope:android.gltrace.GLMessage)
  private:
   mutable int _cached_size_;
@@ -1187,11 +1298,12 @@
   ::google::protobuf::RepeatedPtrField< ::android::gltrace::GLMessage_DataType > args_;
   ::android::gltrace::GLMessage_DataType* returnvalue_;
   float duration_;
+  ::android::gltrace::GLMessage_FrameBuffer* fb_;
   friend void  protobuf_AddDesc_gltrace_2eproto();
   friend void protobuf_AssignDesc_gltrace_2eproto();
   friend void protobuf_ShutdownFile_gltrace_2eproto();
   
-  ::google::protobuf::uint32 _has_bits_[(5 + 31) / 32];
+  ::google::protobuf::uint32 _has_bits_[(6 + 31) / 32];
   
   // WHY DOES & HAVE LOWER PRECEDENCE THAN != !?
   inline bool _has_bit(int index) const {
@@ -1412,6 +1524,86 @@
 
 // -------------------------------------------------------------------
 
+// GLMessage_FrameBuffer
+
+// required int32 width = 1;
+inline bool GLMessage_FrameBuffer::has_width() const {
+  return _has_bit(0);
+}
+inline void GLMessage_FrameBuffer::clear_width() {
+  width_ = 0;
+  _clear_bit(0);
+}
+inline ::google::protobuf::int32 GLMessage_FrameBuffer::width() const {
+  return width_;
+}
+inline void GLMessage_FrameBuffer::set_width(::google::protobuf::int32 value) {
+  _set_bit(0);
+  width_ = value;
+}
+
+// required int32 height = 2;
+inline bool GLMessage_FrameBuffer::has_height() const {
+  return _has_bit(1);
+}
+inline void GLMessage_FrameBuffer::clear_height() {
+  height_ = 0;
+  _clear_bit(1);
+}
+inline ::google::protobuf::int32 GLMessage_FrameBuffer::height() const {
+  return height_;
+}
+inline void GLMessage_FrameBuffer::set_height(::google::protobuf::int32 value) {
+  _set_bit(1);
+  height_ = value;
+}
+
+// repeated bytes contents = 3;
+inline int GLMessage_FrameBuffer::contents_size() const {
+  return contents_.size();
+}
+inline void GLMessage_FrameBuffer::clear_contents() {
+  contents_.Clear();
+}
+inline const ::std::string& GLMessage_FrameBuffer::contents(int index) const {
+  return contents_.Get(index);
+}
+inline ::std::string* GLMessage_FrameBuffer::mutable_contents(int index) {
+  return contents_.Mutable(index);
+}
+inline void GLMessage_FrameBuffer::set_contents(int index, const ::std::string& value) {
+  contents_.Mutable(index)->assign(value);
+}
+inline void GLMessage_FrameBuffer::set_contents(int index, const char* value) {
+  contents_.Mutable(index)->assign(value);
+}
+inline void GLMessage_FrameBuffer::set_contents(int index, const void* value, size_t size) {
+  contents_.Mutable(index)->assign(
+    reinterpret_cast<const char*>(value), size);
+}
+inline ::std::string* GLMessage_FrameBuffer::add_contents() {
+  return contents_.Add();
+}
+inline void GLMessage_FrameBuffer::add_contents(const ::std::string& value) {
+  contents_.Add()->assign(value);
+}
+inline void GLMessage_FrameBuffer::add_contents(const char* value) {
+  contents_.Add()->assign(value);
+}
+inline void GLMessage_FrameBuffer::add_contents(const void* value, size_t size) {
+  contents_.Add()->assign(reinterpret_cast<const char*>(value), size);
+}
+inline const ::google::protobuf::RepeatedPtrField< ::std::string>&
+GLMessage_FrameBuffer::contents() const {
+  return contents_;
+}
+inline ::google::protobuf::RepeatedPtrField< ::std::string>*
+GLMessage_FrameBuffer::mutable_contents() {
+  return &contents_;
+}
+
+// -------------------------------------------------------------------
+
 // GLMessage
 
 // required int32 context_id = 1;
@@ -1505,6 +1697,23 @@
   duration_ = value;
 }
 
+// optional .android.gltrace.GLMessage.FrameBuffer fb = 6;
+inline bool GLMessage::has_fb() const {
+  return _has_bit(5);
+}
+inline void GLMessage::clear_fb() {
+  if (fb_ != NULL) fb_->::android::gltrace::GLMessage_FrameBuffer::Clear();
+  _clear_bit(5);
+}
+inline const ::android::gltrace::GLMessage_FrameBuffer& GLMessage::fb() const {
+  return fb_ != NULL ? *fb_ : *default_instance_->fb_;
+}
+inline ::android::gltrace::GLMessage_FrameBuffer* GLMessage::mutable_fb() {
+  _set_bit(5);
+  if (fb_ == NULL) fb_ = new ::android::gltrace::GLMessage_FrameBuffer;
+  return fb_;
+}
+
 
 // @@protoc_insertion_point(namespace_scope)
 
diff --git a/opengl/libs/GLES_trace/src/gltrace_fixup.cpp b/opengl/libs/GLES_trace/src/gltrace_fixup.cpp
index 90021f4..c5b0451 100644
--- a/opengl/libs/GLES_trace/src/gltrace_fixup.cpp
+++ b/opengl/libs/GLES_trace/src/gltrace_fixup.cpp
@@ -95,20 +95,16 @@
     }
 }
 
-/* Add the contents of the framebuffer as an argument */
+/* Add the contents of the framebuffer to the protobuf message */
 void fixup_addFBContents(GLMessage *glmsg) {
-    GLMessage_DataType *arg_fb = glmsg->add_args();    /* Add the FB as the last argument */
-    GLTraceContext *glContext = getGLTraceContext();
-
-    void *fb;
+    void *fbcontents;
     unsigned fbsize, fbwidth, fbheight;
-    glContext->getCompressedFB(&fb, &fbsize, &fbwidth, &fbheight);
+    getGLTraceContext()->getCompressedFB(&fbcontents, &fbsize, &fbwidth, &fbheight);
 
-    arg_fb->set_isarray(true);
-    arg_fb->set_type(GLMessage::DataType::BYTE);
-    arg_fb->add_rawbytes(fb, fbsize);
-    arg_fb->add_intvalue(fbwidth);
-    arg_fb->add_intvalue(fbheight);
+    GLMessage_FrameBuffer *fb = glmsg->mutable_fb();
+    fb->set_width(fbwidth);
+    fb->set_height(fbheight);
+    fb->add_contents(fbcontents, fbsize);
 }
 
 void fixup_glTexImage2D(GLMessage *glmsg) {
diff --git a/packages/SettingsProvider/res/values/defaults.xml b/packages/SettingsProvider/res/values/defaults.xml
index 7a98615..4ea2c31 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. -->
@@ -112,6 +115,11 @@
             0x200000038=0x03000701:0x03010701:0x03020701;
     </string>
 
+    <!-- Default for Settings.Secure.ACCESSIBILITY_SCRIPT_INJECTION_URL -->
+    <string name="def_accessibility_screen_reader_url" translatable="false">
+        https://ssl.gstatic.com/accessibility/javascript/android/AndroidScriptChooser.user.js
+    </string>
+
     <!-- Default for Settings.Secure.TOUCH_EXPLORATION_ENABLED -->
     <bool name="def_touch_exploration_enabled">false</bool>
 
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
index 080d345..a6a3303 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 = 74;
 
     private Context mContext;
 
@@ -952,6 +952,56 @@
             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;
+        }
+
+        if (upgradeVersion == 73) {
+            // URL from which WebView loads a JavaScript based screen-reader.
+            db.beginTransaction();
+            SQLiteStatement stmt = null;
+            try {
+                stmt = db.compileStatement("INSERT INTO secure(name,value) VALUES(?,?);");
+                loadStringSetting(stmt, Settings.Secure.ACCESSIBILITY_SCREEN_READER_URL,
+                        R.string.def_accessibility_screen_reader_url);
+                db.setTransactionSuccessful();
+            } finally {
+                db.endTransaction();
+                if (stmt != null) stmt.close();
+            }
+            upgradeVersion = 74;
+        }
+
         // *** Remember to update DATABASE_VERSION above!
 
         if (upgradeVersion != currentVersion) {
@@ -1151,8 +1201,7 @@
                     intent.setComponent(cn);
                     title = info.loadLabel(packageManager).toString();
                 } else if (category != null) {
-                    intent = new Intent(Intent.ACTION_MAIN, null);
-                    intent.addCategory(category);
+                    intent = Intent.makeMainSelectorActivity(Intent.ACTION_MAIN, category);
                     title = "";
                 } else {
                     Log.w(TAG, "Unable to add bookmark for shortcut " + shortcutStr
@@ -1490,6 +1539,12 @@
 
             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);
+
+            loadStringSetting(stmt, Settings.Secure.ACCESSIBILITY_SCREEN_READER_URL,
+                    R.string.def_accessibility_screen_reader_url);
         } 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/res/layout-sw600dp/status_bar_ticker_panel.xml b/packages/SystemUI/res/layout-sw600dp/status_bar_ticker_panel.xml
index 6cd8899..d51f9c8 100644
--- a/packages/SystemUI/res/layout-sw600dp/status_bar_ticker_panel.xml
+++ b/packages/SystemUI/res/layout-sw600dp/status_bar_ticker_panel.xml
@@ -15,20 +15,29 @@
  * limitations under the License.
 -->
 
-<LinearLayout
+<RelativeLayout
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
-    android:orientation="horizontal"
-    android:gravity="bottom"
     >
 
+    <View
+        android:layout_height="@*android:dimen/status_bar_height"
+        android:layout_width="match_parent"
+        android:background="@drawable/status_bar_ticker_background"
+        android:layout_alignParentLeft="true"
+        android:layout_alignParentBottom="true"
+        android:clickable="false"
+        />
+
     <ImageView
         android:id="@+id/large_icon"
         android:layout_width="@android:dimen/notification_large_icon_height"
         android:layout_height="@android:dimen/notification_large_icon_width"
         android:scaleType="center"
         android:visibility="gone"
+        android:layout_alignParentLeft="true"
+        android:layout_alignParentBottom="true"
         />
 
     <FrameLayout
@@ -36,6 +45,8 @@
         android:layout_weight="1"
         android:layout_height="@*android:dimen/status_bar_height"
         android:layout_width="match_parent"
-        android:background="@drawable/status_bar_ticker_background"
+        android:layout_toRightOf="@id/large_icon"
+        android:layout_alignParentBottom="true"
+        android:layout_alignWithParentIfMissing="true"
         />
-</LinearLayout>
+</RelativeLayout>
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 c69a145..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);
@@ -973,7 +976,7 @@
             } catch (NameNotFoundException ex) {
                 Slog.e(TAG, "Failed looking up ApplicationInfo for " + sbn.pkg, ex);
             }
-            if (version > 0 && version < Build.VERSION_CODES.HONEYCOMB) {
+            if (version > 0 && version < Build.VERSION_CODES.GINGERBREAD) {
                 content.setBackgroundResource(R.drawable.notification_row_legacy_bg);
             } else {
                 content.setBackgroundResource(R.drawable.notification_row_bg);
@@ -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/policy/BluetoothController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothController.java
index 903a300..603808e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothController.java
@@ -36,7 +36,7 @@
 
     private int mIconId = R.drawable.stat_sys_data_bluetooth;
     private int mContentDescriptionId = 0;
-    private boolean mEnabled;
+    private boolean mEnabled = false;
 
     public BluetoothController(Context context) {
         mContext = context;
@@ -47,8 +47,10 @@
         context.registerReceiver(this, filter);
 
         final BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
-        handleAdapterStateChange(adapter.getState());
-        handleConnectionStateChange(adapter.getConnectionState());
+        if (adapter != null) {
+            handleAdapterStateChange(adapter.getState());
+            handleConnectionStateChange(adapter.getConnectionState());
+        }
         refreshViews();
     }
 
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 757ce0c..9919d825 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;
@@ -168,7 +170,6 @@
     NetworkController mNetworkController;
 
     ViewGroup mBarContents;
-    LayoutTransition mBarContentsLayoutTransition;
 
     // hide system chrome ("lights out") support
     View mShadow;
@@ -194,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() {
@@ -311,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),
@@ -335,6 +337,7 @@
 
         WindowManagerImpl.getDefault().addView(mRecentsPanel, lp);
         mRecentsPanel.setBar(this);
+        mRecentsPanel.setStatusBarView(mStatusBarView);
 
         // Input methods Panel
         mInputMethodsPanel = (InputMethodsPanel) View.inflate(context,
@@ -343,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,
@@ -366,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,
@@ -432,6 +435,10 @@
         }
     }
 
+    public View getStatusBarView() {
+        return mStatusBarView;
+    }
+
     protected View makeStatusBarView() {
         final Context context = mContext;
 
@@ -461,19 +468,6 @@
         }
 
         mBarContents = (ViewGroup) sb.findViewById(R.id.bar_contents);
-        // layout transitions for the status bar's contents
-        mBarContentsLayoutTransition = new LayoutTransition();
-        // add/removal will fade as normal
-        mBarContentsLayoutTransition.setAnimator(LayoutTransition.APPEARING,
-                ObjectAnimator.ofFloat(null, "alpha", 0f, 1f));
-        mBarContentsLayoutTransition.setAnimator(LayoutTransition.DISAPPEARING,
-                ObjectAnimator.ofFloat(null, "alpha", 1f, 0f));
-        // no animations for siblings on change: just jump into place please
-        mBarContentsLayoutTransition.setAnimator(LayoutTransition.CHANGE_APPEARING, null);
-        mBarContentsLayoutTransition.setAnimator(LayoutTransition.CHANGE_DISAPPEARING, null);
-        // quick like bunny
-        mBarContentsLayoutTransition.setDuration(250 * (DEBUG?10:1));
-        mBarContents.setLayoutTransition(mBarContentsLayoutTransition);
 
         // the whole right-hand side of the bar
         mNotificationArea = sb.findViewById(R.id.notificationArea);
@@ -522,7 +516,23 @@
         mMenuButton = mNavigationArea.findViewById(R.id.menu);
         mRecentButton = mNavigationArea.findViewById(R.id.recent_apps);
         mRecentButton.setOnClickListener(mOnClickListener);
-        mNavigationArea.setLayoutTransition(mBarContentsLayoutTransition);
+
+        LayoutTransition lt = new LayoutTransition();
+        lt.setDuration(250);
+        // don't wait for these transitions; we just want icons to fade in/out, not move around
+        lt.setDuration(LayoutTransition.CHANGE_APPEARING, 0);
+        lt.setDuration(LayoutTransition.CHANGE_DISAPPEARING, 0);
+        lt.addTransitionListener(new LayoutTransition.TransitionListener() {
+            public void endTransition(LayoutTransition transition, ViewGroup container,
+                    View view, int transitionType) {
+                // ensure the menu button doesn't stick around on the status bar after it's been
+                // removed
+                mBarContents.invalidate();
+            }
+            public void startTransition(LayoutTransition transition, ViewGroup container,
+                    View view, int transitionType) {}
+        });
+        mNavigationArea.setLayoutTransition(lt);
         // no multi-touch on the nav buttons
         mNavigationArea.setMotionEventSplittingEnabled(false);
 
@@ -1090,6 +1100,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);
@@ -1193,24 +1228,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);
@@ -1218,6 +1244,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
@@ -1836,7 +1870,7 @@
             } catch (NameNotFoundException ex) {
                 Slog.e(TAG, "Failed looking up ApplicationInfo for " + sbn.pkg, ex);
             }
-            if (version > 0 && version < Build.VERSION_CODES.HONEYCOMB) {
+            if (version > 0 && version < Build.VERSION_CODES.GINGERBREAD) {
                 content.setBackgroundResource(R.drawable.notification_row_legacy_bg);
             } else {
                 content.setBackgroundResource(R.drawable.notification_row_bg);
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/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletTicker.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletTicker.java
index 6045e31..e93a32b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletTicker.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletTicker.java
@@ -73,6 +73,8 @@
     private StatusBarNotification[] mQueue = new StatusBarNotification[QUEUE_LENGTH];
     private int mQueuePos;
 
+    private final int mLargeIconHeight;
+
     private TabletStatusBar mBar;
 
     private LayoutTransition mLayoutTransition;
@@ -81,6 +83,9 @@
     public TabletTicker(TabletStatusBar bar) {
         mBar = bar;
         mContext = bar.getContext();
+        final Resources res = mContext.getResources();
+        mLargeIconHeight = res.getDimensionPixelSize(
+                android.R.dimen.notification_large_icon_height);
     }
 
     public void add(IBinder key, StatusBarNotification notification) {
@@ -209,8 +214,6 @@
         final Resources res = mContext.getResources();
         final FrameLayout view = new FrameLayout(mContext);
         final int width = res.getDimensionPixelSize(R.dimen.notification_ticker_width);
-        final int height = res.getDimensionPixelSize(
-                android.R.dimen.notification_large_icon_height);
         int windowFlags = WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
                     | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
                     | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS;
@@ -219,7 +222,7 @@
         } else {
             windowFlags |= WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
         }
-        WindowManager.LayoutParams lp = new WindowManager.LayoutParams(width, height,
+        WindowManager.LayoutParams lp = new WindowManager.LayoutParams(width, mLargeIconHeight,
                 WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL, windowFlags,
                 PixelFormat.TRANSLUCENT);
         lp.gravity = Gravity.BOTTOM | Gravity.RIGHT;
@@ -297,6 +300,16 @@
         if (n.largeIcon != null) {
             largeIcon.setImageBitmap(n.largeIcon);
             largeIcon.setVisibility(View.VISIBLE);
+            final ViewGroup.LayoutParams lp = largeIcon.getLayoutParams();
+            final int statusBarHeight = mBar.getStatusBarHeight();
+            if (n.largeIcon.getHeight() <= statusBarHeight) {
+                // for smallish largeIcons, it looks a little odd to have them floating halfway up
+                // the ticker, so we vertically center them in the status bar area instead
+                lp.height = statusBarHeight;
+            } else {
+                lp.height = mLargeIconHeight;
+            }
+            largeIcon.setLayoutParams(lp);
         }
 
         if (CLICKABLE_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..38c85bb 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,15 +179,23 @@
                 }
             });
 
+        // 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.getListView().setItemsCanFocus(true);
         dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG);
 
         dialog.setOnDismissListener(this);
@@ -238,8 +206,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 +213,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 +355,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 +432,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 +494,70 @@
         }
     }
 
+    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);
+
+            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 +589,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/IconUtilities.java b/policy/src/com/android/internal/policy/impl/IconUtilities.java
index 4564f90..e997355 100644
--- a/policy/src/com/android/internal/policy/impl/IconUtilities.java
+++ b/policy/src/com/android/internal/policy/impl/IconUtilities.java
@@ -38,6 +38,8 @@
 import android.text.TextPaint;
 import android.util.DisplayMetrics;
 import android.util.Log;
+import android.util.TypedValue;
+import android.view.ContextThemeWrapper;
 import android.content.res.Resources;
 import android.content.Context;
 
@@ -74,9 +76,13 @@
         mIconTextureWidth = mIconTextureHeight = mIconWidth + (int)(blurPx*2);
 
         mBlurPaint.setMaskFilter(new BlurMaskFilter(blurPx, BlurMaskFilter.Blur.NORMAL));
-        mGlowColorPressedPaint.setColor(0xffffc300);
+
+        TypedValue value = new TypedValue();
+        mGlowColorPressedPaint.setColor(context.getTheme().resolveAttribute(
+                android.R.attr.colorPressedHighlight, value, true) ? value.data : 0xffffc300);
         mGlowColorPressedPaint.setMaskFilter(TableMaskFilter.CreateClipTable(0, 30));
-        mGlowColorFocusedPaint.setColor(0xffff8e00);
+        mGlowColorFocusedPaint.setColor(context.getTheme().resolveAttribute(
+                android.R.attr.colorFocusedHighlight, value, true) ? value.data : 0xffff8e00);
         mGlowColorFocusedPaint.setMaskFilter(TableMaskFilter.CreateClipTable(0, 30));
 
         ColorMatrix cm = new ColorMatrix();
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/policy/src/com/android/internal/policy/impl/PhoneWindow.java b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
index af86ae9..535f039 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneWindow.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
@@ -1816,22 +1816,42 @@
 
         @Override
         public boolean dispatchKeyShortcutEvent(KeyEvent ev) {
-            // Perform the shortcut (mPreparedPanel can be null since
-            // global shortcuts (such as search) don't rely on a
-            // prepared panel or menu).
-            boolean handled = performPanelShortcut(mPreparedPanel, ev.getKeyCode(), ev,
-                    Menu.FLAG_PERFORM_NO_CLOSE);
-            if (handled) {
-                if (mPreparedPanel != null) {
-                    mPreparedPanel.isHandled = true;
+            // If the panel is already prepared, then perform the shortcut using it.
+            boolean handled;
+            if (mPreparedPanel != null) {
+                handled = performPanelShortcut(mPreparedPanel, ev.getKeyCode(), ev,
+                        Menu.FLAG_PERFORM_NO_CLOSE);
+                if (handled) {
+                    if (mPreparedPanel != null) {
+                        mPreparedPanel.isHandled = true;
+                    }
+                    return true;
                 }
-                return true;
             }
 
             // Shortcut not handled by the panel.  Dispatch to the view hierarchy.
             final Callback cb = getCallback();
-            return cb != null && !isDestroyed() && mFeatureId < 0 ? cb.dispatchKeyShortcutEvent(ev)
-                    : super.dispatchKeyShortcutEvent(ev);
+            handled = cb != null && !isDestroyed() && mFeatureId < 0
+                    ? cb.dispatchKeyShortcutEvent(ev) : super.dispatchKeyShortcutEvent(ev);
+            if (handled) {
+                return true;
+            }
+
+            // If the panel is not prepared, then we may be trying to handle a shortcut key
+            // combination such as Control+C.  Temporarily prepare the panel then mark it
+            // unprepared again when finished to ensure that the panel will again be prepared
+            // the next time it is shown for real.
+            if (mPreparedPanel == null) {
+                PanelFeatureState st = getPanelState(FEATURE_OPTIONS_PANEL, true);
+                preparePanel(st, ev);
+                handled = performPanelShortcut(st, ev.getKeyCode(), ev,
+                        Menu.FLAG_PERFORM_NO_CLOSE);
+                st.isPrepared = false;
+                if (handled) {
+                    return true;
+                }
+            }
+            return false;
         }
 
         @Override
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
index e6b86fc..0a5a765 100755
--- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
@@ -301,9 +301,15 @@
     GlobalActions mGlobalActions;
     volatile boolean mPowerKeyHandled; // accessed from input reader and handler thread
     boolean mPendingPowerKeyUpCanceled;
-    RecentApplicationsDialog mRecentAppsDialog;
     Handler mHandler;
 
+    static final int RECENT_APPS_BEHAVIOR_SHOW_OR_DISMISS = 0;
+    static final int RECENT_APPS_BEHAVIOR_EXIT_TOUCH_MODE_AND_SHOW = 1;
+    static final int RECENT_APPS_BEHAVIOR_DISMISS_AND_SWITCH = 2;
+
+    RecentApplicationsDialog mRecentAppsDialog;
+    int mRecentAppsDialogHeldModifiers;
+
     private static final int LID_ABSENT = -1;
     private static final int LID_CLOSED = 0;
     private static final int LID_OPEN = 1;
@@ -715,7 +721,7 @@
         }
 
         if (mLongPressOnHomeBehavior == LONG_PRESS_HOME_RECENT_DIALOG) {
-            showOrHideRecentAppsDialog(0, true /*dismissIfShown*/);
+            showOrHideRecentAppsDialog(RECENT_APPS_BEHAVIOR_SHOW_OR_DISMISS);
         } else if (mLongPressOnHomeBehavior == LONG_PRESS_HOME_RECENT_SYSTEM_UI) {
             try {
                 mStatusBarService.toggleRecentApps();
@@ -726,10 +732,10 @@
     }
 
     /**
-     * Create (if necessary) and launch the recent apps dialog, or hide it if it is
-     * already shown.
+     * Create (if necessary) and show or dismiss the recent apps dialog according
+     * according to the requested behavior.
      */
-    void showOrHideRecentAppsDialog(final int heldModifiers, final boolean dismissIfShown) {
+    void showOrHideRecentAppsDialog(final int behavior) {
         mHandler.post(new Runnable() {
             @Override
             public void run() {
@@ -737,12 +743,33 @@
                     mRecentAppsDialog = new RecentApplicationsDialog(mContext);
                 }
                 if (mRecentAppsDialog.isShowing()) {
-                    if (dismissIfShown) {
-                        mRecentAppsDialog.dismiss();
+                    switch (behavior) {
+                        case RECENT_APPS_BEHAVIOR_SHOW_OR_DISMISS:
+                            mRecentAppsDialog.dismiss();
+                            break;
+                        case RECENT_APPS_BEHAVIOR_DISMISS_AND_SWITCH:
+                            mRecentAppsDialog.dismissAndSwitch();
+                            break;
+                        case RECENT_APPS_BEHAVIOR_EXIT_TOUCH_MODE_AND_SHOW:
+                        default:
+                            break;
                     }
                 } else {
-                    mRecentAppsDialog.setHeldModifiers(heldModifiers);
-                    mRecentAppsDialog.show();
+                    switch (behavior) {
+                        case RECENT_APPS_BEHAVIOR_SHOW_OR_DISMISS:
+                            mRecentAppsDialog.show();
+                            break;
+                        case RECENT_APPS_BEHAVIOR_EXIT_TOUCH_MODE_AND_SHOW:
+                            try {
+                                mWindowManager.setInTouchMode(false);
+                            } catch (RemoteException e) {
+                            }
+                            mRecentAppsDialog.show();
+                            break;
+                        case RECENT_APPS_BEHAVIOR_DISMISS_AND_SWITCH:
+                        default:
+                            break;
+                    }
                 }
             }
         });
@@ -1649,7 +1676,7 @@
             return 0;
         } else if (keyCode == KeyEvent.KEYCODE_APP_SWITCH) {
             if (down && repeatCount == 0) {
-                showOrHideRecentAppsDialog(0, true /*dismissIfShown*/);
+                showOrHideRecentAppsDialog(RECENT_APPS_BEHAVIOR_SHOW_OR_DISMISS);
             }
             return -1;
         }
@@ -1685,12 +1712,31 @@
             }
         }
 
+        // Invoke shortcuts using Meta.
+        if (down && repeatCount == 0
+                && (metaState & KeyEvent.META_META_ON) != 0) {
+            final KeyCharacterMap kcm = event.getKeyCharacterMap();
+            Intent shortcutIntent = mShortcutManager.getIntent(kcm, keyCode,
+                    metaState & ~(KeyEvent.META_META_ON
+                            | KeyEvent.META_META_LEFT_ON | KeyEvent.META_META_RIGHT_ON));
+            if (shortcutIntent != null) {
+                shortcutIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+                try {
+                    mContext.startActivity(shortcutIntent);
+                } catch (ActivityNotFoundException ex) {
+                    Slog.w(TAG, "Dropping shortcut key combination because "
+                            + "the activity to which it is registered was not found: "
+                            + "META+" + KeyEvent.keyCodeToString(keyCode), ex);
+                }
+                return -1;
+            }
+        }
+
         // Handle application launch keys.
         if (down && repeatCount == 0) {
             String category = sApplicationLaunchKeyCategories.get(keyCode);
             if (category != null) {
-                Intent intent = new Intent(Intent.ACTION_MAIN);
-                intent.addCategory(category);
+                Intent intent = Intent.makeMainSelectorActivity(Intent.ACTION_MAIN, category);
                 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                 try {
                     mContext.startActivity(intent);
@@ -1699,9 +1745,29 @@
                             + "the activity to which it is registered was not found: "
                             + "keyCode=" + keyCode + ", category=" + category, ex);
                 }
+                return -1;
             }
         }
 
+        // Display task switcher for ALT-TAB or Meta-TAB.
+        if (down && repeatCount == 0 && keyCode == KeyEvent.KEYCODE_TAB) {
+            if (mRecentAppsDialogHeldModifiers == 0) {
+                final int shiftlessModifiers = event.getModifiers() & ~KeyEvent.META_SHIFT_MASK;
+                if (KeyEvent.metaStateHasModifiers(shiftlessModifiers, KeyEvent.META_ALT_ON)
+                        || KeyEvent.metaStateHasModifiers(
+                                shiftlessModifiers, KeyEvent.META_META_ON)) {
+                    mRecentAppsDialogHeldModifiers = shiftlessModifiers;
+                    showOrHideRecentAppsDialog(RECENT_APPS_BEHAVIOR_EXIT_TOUCH_MODE_AND_SHOW);
+                    return -1;
+                }
+            }
+        } else if (!down && mRecentAppsDialogHeldModifiers != 0
+                && (metaState & mRecentAppsDialogHeldModifiers) == 0) {
+            mRecentAppsDialogHeldModifiers = 0;
+            showOrHideRecentAppsDialog(RECENT_APPS_BEHAVIOR_DISMISS_AND_SWITCH);
+        }
+
+        // Let the application handle the key.
         return 0;
     }
 
@@ -1723,39 +1789,6 @@
             final KeyCharacterMap kcm = event.getKeyCharacterMap();
             final int keyCode = event.getKeyCode();
             final int metaState = event.getMetaState();
-            final boolean initialDown = event.getAction() == KeyEvent.ACTION_DOWN
-                    && event.getRepeatCount() == 0;
-
-            if (initialDown) {
-                // Invoke shortcuts using Meta as a fallback.
-                if ((metaState & KeyEvent.META_META_ON) != 0) {
-                    Intent shortcutIntent = mShortcutManager.getIntent(kcm, keyCode,
-                            metaState & ~(KeyEvent.META_META_ON
-                                    | KeyEvent.META_META_LEFT_ON | KeyEvent.META_META_RIGHT_ON));
-                    if (shortcutIntent != null) {
-                        shortcutIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-                        try {
-                            mContext.startActivity(shortcutIntent);
-                        } catch (ActivityNotFoundException ex) {
-                            Slog.w(TAG, "Dropping shortcut key combination because "
-                                    + "the activity to which it is registered was not found: "
-                                    + "META+" + KeyEvent.keyCodeToString(keyCode), ex);
-                        }
-                        return null;
-                    }
-                }
-
-                // Display task switcher for ALT-TAB or Meta-TAB.
-                if (keyCode == KeyEvent.KEYCODE_TAB) {
-                    final int shiftlessModifiers = event.getModifiers() & ~KeyEvent.META_SHIFT_MASK;
-                    if (KeyEvent.metaStateHasModifiers(shiftlessModifiers, KeyEvent.META_ALT_ON)
-                            || KeyEvent.metaStateHasModifiers(
-                                    shiftlessModifiers, KeyEvent.META_META_ON)) {
-                        showOrHideRecentAppsDialog(shiftlessModifiers, false /*dismissIfShown*/);
-                        return null;
-                    }
-                }
-            }
 
             // Check for fallback actions specified by the key character map.
             if (getFallbackAction(kcm, keyCode, metaState, mFallbackAction)) {
@@ -3214,10 +3247,7 @@
             }
 
             final int preferredRotation;
-            if (mHdmiPlugged) {
-                // Ignore sensor when plugged into HDMI.
-                preferredRotation = mHdmiRotation;
-            } else if (mLidOpen == LID_OPEN && mLidOpenRotation >= 0) {
+            if (mLidOpen == LID_OPEN && mLidOpenRotation >= 0) {
                 // Ignore sensor when lid switch is open and rotation is forced.
                 preferredRotation = mLidOpenRotation;
             } else if (mDockMode == Intent.EXTRA_DOCK_STATE_CAR
@@ -3236,6 +3266,10 @@
                 // enable 180 degree rotation while docked.
                 preferredRotation = mDeskDockEnablesAccelerometer
                         ? sensorRotation : mDeskDockRotation;
+            } else if (mHdmiPlugged) {
+                // Ignore sensor when plugged into HDMI.
+                // Note that the dock orientation overrides the HDMI orientation.
+                preferredRotation = mHdmiRotation;
             } else if ((mAccelerometerDefault != 0 /* implies not rotation locked */
                             && (orientation == ActivityInfo.SCREEN_ORIENTATION_USER
                                     || orientation == ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED))
@@ -3478,6 +3512,9 @@
                             WindowManager.LayoutParams.FLAG_DIM_BEHIND
                             | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN);
                     mBootMsgDialog.getWindow().setDimAmount(1);
+                    WindowManager.LayoutParams lp = mBootMsgDialog.getWindow().getAttributes();
+                    lp.screenOrientation = ActivityInfo.SCREEN_ORIENTATION_NOSENSOR;
+                    mBootMsgDialog.getWindow().setAttributes(lp);
                     mBootMsgDialog.setCancelable(false);
                     mBootMsgDialog.show();
                 }
diff --git a/policy/src/com/android/internal/policy/impl/RecentApplicationsDialog.java b/policy/src/com/android/internal/policy/impl/RecentApplicationsDialog.java
index aa00fbdd..b9903dd 100644
--- a/policy/src/com/android/internal/policy/impl/RecentApplicationsDialog.java
+++ b/policy/src/com/android/internal/policy/impl/RecentApplicationsDialog.java
@@ -71,8 +71,6 @@
         }
     };
 
-    private int mHeldModifiers;
-
     public RecentApplicationsDialog(Context context) {
         super(context, com.android.internal.R.style.Theme_Dialog_RecentApplications);
 
@@ -124,17 +122,6 @@
         }
     }
 
-    /**
-     * Sets the modifier keys that are being held to keep the dialog open, or 0 if none.
-     * Used to make the recent apps dialog automatically dismiss itself when the modifiers
-     * all go up.
-     * @param heldModifiers The held key modifiers, such as {@link KeyEvent#META_ALT_ON}.
-     * Should exclude shift.
-     */
-    public void setHeldModifiers(int heldModifiers) {
-        mHeldModifiers = heldModifiers;
-    }
-
     @Override
     public boolean onKeyDown(int keyCode, KeyEvent event) {
         if (keyCode == KeyEvent.KEYCODE_TAB) {
@@ -174,30 +161,27 @@
         return super.onKeyDown(keyCode, event);
     }
 
-    @Override
-    public boolean onKeyUp(int keyCode, KeyEvent event) {
-        if (mHeldModifiers != 0 && (event.getModifiers() & mHeldModifiers) == 0) {
-            final int numIcons = mIcons.length;
-            RecentTag tag = null;
-            for (int i = 0; i < numIcons; i++) {
-                if (mIcons[i].getVisibility() != View.VISIBLE) {
+    /**
+     * Dismiss the dialog and switch to the selected application.
+     */
+    public void dismissAndSwitch() {
+        final int numIcons = mIcons.length;
+        RecentTag tag = null;
+        for (int i = 0; i < numIcons; i++) {
+            if (mIcons[i].getVisibility() != View.VISIBLE) {
+                break;
+            }
+            if (i == 0 || mIcons[i].hasFocus()) {
+                tag = (RecentTag) mIcons[i].getTag();
+                if (mIcons[i].hasFocus()) {
                     break;
                 }
-                if (i == 0 || mIcons[i].hasFocus()) {
-                    tag = (RecentTag) mIcons[i].getTag();
-                    if (mIcons[i].hasFocus()) {
-                        break;
-                    }
-                }
             }
-            if (tag != null) {
-                switchTo(tag);
-            }
-            dismiss();
-            return true;
         }
-
-        return super.onKeyUp(keyCode, event);
+        if (tag != null) {
+            switchTo(tag);
+        }
+        dismiss();
     }
 
     /**
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index 66eb63a..b48f23d 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -1816,6 +1816,18 @@
     return &mOutput->stream->common;
 }
 
+uint32_t AudioFlinger::PlaybackThread::activeSleepTimeUs()
+{
+    // A2DP output latency is not due only to buffering capacity. It also reflects encoding,
+    // decoding and transfer time. So sleeping for half of the latency would likely cause
+    // underruns
+    if (audio_is_a2dp_device((audio_devices_t)mDevice)) {
+        return (uint32_t)((uint32_t)((mFrameCount * 1000) / mSampleRate) * 1000);
+    } else {
+        return (uint32_t)(mOutput->stream->get_latency(mOutput->stream) * 1000) / 2;
+    }
+}
+
 // ----------------------------------------------------------------------------
 
 AudioFlinger::MixerThread::MixerThread(const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output, int id, uint32_t device)
@@ -2422,11 +2434,6 @@
     return NO_ERROR;
 }
 
-uint32_t AudioFlinger::MixerThread::activeSleepTimeUs()
-{
-    return (uint32_t)(mOutput->stream->get_latency(mOutput->stream) * 1000) / 2;
-}
-
 uint32_t AudioFlinger::MixerThread::idleSleepTimeUs()
 {
     return (uint32_t)(((mFrameCount * 1000) / mSampleRate) * 1000) / 2;
@@ -2893,7 +2900,7 @@
 {
     uint32_t time;
     if (audio_is_linear_pcm(mFormat)) {
-        time = (uint32_t)(mOutput->stream->get_latency(mOutput->stream) * 1000) / 2;
+        time = PlaybackThread::activeSleepTimeUs();
     } else {
         time = 10000;
     }
diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h
index 897bc78..6cafa7e 100644
--- a/services/audioflinger/AudioFlinger.h
+++ b/services/audioflinger/AudioFlinger.h
@@ -776,7 +776,7 @@
 
         virtual int             getTrackName_l() = 0;
         virtual void            deleteTrackName_l(int name) = 0;
-        virtual uint32_t        activeSleepTimeUs() = 0;
+        virtual uint32_t        activeSleepTimeUs();
         virtual uint32_t        idleSleepTimeUs() = 0;
         virtual uint32_t        suspendSleepTimeUs() = 0;
 
@@ -833,7 +833,6 @@
                                                 Vector< sp<Track> > *tracksToRemove);
         virtual     int         getTrackName_l();
         virtual     void        deleteTrackName_l(int name);
-        virtual     uint32_t    activeSleepTimeUs();
         virtual     uint32_t    idleSleepTimeUs();
         virtual     uint32_t    suspendSleepTimeUs();
 
diff --git a/services/input/InputDispatcher.cpp b/services/input/InputDispatcher.cpp
index 382f4d9..5f31f05 100644
--- a/services/input/InputDispatcher.cpp
+++ b/services/input/InputDispatcher.cpp
@@ -4312,12 +4312,23 @@
             mKeyMementos.removeAt(index);
             return true;
         }
+        /* FIXME: We can't just drop the key up event because that prevents creating
+         * popup windows that are automatically shown when a key is held and then
+         * dismissed when the key is released.  The problem is that the popup will
+         * not have received the original key down, so the key up will be considered
+         * to be inconsistent with its observed state.  We could perhaps handle this
+         * by synthesizing a key down but that will cause other problems.
+         *
+         * So for now, allow inconsistent key up events to be dispatched.
+         *
 #if DEBUG_OUTBOUND_EVENT_DETAILS
         LOGD("Dropping inconsistent key up event: deviceId=%d, source=%08x, "
                 "keyCode=%d, scanCode=%d",
                 entry->deviceId, entry->source, entry->keyCode, entry->scanCode);
 #endif
         return false;
+        */
+        return true;
     }
 
     case AKEY_EVENT_ACTION_DOWN: {
diff --git a/services/java/com/android/server/AppWidgetService.java b/services/java/com/android/server/AppWidgetService.java
index 2af5103..4f81178 100644
--- a/services/java/com/android/server/AppWidgetService.java
+++ b/services/java/com/android/server/AppWidgetService.java
@@ -24,9 +24,9 @@
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
+import android.content.Intent.FilterComparison;
 import android.content.IntentFilter;
 import android.content.ServiceConnection;
-import android.content.Intent.FilterComparison;
 import android.content.pm.ActivityInfo;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageInfo;
@@ -39,6 +39,8 @@
 import android.net.Uri;
 import android.os.Binder;
 import android.os.Bundle;
+import android.os.Handler;
+import android.os.HandlerThread;
 import android.os.IBinder;
 import android.os.RemoteException;
 import android.os.SystemClock;
@@ -74,6 +76,7 @@
 import java.util.Iterator;
 import java.util.List;
 import java.util.Locale;
+import java.util.Set;
 
 class AppWidgetService extends IAppWidgetService.Stub
 {
@@ -805,6 +808,45 @@
                     id.host.callbacks = null;
                 }
             }
+
+            // If the host is unavailable, then we call the associated
+            // RemoteViewsFactory.onDataSetChanged() directly
+            if (id.host.callbacks == null) {
+                Set<FilterComparison> keys = mRemoteViewsServicesAppWidgets.keySet();
+                for (FilterComparison key : keys) {
+                    if (mRemoteViewsServicesAppWidgets.get(key).contains(id.appWidgetId)) {
+                        Intent intent = key.getIntent();
+
+                        final ServiceConnection conn = new ServiceConnection() {
+                            @Override
+                            public void onServiceConnected(ComponentName name, IBinder service) {
+                                IRemoteViewsFactory cb =
+                                    IRemoteViewsFactory.Stub.asInterface(service);
+                                try {
+                                    cb.onDataSetChangedAsync();
+                                } catch (RemoteException e) {
+                                    e.printStackTrace();
+                                } catch (RuntimeException e) {
+                                    e.printStackTrace();
+                                }
+                                mContext.unbindService(this);
+                            }
+                            @Override
+                            public void onServiceDisconnected(android.content.ComponentName name) {
+                                // Do nothing
+                            }
+                        };
+
+                        // Bind to the service and call onDataSetChanged()
+                        final long token = Binder.clearCallingIdentity();
+                        try {
+                            mContext.bindService(intent, conn, Context.BIND_AUTO_CREATE);
+                        } finally {
+                            Binder.restoreCallingIdentity(token);
+                        }
+                    }
+                }
+            }
         }
     }
 
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/services/java/com/android/server/WifiService.java b/services/java/com/android/server/WifiService.java
index 3c65255..16643ff 100644
--- a/services/java/com/android/server/WifiService.java
+++ b/services/java/com/android/server/WifiService.java
@@ -1078,7 +1078,6 @@
                 mWifiStateMachine.setHighPerfModeEnabled(strongestLockMode
                         == WifiManager.WIFI_MODE_FULL_HIGH_PERF);
             } else {
-                mWifiStateMachine.requestCmWakeLock();
                 mWifiStateMachine.setDriverStart(false);
             }
         } else {
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index a4d321d..df58e83 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -14419,10 +14419,16 @@
                             app.thread.scheduleTrimMemory(curLevel);
                         } catch (RemoteException e) {
                         }
-                        if (curLevel >= ComponentCallbacks2.TRIM_MEMORY_COMPLETE) {
-                            // For these apps we will also finish their activities
-                            // to help them free memory.
-                            mMainStack.destroyActivitiesLocked(app, false, "trim");
+                        if (false) {
+                            // For now we won't do this; our memory trimming seems
+                            // to be good enough at this point that destroying
+                            // activities causes more harm than good.
+                            if (curLevel >= ComponentCallbacks2.TRIM_MEMORY_COMPLETE
+                                    && app != mHomeProcess && app != mPreviousProcess) {
+                                // For these apps we will also finish their activities
+                                // to help them free memory.
+                                mMainStack.destroyActivitiesLocked(app, false, "trim");
+                            }
                         }
                     }
                     app.trimMemoryLevel = curLevel;
diff --git a/services/java/com/android/server/am/ActivityStack.java b/services/java/com/android/server/am/ActivityStack.java
index b5edc0a..6c11953 100644
--- a/services/java/com/android/server/am/ActivityStack.java
+++ b/services/java/com/android/server/am/ActivityStack.java
@@ -1932,8 +1932,9 @@
                     // should be left as-is.
                     replyChainEnd = -1;
                 }
-                
-            } else if (target.resultTo != null) {
+
+            } else if (target.resultTo != null && (below == null
+                    || below.task == target.task)) {
                 // If this activity is sending a reply to a previous
                 // activity, we can't do anything with it now until
                 // we reach the start of the reply chain.
@@ -1963,6 +1964,8 @@
                         replyChainEnd = targetI;
                     }
                     ActivityRecord p = null;
+                    if (DEBUG_TASKS) Slog.v(TAG, "Finishing task at index "
+                            + targetI + " to " + replyChainEnd);
                     for (int srcPos=targetI; srcPos<=replyChainEnd; srcPos++) {
                         p = mHistory.get(srcPos);
                         if (p.finishing) {
@@ -1981,6 +1984,8 @@
                     if (replyChainEnd < 0) {
                         replyChainEnd = targetI;
                     }
+                    if (DEBUG_TASKS) Slog.v(TAG, "Reparenting task at index "
+                            + targetI + " to " + replyChainEnd);
                     for (int srcPos=replyChainEnd; srcPos>=targetI; srcPos--) {
                         ActivityRecord p = mHistory.get(srcPos);
                         if (p.finishing) {
@@ -2002,6 +2007,7 @@
                         p.setTask(task, null, false);
                         mHistory.add(lastReparentPos, p);
                         if (DEBUG_TASKS) Slog.v(TAG, "Pulling activity " + p
+                                + " from " + srcPos + " to " + lastReparentPos
                                 + " in to resetting task " + task);
                         mService.mWindowManager.moveAppToken(lastReparentPos, p.appToken);
                         mService.mWindowManager.setAppGroupId(p.appToken, p.task.taskId);
@@ -2031,6 +2037,11 @@
                         }
                     }
                 }
+
+            } else if (below != null && below.task != target.task) {
+                // We hit the botton of a task; the reply chain can't
+                // pass through it.
+                replyChainEnd = -1;
             }
             
             target = below;
diff --git a/services/java/com/android/server/am/TaskRecord.java b/services/java/com/android/server/am/TaskRecord.java
index a860763..de3129b 100644
--- a/services/java/com/android/server/am/TaskRecord.java
+++ b/services/java/com/android/server/am/TaskRecord.java
@@ -54,8 +54,17 @@
     
     void setIntent(Intent _intent, ActivityInfo info) {
         stringName = null;
-        
+
         if (info.targetActivity == null) {
+            if (_intent != null) {
+                // If this Intent has a selector, we want to clear it for the
+                // recent task since it is not relevant if the user later wants
+                // to re-launch the app.
+                if (_intent.getSelector() != null) {
+                    _intent = new Intent(_intent);
+                    _intent.setSelector(null);
+                }
+            }
             intent = _intent;
             realActivity = _intent != null ? _intent.getComponent() : null;
             origActivity = null;
@@ -65,6 +74,7 @@
             if (_intent != null) {
                 Intent targetIntent = new Intent(_intent);
                 targetIntent.setComponent(targetComponent);
+                targetIntent.setSelector(null);
                 intent = targetIntent;
                 realActivity = targetComponent;
                 origActivity = _intent.getComponent();
diff --git a/services/java/com/android/server/pm/PackageManagerService.java b/services/java/com/android/server/pm/PackageManagerService.java
index 7005541..6b61c47 100644
--- a/services/java/com/android/server/pm/PackageManagerService.java
+++ b/services/java/com/android/server/pm/PackageManagerService.java
@@ -2162,6 +2162,9 @@
             int flags, List<ResolveInfo> query, int priority) {
         // writer
         synchronized (mPackages) {
+            if (intent.getSelector() != null) {
+                intent = intent.getSelector(); 
+            }
             if (DEBUG_PREFERRED) intent.addFlags(Intent.FLAG_DEBUG_LOG_RESOLUTION);
             List<PreferredActivity> prefs =
                     mSettings.mPreferredActivities.queryIntent(intent, resolvedType,
@@ -2242,7 +2245,13 @@
 
     public List<ResolveInfo> queryIntentActivities(Intent intent,
             String resolvedType, int flags) {
-        final ComponentName comp = intent.getComponent();
+        ComponentName comp = intent.getComponent();
+        if (comp == null) {
+            if (intent.getSelector() != null) {
+                intent = intent.getSelector(); 
+                comp = intent.getComponent();
+            }
+        }
         if (comp != null) {
             final List<ResolveInfo> list = new ArrayList<ResolveInfo>(1);
             final ActivityInfo ai = getActivityInfo(comp, flags);
@@ -2440,6 +2449,12 @@
 
     public List<ResolveInfo> queryIntentReceivers(Intent intent, String resolvedType, int flags) {
         ComponentName comp = intent.getComponent();
+        if (comp == null) {
+            if (intent.getSelector() != null) {
+                intent = intent.getSelector(); 
+                comp = intent.getComponent();
+            }
+        }
         if (comp != null) {
             List<ResolveInfo> list = new ArrayList<ResolveInfo>(1);
             ActivityInfo ai = getReceiverInfo(comp, flags);
@@ -2478,7 +2493,13 @@
     }
 
     public List<ResolveInfo> queryIntentServices(Intent intent, String resolvedType, int flags) {
-        final ComponentName comp = intent.getComponent();
+        ComponentName comp = intent.getComponent();
+        if (comp == null) {
+            if (intent.getSelector() != null) {
+                intent = intent.getSelector(); 
+                comp = intent.getComponent();
+            }
+        }
         if (comp != null) {
             final List<ResolveInfo> list = new ArrayList<ResolveInfo>(1);
             final ServiceInfo si = getServiceInfo(comp, flags);
diff --git a/services/surfaceflinger/DisplayEventConnection.cpp b/services/surfaceflinger/DisplayEventConnection.cpp
index a0aa9c0..77ecbd2 100644
--- a/services/surfaceflinger/DisplayEventConnection.cpp
+++ b/services/surfaceflinger/DisplayEventConnection.cpp
@@ -25,6 +25,7 @@
 
 #include "SurfaceFlinger.h"
 #include "DisplayEventConnection.h"
+#include "EventThread.h"
 
 // ---------------------------------------------------------------------------
 
@@ -33,30 +34,38 @@
 // ---------------------------------------------------------------------------
 
 DisplayEventConnection::DisplayEventConnection(
-        const sp<SurfaceFlinger>& flinger)
-    : mFlinger(flinger), mChannel(new BitTube())
+        const sp<EventThread>& eventThread)
+    : mEventThread(eventThread), mChannel(new BitTube())
 {
 }
 
 DisplayEventConnection::~DisplayEventConnection() {
-    mFlinger->cleanupDisplayEventConnection(this);
+    mEventThread->unregisterDisplayEventConnection(this);
 }
 
 void DisplayEventConnection::onFirstRef() {
-    // nothing to do here for now.
+    // NOTE: mEventThread doesn't hold a strong reference on us
+    mEventThread->registerDisplayEventConnection(this);
 }
 
 sp<BitTube> DisplayEventConnection::getDataChannel() const {
     return mChannel;
 }
 
+void DisplayEventConnection::setVsyncRate(uint32_t count) {
+    mEventThread->setVsyncRate(count, this);
+}
+
+void DisplayEventConnection::requestNextVsync() {
+    mEventThread->requestNextVsync(this);
+}
+
 status_t DisplayEventConnection::postEvent(const DisplayEventReceiver::Event& event)
 {
     ssize_t size = mChannel->write(&event, sizeof(DisplayEventReceiver::Event));
     return size < 0 ? status_t(size) : status_t(NO_ERROR);
 }
 
-
 // ---------------------------------------------------------------------------
 
 }; // namespace android
diff --git a/services/surfaceflinger/DisplayEventConnection.h b/services/surfaceflinger/DisplayEventConnection.h
index 46cf64b..cc3ee36 100644
--- a/services/surfaceflinger/DisplayEventConnection.h
+++ b/services/surfaceflinger/DisplayEventConnection.h
@@ -32,13 +32,13 @@
 // ---------------------------------------------------------------------------
 
 class BitTube;
-class SurfaceFlinger;
+class EventThread;
 
 // ---------------------------------------------------------------------------
 
 class DisplayEventConnection : public BnDisplayEventConnection {
 public:
-    DisplayEventConnection(const sp<SurfaceFlinger>& flinger);
+    DisplayEventConnection(const sp<EventThread>& flinger);
 
     status_t postEvent(const DisplayEventReceiver::Event& event);
 
@@ -46,8 +46,10 @@
     virtual ~DisplayEventConnection();
     virtual void onFirstRef();
     virtual sp<BitTube> getDataChannel() const;
+    virtual void setVsyncRate(uint32_t count);
+    virtual void requestNextVsync();    // asynchronous
 
-    sp<SurfaceFlinger> const mFlinger;
+    sp<EventThread> const mEventThread;
     sp<BitTube> const mChannel;
 };
 
diff --git a/services/surfaceflinger/EventThread.cpp b/services/surfaceflinger/EventThread.cpp
index edb06ba..dc39f88 100644
--- a/services/surfaceflinger/EventThread.cpp
+++ b/services/surfaceflinger/EventThread.cpp
@@ -47,7 +47,8 @@
 status_t EventThread::registerDisplayEventConnection(
         const sp<DisplayEventConnection>& connection) {
     Mutex::Autolock _l(mLock);
-    mDisplayEventConnections.add(connection);
+    ConnectionInfo info;
+    mDisplayEventConnections.add(connection, info);
     mCondition.signal();
     return NO_ERROR;
 }
@@ -55,43 +56,132 @@
 status_t EventThread::unregisterDisplayEventConnection(
         const wp<DisplayEventConnection>& connection) {
     Mutex::Autolock _l(mLock);
-    mDisplayEventConnections.remove(connection);
+    mDisplayEventConnections.removeItem(connection);
     mCondition.signal();
     return NO_ERROR;
 }
 
+void EventThread::removeDisplayEventConnection(
+        const wp<DisplayEventConnection>& connection) {
+    Mutex::Autolock _l(mLock);
+    mDisplayEventConnections.removeItem(connection);
+}
+
+EventThread::ConnectionInfo* EventThread::getConnectionInfoLocked(
+        const wp<DisplayEventConnection>& connection) {
+    ssize_t index = mDisplayEventConnections.indexOfKey(connection);
+    if (index < 0) return NULL;
+    return &mDisplayEventConnections.editValueAt(index);
+}
+
+void EventThread::setVsyncRate(uint32_t count,
+        const wp<DisplayEventConnection>& connection) {
+    if (int32_t(count) >= 0) { // server must protect against bad params
+        Mutex::Autolock _l(mLock);
+        ConnectionInfo* info = getConnectionInfoLocked(connection);
+        if (info) {
+            info->count = (count == 0) ? -1 : count;
+            mCondition.signal();
+        }
+    }
+}
+
+void EventThread::requestNextVsync(
+        const wp<DisplayEventConnection>& connection) {
+    Mutex::Autolock _l(mLock);
+    ConnectionInfo* info = getConnectionInfoLocked(connection);
+    if (info) {
+        if (info->count < 0) {
+            info->count = 0;
+        }
+        mCondition.signal();
+    }
+}
+
 bool EventThread::threadLoop() {
 
     nsecs_t timestamp;
-    Mutex::Autolock _l(mLock);
-    do {
-        // wait for listeners
-        while (!mDisplayEventConnections.size()) {
-            mCondition.wait(mLock);
-        }
-
-        // wait for vsync
-        mLock.unlock();
-        timestamp = mHw.waitForVSync();
-        mLock.lock();
-
-        // make sure we still have some listeners
-    } while (!mDisplayEventConnections.size());
-
-
-    // dispatch vsync events to listeners...
-    mDeliveredEvents++;
-    const size_t count = mDisplayEventConnections.size();
-
     DisplayEventReceiver::Event vsync;
-    vsync.header.type = DisplayEventReceiver::DISPLAY_EVENT_VSYNC;
-    vsync.header.timestamp = timestamp;
-    vsync.vsync.count = mDeliveredEvents;
+    KeyedVector< wp<DisplayEventConnection>, ConnectionInfo > displayEventConnections;
 
+    { // scope for the lock
+        Mutex::Autolock _l(mLock);
+        do {
+            // wait for listeners
+            do {
+                bool waitForNextVsync = false;
+                size_t count = mDisplayEventConnections.size();
+                for (size_t i=0 ; i<count ; i++) {
+                    const ConnectionInfo& info(
+                            mDisplayEventConnections.valueAt(i));
+                    if (info.count >= 1) {
+                        // continuous mode
+                        waitForNextVsync = true;
+                    } else {
+                        // one-shot event
+                        if (info.count >= -1) {
+                            ConnectionInfo& info(
+                                    mDisplayEventConnections.editValueAt(i));
+                            info.count--;
+                            if (info.count == -1) {
+                                // fired this time around
+                                waitForNextVsync = true;
+                            }
+                        }
+                    }
+                }
+
+                if (waitForNextVsync)
+                    break;
+
+                mCondition.wait(mLock);
+            } while(true);
+
+            // wait for vsync
+            mLock.unlock();
+            timestamp = mHw.waitForVSync();
+            mLock.lock();
+            mDeliveredEvents++;
+
+            // make sure we still have some listeners
+        } while (!mDisplayEventConnections.size());
+
+        // dispatch vsync events to listeners...
+        vsync.header.type = DisplayEventReceiver::DISPLAY_EVENT_VSYNC;
+        vsync.header.timestamp = timestamp;
+        vsync.vsync.count = mDeliveredEvents;
+
+        // make a copy of our connection list, so we can
+        // dispatch events without holding mLock
+        displayEventConnections = mDisplayEventConnections;
+    }
+
+    const size_t count = displayEventConnections.size();
     for (size_t i=0 ; i<count ; i++) {
-        sp<DisplayEventConnection> conn(mDisplayEventConnections.itemAt(i).promote());
+        sp<DisplayEventConnection> conn(displayEventConnections.keyAt(i).promote());
         // make sure the connection didn't die
         if (conn != NULL) {
+
+            const ConnectionInfo& info(
+                    displayEventConnections.valueAt(i));
+
+            if ((info.count > 1) && (mDeliveredEvents % info.count)) {
+                // continuous event, but not time to send this event yet
+                continue;
+            } else if (info.count < -1) {
+                // disabled event
+                continue;
+            } else if (info.count == 0) {
+                // impossible by construction. but we prefer to be safe.
+                continue;
+            }
+
+            // here, either:
+            // count = -1 : one-shot scheduled this time around
+            // count =  1 : continuous not rate-limited
+            // count >  1 : continuous, rate-limited
+            // Note: count == 0 is not possible by construction
+
             status_t err = conn->postEvent(vsync);
             if (err == -EAGAIN || err == -EWOULDBLOCK) {
                 // The destination doesn't accept events anymore, it's probably
@@ -103,11 +193,18 @@
                 // handle any other error on the pipe as fatal. the only
                 // reasonable thing to do is to clean-up this connection.
                 // The most common error we'll get here is -EPIPE.
-                mDisplayEventConnections.remove(conn);
+                removeDisplayEventConnection(displayEventConnections.keyAt(i));
             }
+        } else {
+            // somehow the connection is dead, but we still have it in our list
+            // just clean the list.
+            removeDisplayEventConnection(displayEventConnections.keyAt(i));
         }
     }
 
+    // clear all our references without holding mLock
+    displayEventConnections.clear();
+
     return true;
 }
 
diff --git a/services/surfaceflinger/EventThread.h b/services/surfaceflinger/EventThread.h
index 0482ab7..35bd299 100644
--- a/services/surfaceflinger/EventThread.h
+++ b/services/surfaceflinger/EventThread.h
@@ -24,7 +24,7 @@
 
 #include <utils/Errors.h>
 #include <utils/threads.h>
-#include <utils/SortedVector.h>
+#include <utils/KeyedVector.h>
 
 #include "DisplayEventConnection.h"
 
@@ -51,6 +51,11 @@
     status_t unregisterDisplayEventConnection(
             const wp<DisplayEventConnection>& connection);
 
+    void setVsyncRate(uint32_t count,
+            const wp<DisplayEventConnection>& connection);
+
+    void requestNextVsync(const wp<DisplayEventConnection>& connection);
+
     void dump(String8& result, char* buffer, size_t SIZE) const;
 
 private:
@@ -58,6 +63,22 @@
     virtual status_t    readyToRun();
     virtual void        onFirstRef();
 
+    struct ConnectionInfo {
+        ConnectionInfo() : count(-1) { }
+
+        // count >= 1 : continuous event. count is the vsync rate
+        // count == 0 : one-shot event that has not fired
+        // count ==-1 : one-shot event that fired this round / disabled
+        // count ==-2 : one-shot event that fired the round before
+        int32_t count;
+    };
+
+    void removeDisplayEventConnection(
+            const wp<DisplayEventConnection>& connection);
+
+    ConnectionInfo* getConnectionInfoLocked(
+            const wp<DisplayEventConnection>& connection);
+
     // constants
     sp<SurfaceFlinger> mFlinger;
     const DisplayHardware& mHw;
@@ -66,7 +87,9 @@
     mutable Condition mCondition;
 
     // protected by mLock
-    SortedVector<wp<DisplayEventConnection> > mDisplayEventConnections;
+    KeyedVector< wp<DisplayEventConnection>, ConnectionInfo > mDisplayEventConnections;
+
+    // main thread only
     size_t mDeliveredEvents;
 };
 
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 58196d8..014c7e2 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -389,16 +389,10 @@
 // ----------------------------------------------------------------------------
 
 sp<IDisplayEventConnection> SurfaceFlinger::createDisplayEventConnection() {
-    sp<DisplayEventConnection> result(new DisplayEventConnection(this));
-    mEventThread->registerDisplayEventConnection(result);
+    sp<DisplayEventConnection> result(new DisplayEventConnection(mEventThread));
     return result;
 }
 
-void SurfaceFlinger::cleanupDisplayEventConnection(
-        const wp<DisplayEventConnection>& connection) {
-    mEventThread->unregisterDisplayEventConnection(connection);
-}
-
 // ----------------------------------------------------------------------------
 #if 0
 #pragma mark -
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index e6d2cd9..41caee3 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -335,9 +335,6 @@
             status_t electronBeamOffAnimationImplLocked();
             status_t electronBeamOnAnimationImplLocked();
 
-            void cleanupDisplayEventConnection(
-                    const wp<DisplayEventConnection>& connection);
-
             void        debugFlashRegions();
             void        debugShowFPS() const;
             void        drawWormhole() const;
diff --git a/telephony/java/com/android/internal/telephony/BaseCommands.java b/telephony/java/com/android/internal/telephony/BaseCommands.java
index f111dd6..07b6183 100644
--- a/telephony/java/com/android/internal/telephony/BaseCommands.java
+++ b/telephony/java/com/android/internal/telephony/BaseCommands.java
@@ -683,6 +683,13 @@
         mRilConnectedRegistrants.remove(h);
     }
 
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void setCurrentPreferredNetworkType() {
+    }
+
     //***** Protected Methods
     /**
      * Store new RadioState and send notification based on the changes
diff --git a/telephony/java/com/android/internal/telephony/CommandsInterface.java b/telephony/java/com/android/internal/telephony/CommandsInterface.java
index 33ead75..d6e6ae0 100644
--- a/telephony/java/com/android/internal/telephony/CommandsInterface.java
+++ b/telephony/java/com/android/internal/telephony/CommandsInterface.java
@@ -1311,6 +1311,12 @@
     void queryAvailableBandMode (Message response);
 
     /**
+     * Set the current preferred network type. This will be the last
+     * networkType that was passed to setPreferredNetworkType.
+     */
+    void setCurrentPreferredNetworkType();
+
+    /**
      *  Requests to set the preferred network type for searching and registering
      * (CS/PS domain, RAT, and operation mode)
      * @param networkType one of  NT_*_TYPE
diff --git a/telephony/java/com/android/internal/telephony/RIL.java b/telephony/java/com/android/internal/telephony/RIL.java
index 9f93fb8..f2e7f45 100644
--- a/telephony/java/com/android/internal/telephony/RIL.java
+++ b/telephony/java/com/android/internal/telephony/RIL.java
@@ -1823,6 +1823,16 @@
     /**
      * {@inheritDoc}
      */
+    @Override
+    public void setCurrentPreferredNetworkType() {
+        if (RILJ_LOGD) riljLog("setCurrentPreferredNetworkType: " + mSetPreferredNetworkType);
+        setPreferredNetworkType(mSetPreferredNetworkType, null);
+    }
+    private int mSetPreferredNetworkType;
+
+    /**
+     * {@inheritDoc}
+     */
     public void setPreferredNetworkType(int networkType , Message response) {
         RILRequest rr = RILRequest.obtain(
                 RILConstants.RIL_REQUEST_SET_PREFERRED_NETWORK_TYPE, response);
@@ -1830,6 +1840,7 @@
         rr.mp.writeInt(1);
         rr.mp.writeInt(networkType);
 
+        mSetPreferredNetworkType = networkType;
         mPreferredNetworkType = networkType;
 
         if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)
diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java b/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java
index 3d6cd68..d939e98 100755
--- a/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java
@@ -257,6 +257,9 @@
             break;
 
         case EVENT_RUIM_READY:
+            // TODO: Consider calling setCurrentPreferredNetworkType as we do in GsmSST.
+            // cm.setCurrentPreferredNetworkType();
+
             // The RUIM is now ready i.e if it was locked it has been
             // unlocked. At this stage, the radio is already powered on.
             isSubscriptionFromRuim = true;
@@ -277,6 +280,9 @@
             break;
 
         case EVENT_NV_READY:
+            // TODO: Consider calling setCurrentPreferredNetworkType as we do in GsmSST.
+            // cm.setCurrentPreferredNetworkType();
+
             isSubscriptionFromRuim = false;
             // For Non-RUIM phones, the subscription information is stored in
             // Non Volatile. Here when Non-Volatile is ready, we can poll the CDMA
diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
index 11f1623..963db2c 100644
--- a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
+++ b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
@@ -914,10 +914,16 @@
                         cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.NUMERIC)),
                         cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.NAME)),
                         cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.APN)),
-                        cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.PROXY)),
+                        NetworkUtils.trimV4AddrZeros(
+                                cursor.getString(
+                                cursor.getColumnIndexOrThrow(Telephony.Carriers.PROXY))),
                         cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.PORT)),
-                        cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.MMSC)),
-                        cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.MMSPROXY)),
+                        NetworkUtils.trimV4AddrZeros(
+                                cursor.getString(
+                                cursor.getColumnIndexOrThrow(Telephony.Carriers.MMSC))),
+                        NetworkUtils.trimV4AddrZeros(
+                                cursor.getString(
+                                cursor.getColumnIndexOrThrow(Telephony.Carriers.MMSPROXY))),
                         cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.MMSPORT)),
                         cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.USER)),
                         cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.PASSWORD)),
diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmMmiCode.java b/telephony/java/com/android/internal/telephony/gsm/GsmMmiCode.java
index 3799894..16d3129 100644
--- a/telephony/java/com/android/internal/telephony/gsm/GsmMmiCode.java
+++ b/telephony/java/com/android/internal/telephony/gsm/GsmMmiCode.java
@@ -132,7 +132,7 @@
     // See TS 22.030 6.5.2 "Structure of the MMI"
 
     static Pattern sPatternSuppService = Pattern.compile(
-        "((\\*|#|\\*#|\\*\\*|##)(\\d{2,3})(\\*([^*#]*)(\\*([^*#]*)(\\*([^*#]*)(\\*([^*#]*))?)?)?)?#)(.*)");
+        "((\\*|#|\\*#|\\*\\*|##)(\\d{2,3})(\\*([^*#]*)(\\*([^*#]*)(\\*([^*#]*)(\\*([^*#]*))?)?)?)?#)([^#]*)");
 /*       1  2                    3          4  5       6   7         8    9     10  11             12
 
          1 = Full string up to and including #
@@ -141,7 +141,7 @@
          5 = SIA
          7 = SIB
          9 = SIC
-         10 = dialing number
+         10 = dialing number which must not include #, e.g. *SCn*SI#DN format
 */
 
     static final int MATCH_GROUP_POUND_STRING = 1;
@@ -1338,4 +1338,20 @@
      * SpecialCharSequenceMgr class.
      */
 
+    @Override
+    public String toString() {
+        StringBuilder sb = new StringBuilder("GsmMmiCode {");
+
+        sb.append("State=" + getState());
+        if (action != null) sb.append(" action=" + action);
+        if (sc != null) sb.append(" sc=" + sc);
+        if (sia != null) sb.append(" sia=" + sia);
+        if (sib != null) sb.append(" sib=" + sib);
+        if (sic != null) sb.append(" sic=" + sic);
+        if (poundString != null) sb.append(" poundString=" + poundString);
+        if (dialingNumber != null) sb.append(" dialingNumber=" + dialingNumber);
+        if (pwd != null) sb.append(" pwd=" + pwd);
+        sb.append("}");
+        return sb.toString();
+    }
 }
diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java b/telephony/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java
index eea2780..84127cf 100644
--- a/telephony/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java
+++ b/telephony/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java
@@ -270,6 +270,9 @@
                 break;
 
             case EVENT_SIM_READY:
+                // Set the network type, in case the radio does not restore it.
+                cm.setCurrentPreferredNetworkType();
+
                 // The SIM is now ready i.e if it was locked
                 // it has been unlocked. At this stage, the radio is already
                 // powered on.
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/PerfTest/src/com/android/perftest/FillTest.java b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/FillTest.java
index 06b4af7..ba70c71 100644
--- a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/FillTest.java
+++ b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/FillTest.java
@@ -62,6 +62,9 @@
         mTests[index].testName = Allocation.createFromString(mRS,
                                                              mNames[index],
                                                              Allocation.USAGE_SCRIPT);
+        mTests[index].debugName = RsBenchRS.createZeroTerminatedAlloc(mRS,
+                                                                      mNames[index],
+                                                                      Allocation.USAGE_SCRIPT);
 
         ScriptField_FillTestData_s.Item dataItem = new ScriptField_FillTestData_s.Item();
         dataItem.testId = testId;
diff --git a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/MeshTest.java b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/MeshTest.java
index f39e7db..cdb4435 100644
--- a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/MeshTest.java
+++ b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/MeshTest.java
@@ -69,6 +69,9 @@
         mTests[index].testName = Allocation.createFromString(mRS,
                                                              mNames[index],
                                                              Allocation.USAGE_SCRIPT);
+        mTests[index].debugName = RsBenchRS.createZeroTerminatedAlloc(mRS,
+                                                                      mNames[index],
+                                                                      Allocation.USAGE_SCRIPT);
 
         ScriptField_MeshTestData_s.Item dataItem = new ScriptField_MeshTestData_s.Item();
         dataItem.meshNum = meshNum;
diff --git a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/RsBench.java b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/RsBench.java
index 4ed42b4..0dceafe 100644
--- a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/RsBench.java
+++ b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/RsBench.java
@@ -95,8 +95,10 @@
         switch (item.getItemId()) {
             case R.id.benchmark_all:
                 mView.setBenchmarkMode(-1);
+                mView.suspendRendering(false);
                 return true;
             case R.id.benchmark_one:
+                mView.suspendRendering(true);
                 AlertDialog.Builder builder = new AlertDialog.Builder(this);
                 builder.setTitle("Pick a Test");
                 builder.setItems(mView.getTestNames(),
@@ -106,11 +108,13 @@
                                        "Starting to benchmark: " + mView.getTestNames()[item],
                                        Toast.LENGTH_SHORT).show();
                         mView.setBenchmarkMode(item);
+                        mView.suspendRendering(false);
                     }
                 });
                 builder.show();
                 return true;
             case R.id.debug_mode:
+                mView.suspendRendering(true);
                 AlertDialog.Builder debugBuilder = new AlertDialog.Builder(this);
                 debugBuilder.setTitle("Pick a Test");
                 debugBuilder.setItems(mView.getTestNames(),
@@ -120,6 +124,7 @@
                                        "Switching to: " + mView.getTestNames()[item],
                                        Toast.LENGTH_SHORT).show();
                         mView.setDebugMode(item);
+                        mView.suspendRendering(false);
                     }
                 });
                 debugBuilder.show();
diff --git a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/RsBenchRS.java b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/RsBenchRS.java
index c51bd82..4ac7dd5 100644
--- a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/RsBenchRS.java
+++ b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/RsBenchRS.java
@@ -60,7 +60,6 @@
         mWidth = width;
         mHeight = height;
         mMode = 0;
-        mMaxModes = 0;
         mLoops = loops;
         mCurrentLoop = 0;
         mBenchmarkDimX = 1280;
@@ -88,11 +87,30 @@
     ScriptField_TestScripts_s.Item[] mIndividualTests;
 
     int mMode;
-    int mMaxModes;
 
     String[] mTestNames;
     float[] mLocalTestResults;
 
+    static Allocation createZeroTerminatedAlloc(RenderScript rs,
+                                                String str,
+                                                int usage) {
+        byte[] allocArray = null;
+        try {
+            allocArray = str.getBytes("UTF-8");
+            byte[] allocArrayZero = new byte[allocArray.length + 1];
+            System.arraycopy(allocArray, 0, allocArrayZero, 0, allocArray.length);
+            allocArrayZero[allocArrayZero.length - 1] = '\0';
+            Allocation alloc = Allocation.createSized(rs, Element.U8(rs),
+                                                      allocArrayZero.length, usage);
+            alloc.copyFrom(allocArrayZero);
+            return alloc;
+        }
+        catch (Exception e) {
+            throw new RSRuntimeException("Could not convert string to utf-8.");
+        }
+
+    }
+
     void appendTests(RsBenchBaseTest testSet) {
         ScriptField_TestScripts_s.Item[] newTests = testSet.getTests();
         if (mIndividualTests != null) {
@@ -119,6 +137,7 @@
 
     void createTestAllocation() {
         int numTests = mIndividualTests.length;
+        mLocalTestResults = new float[numTests];
         ScriptField_TestScripts_s allTests;
         allTests = new ScriptField_TestScripts_s(mRS, numTests);
         for (int i = 0; i < numTests; i ++) {
@@ -239,11 +258,6 @@
         return count;
     }
 
-    private void prepareTestData() {
-        mTestNames = new String[mMaxModes];
-        mLocalTestResults = new float[mMaxModes];
-    }
-
     public void setDebugMode(int num) {
         mScript.invoke_setDebugMode(num);
     }
@@ -252,6 +266,10 @@
         mScript.invoke_setBenchmarkMode(benchNum);
     }
 
+    public void pause(boolean pause) {
+        mScript.set_gPauseRendering(pause);
+    }
+
     private void initRS() {
 
         mScript = new ScriptC_rsbench(mRS, mRes, R.raw.rsbench);
@@ -261,8 +279,6 @@
 
         mScript.set_gMaxLoops(mLoops);
 
-        prepareTestData();
-
         initProgramVertex();
         initProgramFragment();
         mScript.set_gFontSerif(Font.create(mRS, mRes, "serif", Font.Style.NORMAL, 8));
diff --git a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/RsBenchView.java b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/RsBenchView.java
index 004e6bf..124071e 100644
--- a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/RsBenchView.java
+++ b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/RsBenchView.java
@@ -92,6 +92,10 @@
         mRender.setBenchmarkMode(benchNum);
     }
 
+    void suspendRendering(boolean pause) {
+        mRender.pause(pause);
+    }
+
     void setDebugMode(int num) {
         mRender.setDebugMode(num);
     }
diff --git a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/TextTest.java b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/TextTest.java
index ca9e660..3ca2792 100644
--- a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/TextTest.java
+++ b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/TextTest.java
@@ -48,6 +48,9 @@
         mTests[index].testName = Allocation.createFromString(mRS,
                                                              mNames[index],
                                                              Allocation.USAGE_SCRIPT);
+        mTests[index].debugName = RsBenchRS.createZeroTerminatedAlloc(mRS,
+                                                                     mNames[index],
+                                                                     Allocation.USAGE_SCRIPT);
 
         ScriptField_TextTestData_s.Item dataItem = new ScriptField_TextTestData_s.Item();
         dataItem.fillNum = fillNum;
diff --git a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/TorusTest.java b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/TorusTest.java
index d785dc1..5c9ecd5 100644
--- a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/TorusTest.java
+++ b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/TorusTest.java
@@ -98,6 +98,9 @@
         mTests[index].testName = Allocation.createFromString(mRS,
                                                              mNames[index],
                                                              Allocation.USAGE_SCRIPT);
+        mTests[index].debugName = RsBenchRS.createZeroTerminatedAlloc(mRS,
+                                                                      mNames[index],
+                                                                      Allocation.USAGE_SCRIPT);
 
         ScriptField_TorusTestData_s.Item dataItem = new ScriptField_TorusTestData_s.Item();
         dataItem.testId = testId;
diff --git a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/UiTest.java b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/UiTest.java
index cca237e..c8b58b2 100644
--- a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/UiTest.java
+++ b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/UiTest.java
@@ -82,6 +82,9 @@
         mTests[index].testName = Allocation.createFromString(mRS,
                                                              mNames[index],
                                                              Allocation.USAGE_SCRIPT);
+        mTests[index].debugName = RsBenchRS.createZeroTerminatedAlloc(mRS,
+                                                                      mNames[index],
+                                                                      Allocation.USAGE_SCRIPT);
 
         ScriptField_UiTestData_s.Item dataItem = new ScriptField_UiTestData_s.Item();
         dataItem.testId = testId;
diff --git a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/rsbench.rs b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/rsbench.rs
index 2b849a2..27e5b11 100644
--- a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/rsbench.rs
+++ b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/rsbench.rs
@@ -45,11 +45,13 @@
 typedef struct TestScripts_s {
     rs_allocation testData;
     rs_allocation testName;
+    rs_allocation debugName;
     rs_script testScript;
 } TestScripts;
 TestScripts *gTestScripts;
 
 bool gLoadComplete = false;
+bool gPauseRendering = false;
 
 static float gDt = 0;
 
@@ -195,7 +197,8 @@
 
     int64_t end = rsUptimeMillis();
     float fps = (float)(frameCount) / ((float)(end - start)*0.001f);
-    rsDebug("Finishes test ", fps);
+    const char *testName = rsGetElementAt(gTestScripts[benchMode].debugName, 0);
+    rsDebug(testName, fps);
 
     gResultBuffer[benchMode] = fps;
     int bufferW = rsAllocationGetDimX(gRenderBufferColor);
@@ -255,6 +258,10 @@
         return 1;
     }
 
+    if (gPauseRendering) {
+        rsgDrawText("Paused", 50, 50);
+        return 30;
+    }
     if (gIsDebugMode) {
         debug();
     } else {
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/tests/StatusBar/res/layout/notification_builder_test.xml b/tests/StatusBar/res/layout/notification_builder_test.xml
index e1199c7..6c384f7 100644
--- a/tests/StatusBar/res/layout/notification_builder_test.xml
+++ b/tests/StatusBar/res/layout/notification_builder_test.xml
@@ -605,6 +605,11 @@
                         style="@style/FieldContents"
                         android:text="pineapple2"
                         />
+                <RadioButton
+                        android:id="@+id/large_icon_small"
+                        style="@style/FieldContents"
+                        android:text="small"
+                        />
             </RadioGroup>
             
 
diff --git a/tests/StatusBar/src/com/android/statusbartest/NotificationBuilderTest.java b/tests/StatusBar/src/com/android/statusbartest/NotificationBuilderTest.java
index 5a2ebac..fefd890 100644
--- a/tests/StatusBar/src/com/android/statusbartest/NotificationBuilderTest.java
+++ b/tests/StatusBar/src/com/android/statusbartest/NotificationBuilderTest.java
@@ -287,6 +287,9 @@
             case R.id.large_icon_pineapple2:
                 b.setLargeIcon(loadBitmap(R.drawable.pineapple2));
                 break;
+            case R.id.large_icon_small:
+                b.setLargeIcon(loadBitmap(R.drawable.icon2));
+                break;
         }
 
         // sound TODO
diff --git a/tools/aapt/Command.cpp b/tools/aapt/Command.cpp
index 637c27d..d7ac15e 100644
--- a/tools/aapt/Command.cpp
+++ b/tools/aapt/Command.cpp
@@ -625,6 +625,11 @@
             bool actImeService = false;
             bool actWallpaperService = false;
 
+            // These two implement the implicit permissions that are granted
+            // to pre-1.6 applications.
+            bool hasWriteExternalStoragePermission = false;
+            bool hasReadPhoneStatePermission = false;
+
             // This next group of variables is used to implement a group of
             // backward-compatibility heuristics necessitated by the addition of
             // some new uses-feature constants in 2.1 and 2.2. In most cases, the
@@ -986,6 +991,10 @@
                                        name == "android.permission.WRITE_APN_SETTINGS" ||
                                        name == "android.permission.WRITE_SMS") {
                                 hasTelephonyPermission = true;
+                            } else if (name == "android.permission.WRITE_EXTERNAL_STORAGE") {
+                                hasWriteExternalStoragePermission = true;
+                            } else if (name == "android.permission.READ_PHONE_STATE") {
+                                hasReadPhoneStatePermission = true;
                             }
                             printf("uses-permission:'%s'\n", name.string());
                         } else {
@@ -1144,6 +1153,16 @@
                 }
             }
 
+            // Pre-1.6 implicitly granted permission compatibility logic
+            if (targetSdk < 4) {
+                if (!hasWriteExternalStoragePermission) {
+                    printf("uses-permission:'android.permission.WRITE_EXTERNAL_STORAGE'\n");
+                }
+                if (!hasReadPhoneStatePermission) {
+                    printf("uses-permission:'android.permission.READ_PHONE_STATE'\n");
+                }
+            }
+
             /* The following blocks handle printing "inferred" uses-features, based
              * on whether related features or permissions are used by the app.
              * Note that the various spec*Feature variables denote whether the
diff --git a/tools/layoutlib/bridge/src/android/animation/AnimationThread.java b/tools/layoutlib/bridge/src/android/animation/AnimationThread.java
index 2b5e4fa..af83c61 100644
--- a/tools/layoutlib/bridge/src/android/animation/AnimationThread.java
+++ b/tools/layoutlib/bridge/src/android/animation/AnimationThread.java
@@ -86,8 +86,11 @@
         try {
             Handler_Delegate.setCallback(new IHandlerCallback() {
                 public void sendMessageAtTime(Handler handler, Message msg, long uptimeMillis) {
-                    if (msg.what == ValueAnimator.ANIMATION_START ||
-                            msg.what == ValueAnimator.ANIMATION_FRAME) {
+                    if (msg.what == ValueAnimator.ANIMATION_START /*||
+                            FIXME: The ANIMATION_FRAME message no longer exists.  Instead,
+                            the animation timing loop is based on a Choreographer object
+                            that schedules animation and drawing frames.
+                            msg.what == ValueAnimator.ANIMATION_FRAME*/) {
                         mQueue.add(new MessageBundle(handler, msg, uptimeMillis));
                     } else {
                         // just ignore.
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/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index 40ac2a0..1a0e0da 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -413,6 +413,13 @@
     private static final int MAX_RSSI = -55;
 
     /**
+     * Number of RSSI levels used in the framework to initiate
+     * {@link #RSSI_CHANGED_ACTION} broadcast
+     * @hide
+     */
+    public static final int RSSI_LEVELS = 5;
+
+    /**
      * Auto settings in the driver. The driver could choose to operate on both
      * 2.4 GHz and 5 GHz or make a dynamic decision on selecting the band.
      * @hide
diff --git a/wifi/java/android/net/wifi/WifiNative.java b/wifi/java/android/net/wifi/WifiNative.java
index 65caa51..0fc0a45 100644
--- a/wifi/java/android/net/wifi/WifiNative.java
+++ b/wifi/java/android/net/wifi/WifiNative.java
@@ -239,6 +239,10 @@
         return WifiNative.doBooleanCommand("SET config_methods " + cfg);
     }
 
+    public static boolean setP2pSsidPostfix(String postfix) {
+        return WifiNative.doBooleanCommand("SET p2p_ssid_postfix " + postfix);
+    }
+
     public static boolean p2pFind() {
         return doBooleanCommand("P2P_FIND");
     }
diff --git a/wifi/java/android/net/wifi/WifiStateMachine.java b/wifi/java/android/net/wifi/WifiStateMachine.java
index 253e0ec..920947f 100644
--- a/wifi/java/android/net/wifi/WifiStateMachine.java
+++ b/wifi/java/android/net/wifi/WifiStateMachine.java
@@ -306,8 +306,6 @@
     static final int CMD_SET_HIGH_PERF_MODE               = BASE + 77;
     /* Set the country code */
     static final int CMD_SET_COUNTRY_CODE                 = BASE + 80;
-    /* Request connectivity manager wake lock before driver stop */
-    static final int CMD_REQUEST_CM_WAKELOCK              = BASE + 81;
     /* Enables RSSI poll */
     static final int CMD_ENABLE_RSSI_POLL                 = BASE + 82;
     /* RSSI poll */
@@ -1061,15 +1059,6 @@
         return result;
     }
 
-    /**
-     * Request a wakelock with connectivity service to
-     * keep the device awake until we hand-off from wifi
-     * to an alternate network
-     */
-    public void requestCmWakeLock() {
-        sendMessage(CMD_REQUEST_CM_WAKELOCK);
-    }
-
     public void updateBatteryWorkSource(WorkSource newSource) {
         synchronized (mRunningWifiUids) {
             try {
@@ -1469,14 +1458,11 @@
              * be displayed in the status bar, and only send the
              * broadcast if that much more coarse-grained number
              * changes. This cuts down greatly on the number of
-             * broadcasts, at the cost of not mWifiInforming others
+             * broadcasts, at the cost of not informing others
              * interested in RSSI of all the changes in signal
              * level.
              */
-            // TODO: The second arg to the call below needs to be a symbol somewhere, but
-            // it's actually the size of an array of icons that's private
-            // to StatusBar Policy.
-            int newSignalLevel = WifiManager.calculateSignalLevel(newRssi, 4);
+            int newSignalLevel = WifiManager.calculateSignalLevel(newRssi, WifiManager.RSSI_LEVELS);
             if (newSignalLevel != mLastSignalLevel) {
                 sendRssiChangeBroadcast(newRssi);
             }
@@ -1867,7 +1853,6 @@
                 case CMD_SET_HIGH_PERF_MODE:
                 case CMD_SET_COUNTRY_CODE:
                 case CMD_SET_FREQUENCY_BAND:
-                case CMD_REQUEST_CM_WAKELOCK:
                 case CMD_CONNECT_NETWORK:
                 case CMD_SAVE_NETWORK:
                 case CMD_FORGET_NETWORK:
@@ -3024,10 +3009,6 @@
                     WifiNative.disconnectCommand();
                     transitionTo(mDisconnectingState);
                     break;
-                case CMD_REQUEST_CM_WAKELOCK:
-                    checkAndSetConnectivityInstance();
-                    mCm.requestNetworkTransitionWakelock(TAG);
-                    break;
                 case CMD_SET_SCAN_MODE:
                     if (message.arg1 == SCAN_ONLY_MODE) {
                         sendMessage(CMD_DISCONNECT);
@@ -3100,6 +3081,11 @@
         }
         @Override
         public void exit() {
+
+            /* Request a CS wakelock during transition to mobile */
+            checkAndSetConnectivityInstance();
+            mCm.requestNetworkTransitionWakelock(TAG);
+
             /* If a scan result is pending in connected state, the supplicant
              * is in SCAN_ONLY_MODE. Restore CONNECT_MODE on exit
              */
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;
         }
     }
diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pGroup.java b/wifi/java/android/net/wifi/p2p/WifiP2pGroup.java
index 9473993..e141aba 100644
--- a/wifi/java/android/net/wifi/p2p/WifiP2pGroup.java
+++ b/wifi/java/android/net/wifi/p2p/WifiP2pGroup.java
@@ -172,6 +172,12 @@
         return mClients.size() == 0;
     }
 
+    /** @hide Returns {@code true} if the device is part of the group */
+    public boolean contains(WifiP2pDevice device) {
+        if (mOwner.equals(device) || mClients.contains(device)) return true;
+        return false;
+    }
+
     /** Get the list of clients currently part of the p2p group */
     public Collection<WifiP2pDevice> getClientList() {
         return Collections.unmodifiableCollection(mClients);
diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pService.java b/wifi/java/android/net/wifi/p2p/WifiP2pService.java
index ceca78d..dede1b5 100644
--- a/wifi/java/android/net/wifi/p2p/WifiP2pService.java
+++ b/wifi/java/android/net/wifi/p2p/WifiP2pService.java
@@ -1088,16 +1088,13 @@
                     break;
                 case WifiMonitor.P2P_DEVICE_LOST_EVENT:
                     WifiP2pDevice device = (WifiP2pDevice) message.obj;
-                    if (device.equals(mGroup.getOwner())) {
-                        logd("Lost the group owner, killing p2p connection");
-                        WifiNative.p2pGroupRemove(mGroup.getInterface());
-                    } else if (mGroup.removeClient(device)) {
-                        if (!mPersistGroup && mGroup.isClientListEmpty()) {
-                            Slog.d(TAG, "Client list empty, removing a non-persistent p2p group");
-                            WifiNative.p2pGroupRemove(mGroup.getInterface());
-                        }
+                    //Device loss for a connected device indicates it is not in discovery any more
+                    if (mGroup.contains(device)) {
+                        if (DBG) logd("Lost " + device +" , do nothing");
+                        return HANDLED;
                     }
-                    return NOT_HANDLED; // Do the regular device lost handling
+                    // Do the regular device lost handling
+                    return NOT_HANDLED;
                 case WifiP2pManager.DISABLE_P2P:
                     sendMessage(WifiP2pManager.REMOVE_GROUP);
                     deferMessage(message);
@@ -1401,6 +1398,8 @@
     private void initializeP2pSettings() {
         WifiNative.setPersistentReconnect(true);
         WifiNative.setDeviceName(mThisDevice.deviceName);
+        //DIRECT-XY-DEVICENAME (XY is randomly generated)
+        WifiNative.setP2pSsidPostfix("-" + mThisDevice.deviceName);
         WifiNative.setDeviceType(mThisDevice.primaryDeviceType);
         //The supplicant default is to support everything, but a bug necessitates
         //the framework to specify this explicitly