Merge "Add accessibility actions for text editing."
diff --git a/api/current.txt b/api/current.txt
index 235c1b7..ab91974 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -36,6 +36,8 @@
     field public static final java.lang.String CALL_PHONE = "android.permission.CALL_PHONE";
     field public static final java.lang.String CALL_PRIVILEGED = "android.permission.CALL_PRIVILEGED";
     field public static final java.lang.String CAMERA = "android.permission.CAMERA";
+    field public static final java.lang.String CAN_REQUEST_ENHANCED_WEB_ACCESSIBILITY = "android.permission.CAN_REQUEST_ENHANCED_WEB_ACCESSIBILITY";
+    field public static final java.lang.String CAN_REQUEST_TOUCH_EXPLORATION_MODE = "android.permission.CAN_REQUEST_TOUCH_EXPLORATION_MODE";
     field public static final java.lang.String CHANGE_COMPONENT_ENABLED_STATE = "android.permission.CHANGE_COMPONENT_ENABLED_STATE";
     field public static final java.lang.String CHANGE_CONFIGURATION = "android.permission.CHANGE_CONFIGURATION";
     field public static final java.lang.String CHANGE_NETWORK_STATE = "android.permission.CHANGE_NETWORK_STATE";
@@ -141,6 +143,7 @@
 
   public static final class Manifest.permission_group {
     ctor public Manifest.permission_group();
+    field public static final java.lang.String ACCESSIBILITY_FEATURES = "android.permission-group.ACCESSIBILITY_FEATURES";
     field public static final java.lang.String ACCOUNTS = "android.permission-group.ACCOUNTS";
     field public static final java.lang.String AFFECTS_BATTERY = "android.permission-group.AFFECTS_BATTERY";
     field public static final java.lang.String APP_INFO = "android.permission-group.APP_INFO";
@@ -2104,7 +2107,8 @@
     field public static final int FEEDBACK_SPOKEN = 1; // 0x1
     field public static final int FEEDBACK_VISUAL = 8; // 0x8
     field public static final int FLAG_INCLUDE_NOT_IMPORTANT_VIEWS = 2; // 0x2
-    field public static final int FLAG_REPORT_VIEW_IDS = 8; // 0x8
+    field public static final int FLAG_REPORT_VIEW_IDS = 16; // 0x10
+    field public static final int FLAG_REQUEST_ENHANCED_WEB_ACCESSIBILITY = 8; // 0x8
     field public static final int FLAG_REQUEST_TOUCH_EXPLORATION_MODE = 4; // 0x4
     field public int eventTypes;
     field public int feedbackType;
@@ -5931,6 +5935,7 @@
     field public static final java.lang.String CATEGORY_UNIT_TEST = "android.intent.category.UNIT_TEST";
     field public static final android.os.Parcelable.Creator CREATOR;
     field public static final java.lang.String EXTRA_ALARM_COUNT = "android.intent.extra.ALARM_COUNT";
+    field public static final java.lang.String EXTRA_ALLOW_MULTIPLE = "android.intent.extra.ALLOW_MULTIPLE";
     field public static final deprecated java.lang.String EXTRA_ALLOW_REPLACE = "android.intent.extra.ALLOW_REPLACE";
     field public static final java.lang.String EXTRA_ASSIST_CONTEXT = "android.intent.extra.ASSIST_CONTEXT";
     field public static final java.lang.String EXTRA_ASSIST_PACKAGE = "android.intent.extra.ASSIST_PACKAGE";
@@ -20653,21 +20658,23 @@
   public class TextToSpeech.Engine {
     ctor public TextToSpeech.Engine();
     field public static final java.lang.String ACTION_CHECK_TTS_DATA = "android.speech.tts.engine.CHECK_TTS_DATA";
+    field public static final java.lang.String ACTION_GET_SAMPLE_TEXT = "android.speech.tts.engine.GET_SAMPLE_TEXT";
     field public static final java.lang.String ACTION_INSTALL_TTS_DATA = "android.speech.tts.engine.INSTALL_TTS_DATA";
     field public static final java.lang.String ACTION_TTS_DATA_INSTALLED = "android.speech.tts.engine.TTS_DATA_INSTALLED";
-    field public static final int CHECK_VOICE_DATA_BAD_DATA = -1; // 0xffffffff
+    field public static final deprecated int CHECK_VOICE_DATA_BAD_DATA = -1; // 0xffffffff
     field public static final int CHECK_VOICE_DATA_FAIL = 0; // 0x0
-    field public static final int CHECK_VOICE_DATA_MISSING_DATA = -2; // 0xfffffffe
-    field public static final int CHECK_VOICE_DATA_MISSING_VOLUME = -3; // 0xfffffffd
+    field public static final deprecated int CHECK_VOICE_DATA_MISSING_DATA = -2; // 0xfffffffe
+    field public static final deprecated int CHECK_VOICE_DATA_MISSING_VOLUME = -3; // 0xfffffffd
     field public static final int CHECK_VOICE_DATA_PASS = 1; // 0x1
     field public static final int DEFAULT_STREAM = 3; // 0x3
     field public static final java.lang.String EXTRA_AVAILABLE_VOICES = "availableVoices";
-    field public static final java.lang.String EXTRA_CHECK_VOICE_DATA_FOR = "checkVoiceDataFor";
-    field public static final java.lang.String EXTRA_TTS_DATA_INSTALLED = "dataInstalled";
+    field public static final deprecated java.lang.String EXTRA_CHECK_VOICE_DATA_FOR = "checkVoiceDataFor";
+    field public static final java.lang.String EXTRA_SAMPLE_TEXT = "sampleText";
+    field public static final deprecated java.lang.String EXTRA_TTS_DATA_INSTALLED = "dataInstalled";
     field public static final java.lang.String EXTRA_UNAVAILABLE_VOICES = "unavailableVoices";
-    field public static final java.lang.String EXTRA_VOICE_DATA_FILES = "dataFiles";
-    field public static final java.lang.String EXTRA_VOICE_DATA_FILES_INFO = "dataFilesInfo";
-    field public static final java.lang.String EXTRA_VOICE_DATA_ROOT_DIRECTORY = "dataRoot";
+    field public static final deprecated java.lang.String EXTRA_VOICE_DATA_FILES = "dataFiles";
+    field public static final deprecated java.lang.String EXTRA_VOICE_DATA_FILES_INFO = "dataFilesInfo";
+    field public static final deprecated java.lang.String EXTRA_VOICE_DATA_ROOT_DIRECTORY = "dataRoot";
     field public static final java.lang.String INTENT_ACTION_TTS_SERVICE = "android.intent.action.TTS_SERVICE";
     field public static final java.lang.String KEY_FEATURE_EMBEDDED_SYNTHESIS = "embeddedTts";
     field public static final java.lang.String KEY_FEATURE_NETWORK_SYNTHESIS = "networkTts";
@@ -20689,7 +20696,7 @@
     method public abstract void onInit(int);
   }
 
-  public static abstract interface TextToSpeech.OnUtteranceCompletedListener {
+  public static abstract deprecated interface TextToSpeech.OnUtteranceCompletedListener {
     method public abstract void onUtteranceCompleted(java.lang.String);
   }
 
diff --git a/cmds/content/src/com/android/commands/content/Content.java b/cmds/content/src/com/android/commands/content/Content.java
index 2ae2071..c0a1e3b 100644
--- a/cmds/content/src/com/android/commands/content/Content.java
+++ b/cmds/content/src/com/android/commands/content/Content.java
@@ -24,6 +24,7 @@
 import android.database.Cursor;
 import android.net.Uri;
 import android.os.Binder;
+import android.os.Bundle;
 import android.os.IBinder;
 import android.os.UserHandle;
 import android.text.TextUtils;
@@ -102,6 +103,12 @@
                 + "equal to \"new_setting\" and sort the result by name in ascending order.\n"
         + "  adb shell content query --uri content://settings/secure --projection name:value"
                 + " --where \"name=\'new_setting\'\" --sort \"name ASC\"\n"
+        + "\n"
+        + "usage: adb shell content call --uri <URI> --method <METHOD> [--arg <ARG>]\n"
+        + "       [--extra <BINDING> ...]\n"
+        + "  <METHOD> is the name of a provider-defined method\n"
+        + "  <ARG> is an optional string argument\n"
+        + "  <BINDING> is like --bind above, typed data of the form <KEY>:{b,s,i,l,f,d}:<VAL>\n"
         + "\n";
 
     private static class Parser {
@@ -109,12 +116,16 @@
         private static final String ARGUMENT_DELETE = "delete";
         private static final String ARGUMENT_UPDATE = "update";
         private static final String ARGUMENT_QUERY = "query";
+        private static final String ARGUMENT_CALL = "call";
         private static final String ARGUMENT_WHERE = "--where";
         private static final String ARGUMENT_BIND = "--bind";
         private static final String ARGUMENT_URI = "--uri";
         private static final String ARGUMENT_USER = "--user";
         private static final String ARGUMENT_PROJECTION = "--projection";
         private static final String ARGUMENT_SORT = "--sort";
+        private static final String ARGUMENT_METHOD = "--method";
+        private static final String ARGUMENT_ARG = "--arg";
+        private static final String ARGUMENT_EXTRA = "--extra";
         private static final String TYPE_BOOLEAN = "b";
         private static final String TYPE_STRING = "s";
         private static final String TYPE_INTEGER = "i";
@@ -141,6 +152,8 @@
                     return parseUpdateCommand();
                 } else if (ARGUMENT_QUERY.equals(operation)) {
                     return parseQueryCommand();
+                } else if (ARGUMENT_CALL.equals(operation)) {
+                    return parseCallCommand();
                 } else {
                     throw new IllegalArgumentException("Unsupported operation: " + operation);
                 }
@@ -228,6 +241,38 @@
             return new UpdateCommand(uri, userId, values, where);
         }
 
+        public CallCommand parseCallCommand() {
+            String method = null;
+            int userId = UserHandle.USER_OWNER;
+            String arg = null;
+            Uri uri = null;
+            ContentValues values = new ContentValues();
+            for (String argument; (argument = mTokenizer.nextArg())!= null;) {
+                if (ARGUMENT_URI.equals(argument)) {
+                    uri = Uri.parse(argumentValueRequired(argument));
+                } else if (ARGUMENT_USER.equals(argument)) {
+                    userId = Integer.parseInt(argumentValueRequired(argument));
+                } else if (ARGUMENT_METHOD.equals(argument)) {
+                    method = argumentValueRequired(argument);
+                } else if (ARGUMENT_ARG.equals(argument)) {
+                    arg = argumentValueRequired(argument);
+                } else if (ARGUMENT_EXTRA.equals(argument)) {
+                    parseBindValue(values);
+                } else {
+                    throw new IllegalArgumentException("Unsupported argument: " + argument);
+                }
+
+            }
+            if (uri == null) {
+                throw new IllegalArgumentException("Content provider URI not specified."
+                        + " Did you specify --uri argument?");
+            }
+            if (method == null) {
+                throw new IllegalArgumentException("Content provider method not specified.");
+            }
+            return new CallCommand(uri, userId, method, arg, values);
+        }
+
         public QueryCommand parseQueryCommand() {
             Uri uri = null;
             int userId = UserHandle.USER_OWNER;
@@ -376,6 +421,43 @@
         }
     }
 
+    private static class CallCommand extends Command {
+        final String mMethod, mArg;
+        Bundle mExtras = null;
+
+        public CallCommand(Uri uri, int userId, String method, String arg, ContentValues values) {
+            super(uri, userId);
+            mMethod = method;
+            mArg = arg;
+            if (values != null) {
+                mExtras = new Bundle();
+                for (String key : values.keySet()) {
+                    final Object val = values.get(key);
+                    if (val instanceof String) {
+                        mExtras.putString(key, (String) val);
+                    } else if (val instanceof Float) {
+                        mExtras.putFloat(key, (Float) val);
+                    } else if (val instanceof Double) {
+                        mExtras.putDouble(key, (Double) val);
+                    } else if (val instanceof Boolean) {
+                        mExtras.putBoolean(key, (Boolean) val);
+                    } else if (val instanceof Integer) {
+                        mExtras.putInt(key, (Integer) val);
+                    } else if (val instanceof Long) {
+                        mExtras.putLong(key, (Long) val);
+                    }
+                }
+            }
+        }
+
+        @Override
+        public void onExecute(IContentProvider provider) throws Exception {
+            Bundle result = provider.call(null, mMethod, mArg, mExtras);
+            final int size = result.size(); // unpack
+            System.out.println("Result: " + result);
+        }
+    }
+
     private static class QueryCommand extends DeleteCommand {
         final String[] mProjection;
         final String mSortOrder;
diff --git a/core/java/android/accessibilityservice/AccessibilityServiceInfo.java b/core/java/android/accessibilityservice/AccessibilityServiceInfo.java
index 2006bc7..2dc0501 100644
--- a/core/java/android/accessibilityservice/AccessibilityServiceInfo.java
+++ b/core/java/android/accessibilityservice/AccessibilityServiceInfo.java
@@ -153,13 +153,25 @@
     public static final int FLAG_REQUEST_TOUCH_EXPLORATION_MODE= 0x0000004;
 
     /**
+     * This flag requests from the system to enable web accessibility enhancing
+     * extensions. Such extensions aim to provide improved accessibility support
+     * for content presented in a {@link android.webkit.WebView}. An example of such
+     * an extension is injecting JavaScript from Google. The system will enable
+     * enhanced web accessibility if there is at least one accessibility service
+     * that has this flag set. Hence, clearing this flag does not guarantee that the
+     * device will not have enhanced web accessibility enabled since there may be
+     * another enabled service that requested it.
+     */
+    public static final int FLAG_REQUEST_ENHANCED_WEB_ACCESSIBILITY = 0x00000008;
+
+    /**
      * This flag requests that the {@link AccessibilityNodeInfo}s obtained
      * by an {@link AccessibilityService} contain the id of the source view.
      * The source view id will be a fully qualified resource name of the
      * form "package:id/name", for example "foo.bar:id/my_list", and it is
      * useful for UI test automation. This flag is not set by default.
      */
-    public static final int FLAG_REPORT_VIEW_IDS = 0x00000008;
+    public static final int FLAG_REPORT_VIEW_IDS = 0x00000010;
 
     /**
      * The event types an {@link AccessibilityService} is interested in.
diff --git a/core/java/android/content/ContentProvider.java b/core/java/android/content/ContentProvider.java
index 4b977ab..e66efd5 100644
--- a/core/java/android/content/ContentProvider.java
+++ b/core/java/android/content/ContentProvider.java
@@ -191,11 +191,8 @@
                 String selection, String[] selectionArgs, String sortOrder,
                 ICancellationSignal cancellationSignal) {
             if (enforceReadPermission(callingPkg, uri) != AppOpsManager.MODE_ALLOWED) {
-                // The read is not allowed...  to fake it out, we replace the given
-                // selection statement with a dummy one that will always be false.
-                // This way we will get a cursor back that has the correct structure
-                // but contains no rows.
-                selection = "'A' = 'B'";
+                return rejectQuery(uri, projection, selection, selectionArgs, sortOrder,
+                        CancellationSignal.fromTransport(cancellationSignal));
             }
             return ContentProvider.this.query(uri, projection, selection, selectionArgs, sortOrder,
                     CancellationSignal.fromTransport(cancellationSignal));
@@ -209,12 +206,7 @@
         @Override
         public Uri insert(String callingPkg, Uri uri, ContentValues initialValues) {
             if (enforceWritePermission(callingPkg, uri) != AppOpsManager.MODE_ALLOWED) {
-                // If not allowed, we need to return some reasonable URI.  Maybe the
-                // content provider should be responsible for this, but for now we
-                // will just return the base URI with a dummy '0' tagged on to it.
-                // You shouldn't be able to read if you can't write, anyway, so it
-                // shouldn't matter much what is returned.
-                return uri.buildUpon().appendPath("0").build();
+                return rejectInsert(uri, initialValues);
             }
             return ContentProvider.this.insert(uri, initialValues);
         }
@@ -592,6 +584,31 @@
     }
 
     /**
+     * @hide
+     * Implementation when a caller has performed a query on the content
+     * provider, but that call has been rejected for the operation given
+     * to {@link #setAppOps(int, int)}.  The default implementation
+     * rewrites the <var>selection</var> argument to include a condition
+     * that is never true (so will always result in an empty cursor)
+     * and calls through to {@link #query(android.net.Uri, String[], String, String[],
+     * String, android.os.CancellationSignal)} with that.
+     */
+    public Cursor rejectQuery(Uri uri, String[] projection,
+            String selection, String[] selectionArgs, String sortOrder,
+            CancellationSignal cancellationSignal) {
+        // The read is not allowed...  to fake it out, we replace the given
+        // selection statement with a dummy one that will always be false.
+        // This way we will get a cursor back that has the correct structure
+        // but contains no rows.
+        if (selection == null) {
+            selection = "'A' = 'B'";
+        } else {
+            selection = "'A' = 'B' AND (" + selection + ")";
+        }
+        return query(uri, projection, selection, selectionArgs, sortOrder, cancellationSignal);
+    }
+
+    /**
      * Implement this to handle query requests from clients.
      * This method can be called from multiple threads, as described in
      * <a href="{@docRoot}guide/topics/fundamentals/processes-and-threads.html#Threads">Processes
@@ -739,6 +756,23 @@
     public abstract String getType(Uri uri);
 
     /**
+     * @hide
+     * Implementation when a caller has performed an insert on the content
+     * provider, but that call has been rejected for the operation given
+     * to {@link #setAppOps(int, int)}.  The default implementation simply
+     * returns a dummy URI that is the base URI with a 0 path element
+     * appended.
+     */
+    public Uri rejectInsert(Uri uri, ContentValues values) {
+        // If not allowed, we need to return some reasonable URI.  Maybe the
+        // content provider should be responsible for this, but for now we
+        // will just return the base URI with a dummy '0' tagged on to it.
+        // You shouldn't be able to read if you can't write, anyway, so it
+        // shouldn't matter much what is returned.
+        return uri.buildUpon().appendPath("0").build();
+    }
+
+    /**
      * Implement this to handle requests to insert a new row.
      * As a courtesy, call {@link ContentResolver#notifyChange(android.net.Uri ,android.database.ContentObserver) notifyChange()}
      * after inserting.
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index dc367dd..434946c 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -883,7 +883,7 @@
      * Activity Action: Allow the user to select a particular kind of data and
      * return it.  This is different than {@link #ACTION_PICK} in that here we
      * just say what kind of data is desired, not a URI of existing data from
-     * which the user can pick.  A ACTION_GET_CONTENT could allow the user to
+     * which the user can pick.  An ACTION_GET_CONTENT could allow the user to
      * create the data as it runs (for example taking a picture or recording a
      * sound), let them browse over the web and download the desired data,
      * etc.
@@ -917,12 +917,17 @@
      * from a remote server but not already on the local device (thus requiring
      * they be downloaded when opened).
      * <p>
+     * If the caller can handle multiple returned items (the user performing
+     * multiple selection), then it can specify {@link #EXTRA_ALLOW_MULTIPLE}
+     * to indicate this.
+     * <p>
      * Input: {@link #getType} is the desired MIME type to retrieve.  Note
      * that no URI is supplied in the intent, as there are no constraints on
      * where the returned data originally comes from.  You may also include the
      * {@link #CATEGORY_OPENABLE} if you can only accept data that can be
      * opened as a stream.  You may use {@link #EXTRA_LOCAL_ONLY} to limit content
-     * selection to local data.
+     * selection to local data.  You may use {@link #EXTRA_ALLOW_MULTIPLE} to
+     * allow the user to select multiple items.
      * <p>
      * Output: The URI of the item that was picked.  This must be a content:
      * URI so that any receiver can access it.
@@ -3045,6 +3050,17 @@
         "android.intent.extra.LOCAL_ONLY";
 
     /**
+     * Used to indicate that a {@link #ACTION_GET_CONTENT} intent can allow the
+     * user to select and return multiple items.  This is a boolean extra; the default
+     * is false.  If true, an implementation of ACTION_GET_CONTENT is allowed to
+     * present the user with a UI where they can pick multiple items that are all
+     * returned to the caller.  When this happens, they should be returned as
+     * the {@link #getClipData()} part of the result Intent.
+     */
+    public static final String EXTRA_ALLOW_MULTIPLE =
+        "android.intent.extra.ALLOW_MULTIPLE";
+
+    /**
      * The userHandle carried with broadcast intents related to addition, removal and switching of users
      * - {@link #ACTION_USER_ADDED}, {@link #ACTION_USER_REMOVED} and {@link #ACTION_USER_SWITCHED}.
      * @hide
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index 0445b39..a368451 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -210,6 +210,8 @@
     
     List<PackageInfo> getPreferredPackages(int flags);
 
+    void resetPreferredActivities(int userId);
+
     void addPreferredActivity(in IntentFilter filter, int match,
             in ComponentName[] set, in ComponentName activity, int userId);
 
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 3d850cf..be21fb4 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -3351,6 +3351,7 @@
          *
          * @hide
          */
+        @Deprecated
         public static final String TOUCH_EXPLORATION_GRANTED_ACCESSIBILITY_SERVICES =
             "touch_exploration_granted_accessibility_services";
 
diff --git a/core/java/android/speech/tts/TextToSpeech.java b/core/java/android/speech/tts/TextToSpeech.java
index f52b5e3..c1af7a5 100644
--- a/core/java/android/speech/tts/TextToSpeech.java
+++ b/core/java/android/speech/tts/TextToSpeech.java
@@ -140,7 +140,10 @@
      * Listener that will be called when the TTS service has
      * completed synthesizing an utterance. This is only called if the utterance
      * has an utterance ID (see {@link TextToSpeech.Engine#KEY_PARAM_UTTERANCE_ID}).
+     *
+     * @deprecated Use {@link UtteranceProgressListener} instead.
      */
+    @Deprecated
     public interface OnUtteranceCompletedListener {
         /**
          * Called when an utterance has been synthesized.
@@ -236,19 +239,28 @@
         /**
          * Indicates erroneous data when checking the installation status of the resources used by
          * the TextToSpeech engine with the {@link #ACTION_CHECK_TTS_DATA} intent.
+         *
+         * @deprecated Use CHECK_VOICE_DATA_FAIL instead.
          */
+        @Deprecated
         public static final int CHECK_VOICE_DATA_BAD_DATA = -1;
 
         /**
          * Indicates missing resources when checking the installation status of the resources used
          * by the TextToSpeech engine with the {@link #ACTION_CHECK_TTS_DATA} intent.
+         *
+         * @deprecated Use CHECK_VOICE_DATA_FAIL instead.
          */
+        @Deprecated
         public static final int CHECK_VOICE_DATA_MISSING_DATA = -2;
 
         /**
          * Indicates missing storage volume when checking the installation status of the resources
          * used by the TextToSpeech engine with the {@link #ACTION_CHECK_TTS_DATA} intent.
+         *
+         * @deprecated Use CHECK_VOICE_DATA_FAIL instead.
          */
+        @Deprecated
         public static final int CHECK_VOICE_DATA_MISSING_VOLUME = -3;
 
         /**
@@ -284,9 +296,8 @@
                 "android.speech.tts.engine.INSTALL_TTS_DATA";
 
         /**
-         * Broadcast Action: broadcast to signal the completion of the installation of
-         * the data files used by the synthesis engine. Success or failure is indicated in the
-         * {@link #EXTRA_TTS_DATA_INSTALLED} extra.
+         * Broadcast Action: broadcast to signal the change in the list of available
+         * languages or/and their features.
          */
         @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
         public static final String ACTION_TTS_DATA_INSTALLED =
@@ -299,20 +310,16 @@
          * return one of the following codes:
          * {@link #CHECK_VOICE_DATA_PASS},
          * {@link #CHECK_VOICE_DATA_FAIL},
-         * {@link #CHECK_VOICE_DATA_BAD_DATA},
-         * {@link #CHECK_VOICE_DATA_MISSING_DATA}, or
-         * {@link #CHECK_VOICE_DATA_MISSING_VOLUME}.
          * <p> Moreover, the data received in the activity result will contain the following
          * fields:
          * <ul>
-         *   <li>{@link #EXTRA_VOICE_DATA_ROOT_DIRECTORY} which
-         *       indicates the path to the location of the resource files,</li>
-         *   <li>{@link #EXTRA_VOICE_DATA_FILES} which contains
-         *       the list of all the resource files,</li>
-         *   <li>and {@link #EXTRA_VOICE_DATA_FILES_INFO} which
-         *       contains, for each resource file, the description of the language covered by
-         *       the file in the xxx-YYY format, where xxx is the 3-letter ISO language code,
-         *       and YYY is the 3-letter ISO country code.</li>
+         *   <li>{@link #EXTRA_AVAILABLE_VOICES} which contains an ArrayList<String> of all the
+         *   available voices. The format of each voice is: lang-COUNTRY-variant where COUNTRY and
+         *   variant are optional (ie, "eng" or "eng-USA" or "eng-USA-FEMALE").</li>
+         *   <li>{@link #EXTRA_UNAVAILABLE_VOICES} which contains an ArrayList<String> of all the
+         *   unavailable voices (ones that user can install). The format of each voice is:
+         *   lang-COUNTRY-variant where COUNTRY and variant are optional (ie, "eng" or
+         *   "eng-USA" or "eng-USA-FEMALE").</li>
          * </ul>
          */
         @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
@@ -320,37 +327,33 @@
                 "android.speech.tts.engine.CHECK_TTS_DATA";
 
         /**
-         * Activity intent for getting some sample text to use for demonstrating TTS.
+         * Activity intent for getting some sample text to use for demonstrating TTS. Specific
+         * locale have to be requested by passing following extra parameters:
+         * <ul>
+         *   <li>language</li>
+         *   <li>country</li>
+         *   <li>variant</li>
+         * </ul>
          *
-         * @hide This intent was used by engines written against the old API.
-         * Not sure if it should be exposed.
+         * Upon completion, the activity result may contain the following fields:
+         * <ul>
+         *   <li>{@link #EXTRA_SAMPLE_TEXT} which contains an String with sample text.</li>
+         * </ul>
          */
         @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
         public static final String ACTION_GET_SAMPLE_TEXT =
                 "android.speech.tts.engine.GET_SAMPLE_TEXT";
 
+        /**
+         * Extra information received with the {@link #ACTION_GET_SAMPLE_TEXT} intent result where
+         * the TextToSpeech engine returns an String with sample text for requested voice
+         */
+        public static final String EXTRA_SAMPLE_TEXT = "sampleText";
+
+
         // extras for a TTS engine's check data activity
         /**
-         * Extra information received with the {@link #ACTION_CHECK_TTS_DATA} intent where
-         * the TextToSpeech engine specifies the path to its resources.
-         */
-        public static final String EXTRA_VOICE_DATA_ROOT_DIRECTORY = "dataRoot";
-
-        /**
-         * Extra information received with the {@link #ACTION_CHECK_TTS_DATA} intent where
-         * the TextToSpeech engine specifies the file names of its resources under the
-         * resource path.
-         */
-        public static final String EXTRA_VOICE_DATA_FILES = "dataFiles";
-
-        /**
-         * Extra information received with the {@link #ACTION_CHECK_TTS_DATA} intent where
-         * the TextToSpeech engine specifies the locale associated with each resource file.
-         */
-        public static final String EXTRA_VOICE_DATA_FILES_INFO = "dataFilesInfo";
-
-        /**
-         * Extra information received with the {@link #ACTION_CHECK_TTS_DATA} intent where
+         * Extra information received with the {@link #ACTION_CHECK_TTS_DATA} intent result where
          * the TextToSpeech engine returns an ArrayList<String> of all the available voices.
          * The format of each voice is: lang-COUNTRY-variant where COUNTRY and variant are
          * optional (ie, "eng" or "eng-USA" or "eng-USA-FEMALE").
@@ -358,7 +361,7 @@
         public static final String EXTRA_AVAILABLE_VOICES = "availableVoices";
 
         /**
-         * Extra information received with the {@link #ACTION_CHECK_TTS_DATA} intent where
+         * Extra information received with the {@link #ACTION_CHECK_TTS_DATA} intent result where
          * the TextToSpeech engine returns an ArrayList<String> of all the unavailable voices.
          * The format of each voice is: lang-COUNTRY-variant where COUNTRY and variant are
          * optional (ie, "eng" or "eng-USA" or "eng-USA-FEMALE").
@@ -366,22 +369,63 @@
         public static final String EXTRA_UNAVAILABLE_VOICES = "unavailableVoices";
 
         /**
+         * Extra information received with the {@link #ACTION_CHECK_TTS_DATA} intent result where
+         * the TextToSpeech engine specifies the path to its resources.
+         *
+         * It may be used by language packages to find out where to put their data.
+         *
+         * @deprecated TTS engine implementation detail, this information has no use for
+         * text-to-speech API client.
+         */
+        @Deprecated
+        public static final String EXTRA_VOICE_DATA_ROOT_DIRECTORY = "dataRoot";
+
+        /**
+         * Extra information received with the {@link #ACTION_CHECK_TTS_DATA} intent result where
+         * the TextToSpeech engine specifies the file names of its resources under the
+         * resource path.
+         *
+         * @deprecated TTS engine implementation detail, this information has no use for
+         * text-to-speech API client.
+         */
+        @Deprecated
+        public static final String EXTRA_VOICE_DATA_FILES = "dataFiles";
+
+        /**
+         * Extra information received with the {@link #ACTION_CHECK_TTS_DATA} intent result where
+         * the TextToSpeech engine specifies the locale associated with each resource file.
+         *
+         * @deprecated TTS engine implementation detail, this information has no use for
+         * text-to-speech API client.
+         */
+        @Deprecated
+        public static final String EXTRA_VOICE_DATA_FILES_INFO = "dataFilesInfo";
+
+        /**
          * Extra information sent with the {@link #ACTION_CHECK_TTS_DATA} intent where the
          * caller indicates to the TextToSpeech engine which specific sets of voice data to
          * check for by sending an ArrayList<String> of the voices that are of interest.
          * The format of each voice is: lang-COUNTRY-variant where COUNTRY and variant are
          * optional (ie, "eng" or "eng-USA" or "eng-USA-FEMALE").
+         *
+         * @deprecated Redundant functionality, checking for existence of specific sets of voice
+         * data can be done on client side.
          */
+        @Deprecated
         public static final String EXTRA_CHECK_VOICE_DATA_FOR = "checkVoiceDataFor";
 
         // extras for a TTS engine's data installation
         /**
-         * Extra information received with the {@link #ACTION_TTS_DATA_INSTALLED} intent.
+         * Extra information received with the {@link #ACTION_TTS_DATA_INSTALLED} intent result.
          * It indicates whether the data files for the synthesis engine were successfully
          * installed. The installation was initiated with the  {@link #ACTION_INSTALL_TTS_DATA}
          * intent. The possible values for this extra are
          * {@link TextToSpeech#SUCCESS} and {@link TextToSpeech#ERROR}.
+         *
+         * @deprecated No longer in use. If client ise interested in information about what
+         * changed, is should send ACTION_CHECK_TTS_DATA intent to discover available voices.
          */
+        @Deprecated
         public static final String EXTRA_TTS_DATA_INSTALLED = "dataInstalled";
 
         // keys for the parameters passed with speak commands. Hidden keys are used internally
@@ -474,6 +518,10 @@
          * for a description of how feature keys work. If set and supported by the engine
          * as per {@link TextToSpeech#getFeatures(Locale)}, the engine must synthesize
          * text on-device (without making network requests).
+         *
+         * @see TextToSpeech#speak(String, int, java.util.HashMap)
+         * @see TextToSpeech#synthesizeToFile(String, java.util.HashMap, String)
+         * @see TextToSpeech#getFeatures(java.util.Locale)
          */
         public static final String KEY_FEATURE_EMBEDDED_SYNTHESIS = "embeddedTts";
     }
diff --git a/core/java/android/view/HardwareRenderer.java b/core/java/android/view/HardwareRenderer.java
index 2b4260d..5e6125f 100644
--- a/core/java/android/view/HardwareRenderer.java
+++ b/core/java/android/view/HardwareRenderer.java
@@ -1868,7 +1868,7 @@
                 mDebugDataProvider.setupGraphPaint(mProfilePaint, i);
                 switch (graphType) {
                     case GraphDataProvider.GRAPH_TYPE_BARS:
-                        mGlCanvas.drawRects(mProfileShapes[i], count, mProfilePaint);
+                        mGlCanvas.drawRects(mProfileShapes[i], count * 4, mProfilePaint);
                         break;
                     case GraphDataProvider.GRAPH_TYPE_LINES:
                         mGlCanvas.drawLines(mProfileShapes[i], 0, count * 4, mProfilePaint);
diff --git a/core/java/android/view/inputmethod/InputMethodInfo.java b/core/java/android/view/inputmethod/InputMethodInfo.java
index 08e30aa..54c2ba5 100644
--- a/core/java/android/view/inputmethod/InputMethodInfo.java
+++ b/core/java/android/view/inputmethod/InputMethodInfo.java
@@ -81,6 +81,11 @@
     private boolean mIsAuxIme;
 
     /**
+     * Cavert: mForceDefault must be false for production. This flag is only for test.
+     */
+    private final boolean mForceDefault;
+
+    /**
      * Constructor.
      *
      * @param context The Context in which we are parsing the input method.
@@ -108,6 +113,7 @@
         ServiceInfo si = service.serviceInfo;
         mId = new ComponentName(si.packageName, si.name).flattenToShortString();
         mIsAuxIme = true;
+        mForceDefault = false;
 
         PackageManager pm = context.getPackageManager();
         String settingsActivityComponent = null;
@@ -215,13 +221,39 @@
         mIsAuxIme = source.readInt() == 1;
         mService = ResolveInfo.CREATOR.createFromParcel(source);
         source.readTypedList(mSubtypes, InputMethodSubtype.CREATOR);
+        mForceDefault = false;
     }
 
     /**
-     * Temporary API for creating a built-in input method.
+     * Temporary API for creating a built-in input method for test.
      */
     public InputMethodInfo(String packageName, String className,
             CharSequence label, String settingsActivity) {
+        this(buildDummyResolveInfo(packageName, className, label), false, settingsActivity, null,
+                0, false);
+    }
+
+    /**
+     * Temporary API for creating a built-in input method for test.
+     * @hide
+     */
+    public InputMethodInfo(ResolveInfo ri, boolean isAuxIme,
+            String settingsActivity, List<InputMethodSubtype> subtypes, int isDefaultResId,
+            boolean forceDefault) {
+        final ServiceInfo si = ri.serviceInfo;
+        mService = ri;
+        mId = new ComponentName(si.packageName, si.name).flattenToShortString();
+        mSettingsActivityName = settingsActivity;
+        mIsDefaultResId = isDefaultResId;
+        mIsAuxIme = isAuxIme;
+        if (subtypes != null) {
+            mSubtypes.addAll(subtypes);
+        }
+        mForceDefault = forceDefault;
+    }
+
+    private static ResolveInfo buildDummyResolveInfo(String packageName, String className,
+            CharSequence label) {
         ResolveInfo ri = new ResolveInfo();
         ServiceInfo si = new ServiceInfo();
         ApplicationInfo ai = new ApplicationInfo();
@@ -234,11 +266,7 @@
         si.exported = true;
         si.nonLocalizedLabel = label;
         ri.serviceInfo = si;
-        mService = ri;
-        mId = new ComponentName(si.packageName, si.name).flattenToShortString();
-        mSettingsActivityName = settingsActivity;
-        mIsDefaultResId = 0;
-        mIsAuxIme = false;
+        return ri;
     }
 
     /**
@@ -340,6 +368,22 @@
         return mIsDefaultResId;
     }
 
+    /**
+     * Return whether or not this ime is a default ime or not.
+     * @hide
+     */
+    public boolean isDefault(Context context) {
+        if (mForceDefault) {
+            return true;
+        }
+        try {
+            final Resources res = context.createPackageContext(getPackageName(), 0).getResources();
+            return res.getBoolean(getIsDefaultResourceId());
+        } catch (NameNotFoundException e) {
+            return false;
+        }
+    }
+
     public void dump(Printer pw, String prefix) {
         pw.println(prefix + "mId=" + mId
                 + " mSettingsActivityName=" + mSettingsActivityName);
diff --git a/core/java/android/widget/ImageView.java b/core/java/android/widget/ImageView.java
index 8c710ce..1bbf4eb 100644
--- a/core/java/android/widget/ImageView.java
+++ b/core/java/android/widget/ImageView.java
@@ -562,13 +562,14 @@
 
     /** Return the view's optional matrix. This is applied to the
         view's drawable when it is drawn. If there is not matrix,
-        this method will return null.
-        Do not change this matrix in place. If you want a different matrix
-        applied to the drawable, be sure to call setImageMatrix().
+        this method will return an identity matrix.
+        Do not change this matrix in place but make a copy.
+        If you want a different matrix applied to the drawable,
+        be sure to call setImageMatrix().
     */
     public Matrix getImageMatrix() {
         if (mDrawMatrix == null) {
-            return Matrix.IDENTITY_MATRIX;
+            return new Matrix(Matrix.IDENTITY_MATRIX);
         }
         return mDrawMatrix;
     }
diff --git a/core/java/com/android/internal/inputmethod/InputMethodUtils.java b/core/java/com/android/internal/inputmethod/InputMethodUtils.java
index 3d7e1ff..655d148 100644
--- a/core/java/com/android/internal/inputmethod/InputMethodUtils.java
+++ b/core/java/com/android/internal/inputmethod/InputMethodUtils.java
@@ -59,11 +59,53 @@
                 & ApplicationInfo.FLAG_SYSTEM) != 0;
     }
 
-    public static boolean isSystemImeThatHasEnglishSubtype(InputMethodInfo imi) {
+    public static boolean isSystemImeThatHasEnglishKeyboardSubtype(InputMethodInfo imi) {
         if (!isSystemIme(imi)) {
             return false;
         }
-        return containsSubtypeOf(imi, ENGLISH_LOCALE.getLanguage());
+        return containsSubtypeOf(imi, ENGLISH_LOCALE.getLanguage(), SUBTYPE_MODE_KEYBOARD);
+    }
+
+    private static boolean isSystemAuxilialyImeThatHashAutomaticSubtype(InputMethodInfo imi) {
+        if (!isSystemIme(imi)) {
+            return false;
+        }
+        if (!imi.isAuxiliaryIme()) {
+            return false;
+        }
+        final int subtypeCount = imi.getSubtypeCount();
+        for (int i = 0; i < subtypeCount; ++i) {
+            final InputMethodSubtype s = imi.getSubtypeAt(i);
+            if (s.overridesImplicitlyEnabledSubtype()) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    public static ArrayList<InputMethodInfo> getDefaultEnabledImes(
+            Context context, boolean isSystemReady, ArrayList<InputMethodInfo> imis) {
+        final ArrayList<InputMethodInfo> retval = new ArrayList<InputMethodInfo>();
+        boolean auxilialyImeAdded = false;
+        for (int i = 0; i < imis.size(); ++i) {
+            final InputMethodInfo imi = imis.get(i);
+            if (isDefaultEnabledIme(isSystemReady, imi, context)) {
+                retval.add(imi);
+                if (imi.isAuxiliaryIme()) {
+                    auxilialyImeAdded = true;
+                }
+            }
+        }
+        if (auxilialyImeAdded) {
+            return retval;
+        }
+        for (int i = 0; i < imis.size(); ++i) {
+            final InputMethodInfo imi = imis.get(i);
+            if (isSystemAuxilialyImeThatHashAutomaticSubtype(imi)) {
+                retval.add(imi);
+            }
+        }
+        return retval;
     }
 
     // TODO: Rename isSystemDefaultImeThatHasCurrentLanguageSubtype
@@ -77,14 +119,11 @@
         }
         if (imi.getIsDefaultResourceId() != 0) {
             try {
-                Resources res = context.createPackageContext(
-                        imi.getPackageName(), 0).getResources();
-                if (res.getBoolean(imi.getIsDefaultResourceId())
-                        && containsSubtypeOf(imi, context.getResources().getConfiguration().
-                                locale.getLanguage())) {
+                if (imi.isDefault(context) && containsSubtypeOf(
+                        imi, context.getResources().getConfiguration().locale.getLanguage(),
+                        null /* mode */)) {
                     return true;
                 }
-            } catch (PackageManager.NameNotFoundException ex) {
             } catch (Resources.NotFoundException ex) {
             }
         }
@@ -97,15 +136,19 @@
     public static boolean isDefaultEnabledIme(
             boolean isSystemReady, InputMethodInfo imi, Context context) {
         return isValidSystemDefaultIme(isSystemReady, imi, context)
-                || isSystemImeThatHasEnglishSubtype(imi);
+                || isSystemImeThatHasEnglishKeyboardSubtype(imi);
     }
 
-    private static boolean containsSubtypeOf(InputMethodInfo imi, String language) {
+    private static boolean containsSubtypeOf(InputMethodInfo imi, String language, String mode) {
         final int N = imi.getSubtypeCount();
         for (int i = 0; i < N; ++i) {
-            if (imi.getSubtypeAt(i).getLocale().startsWith(language)) {
-                return true;
+            if (!imi.getSubtypeAt(i).getLocale().startsWith(language)) {
+                continue;
             }
+            if(!TextUtils.isEmpty(mode) && !imi.getSubtypeAt(i).getMode().equalsIgnoreCase(mode)) {
+                continue;
+            }
+            return true;
         }
         return false;
     }
@@ -141,7 +184,7 @@
             while (i > 0) {
                 i--;
                 final InputMethodInfo imi = enabledImes.get(i);
-                if (InputMethodUtils.isSystemImeThatHasEnglishSubtype(imi)
+                if (InputMethodUtils.isSystemImeThatHasEnglishKeyboardSubtype(imi)
                         && !imi.isAuxiliaryIme()) {
                     return imi;
                 }
diff --git a/core/java/com/android/internal/os/ZygoteConnection.java b/core/java/com/android/internal/os/ZygoteConnection.java
index d24513a..fd7e3b0 100644
--- a/core/java/com/android/internal/os/ZygoteConnection.java
+++ b/core/java/com/android/internal/os/ZygoteConnection.java
@@ -76,18 +76,6 @@
     private final String peerSecurityContext;
 
     /**
-     * A long-lived reference to the original command socket used to launch
-     * this peer. If "peer wait" mode is specified, the process that requested
-     * the new VM instance intends to track the lifetime of the spawned instance
-     * via the command socket. In this case, the command socket is closed
-     * in the Zygote and placed here in the spawned instance so that it will
-     * not be collected and finalized. This field remains null at all times
-     * in the original Zygote process, and in all spawned processes where
-     * "peer-wait" mode was not requested.
-     */
-    private static LocalSocket sPeerWaitSocket = null;
-
-    /**
      * Constructs instance from connected socket.
      *
      * @param socket non-null; connected socket
@@ -298,11 +286,6 @@
      *   <li> --rlimit=r,c,m<i>tuple of values for setrlimit() call.
      *    <code>r</code> is the resource, <code>c</code> and <code>m</code>
      *    are the settings for current and max value.</i>
-     *   <li> --peer-wait indicates that the command socket should
-     * be inherited by (and set to close-on-exec in) the spawned process
-     * and used to track the lifetime of that process. The spawning process
-     * then exits. Without this flag, it is retained by the spawning process
-     * (and closed in the child) in expectation of a new spawn request.
      *   <li> --classpath=<i>colon-separated classpath</i> indicates
      * that the specified class (which must b first non-flag argument) should
      * be loaded from jar files in the specified classpath. Incompatible with
@@ -330,9 +313,6 @@
         /** from --setgroups */
         int[] gids;
 
-        /** from --peer-wait */
-        boolean peerWait;
-
         /**
          * From --enable-debugger, --enable-checkjni, --enable-assert,
          * --enable-safemode, and --enable-jni-logging.
@@ -437,8 +417,6 @@
                     debugFlags |= Zygote.DEBUG_ENABLE_JNI_LOGGING;
                 } else if (arg.equals("--enable-assert")) {
                     debugFlags |= Zygote.DEBUG_ENABLE_ASSERT;
-                } else if (arg.equals("--peer-wait")) {
-                    peerWait = true;
                 } else if (arg.equals("--runtime-init")) {
                     runtimeInit = true;
                 } else if (arg.startsWith("--seinfo=")) {
@@ -897,23 +875,8 @@
             FileDescriptor[] descriptors, FileDescriptor pipeFd, PrintStream newStderr)
             throws ZygoteInit.MethodAndArgsCaller {
 
-        /*
-         * Close the socket, unless we're in "peer wait" mode, in which
-         * case it's used to track the liveness of this process.
-         */
-
-        if (parsedArgs.peerWait) {
-            try {
-                ZygoteInit.setCloseOnExec(mSocket.getFileDescriptor(), true);
-                sPeerWaitSocket = mSocket;
-            } catch (IOException ex) {
-                Log.e(TAG, "Zygote Child: error setting peer wait "
-                        + "socket to be close-on-exec", ex);
-            }
-        } else {
-            closeSocket();
-            ZygoteInit.closeServerSocket();
-        }
+        closeSocket();
+        ZygoteInit.closeServerSocket();
 
         if (descriptors != null) {
             try {
@@ -1044,18 +1007,6 @@
             return true;
         }
 
-        /*
-         * If the peer wants to use the socket to wait on the
-         * newly spawned process, then we're all done.
-         */
-        if (parsedArgs.peerWait) {
-            try {
-                mSocket.close();
-            } catch (IOException ex) {
-                Log.e(TAG, "Zygote: error closing sockets", ex);
-            }
-            return true;
-        }
         return false;
     }
 
diff --git a/core/java/com/android/internal/os/ZygoteInit.java b/core/java/com/android/internal/os/ZygoteInit.java
index 9e43749..7eddc9c 100644
--- a/core/java/com/android/internal/os/ZygoteInit.java
+++ b/core/java/com/android/internal/os/ZygoteInit.java
@@ -19,10 +19,8 @@
 import static libcore.io.OsConstants.S_IRWXG;
 import static libcore.io.OsConstants.S_IRWXO;
 
-import android.content.pm.ActivityInfo;
 import android.content.res.Resources;
 import android.content.res.TypedArray;
-import android.graphics.drawable.Drawable;
 import android.net.LocalServerSocket;
 import android.os.Debug;
 import android.os.Process;
@@ -88,12 +86,6 @@
     static final int GC_LOOP_COUNT = 10;
 
     /**
-     * If true, zygote forks for each peer. If false, a select loop is used
-     * inside a single process. The latter is preferred.
-     */
-    private static final boolean ZYGOTE_FORK_MODE = false;
-
-    /**
      * The name of a resource file that contains classes to preload.
      */
     private static final String PRELOADED_CLASSES = "preloaded-classes";
@@ -549,11 +541,7 @@
 
             Log.i(TAG, "Accepting command socket connections");
 
-            if (ZYGOTE_FORK_MODE) {
-                runForkMode();
-            } else {
-                runSelectLoopMode();
-            }
+            runSelectLoop();
 
             closeServerSocket();
         } catch (MethodAndArgsCaller caller) {
@@ -566,44 +554,6 @@
     }
 
     /**
-     * Runs the zygote in accept-and-fork mode. In this mode, each peer
-     * gets its own zygote spawner process. This code is retained for
-     * reference only.
-     *
-     * @throws MethodAndArgsCaller in a child process when a main() should
-     * be executed.
-     */
-    private static void runForkMode() throws MethodAndArgsCaller {
-        while (true) {
-            ZygoteConnection peer = acceptCommandPeer();
-
-            int pid;
-
-            pid = Zygote.fork();
-
-            if (pid == 0) {
-                // The child process should handle the peer requests
-
-                // The child does not accept any more connections
-                try {
-                    sServerSocket.close();
-                } catch (IOException ex) {
-                    Log.e(TAG, "Zygote Child: error closing sockets", ex);
-                } finally {
-                    sServerSocket = null;
-                }
-
-                peer.run();
-                break;
-            } else if (pid > 0) {
-                peer.closeSocket();
-            } else {
-                throw new RuntimeException("Error invoking fork()");
-            }
-        }
-    }
-
-    /**
      * Runs the zygote process's select loop. Accepts new connections as
      * they happen, and reads commands from connections one spawn-request's
      * worth at a time.
@@ -611,9 +561,9 @@
      * @throws MethodAndArgsCaller in a child process when a main() should
      * be executed.
      */
-    private static void runSelectLoopMode() throws MethodAndArgsCaller {
-        ArrayList<FileDescriptor> fds = new ArrayList();
-        ArrayList<ZygoteConnection> peers = new ArrayList();
+    private static void runSelectLoop() throws MethodAndArgsCaller {
+        ArrayList<FileDescriptor> fds = new ArrayList<FileDescriptor>();
+        ArrayList<ZygoteConnection> peers = new ArrayList<ZygoteConnection>();
         FileDescriptor[] fdArray = new FileDescriptor[4];
 
         fds.add(sServerSocket.getFileDescriptor());
@@ -734,17 +684,6 @@
             throws IOException;
 
     /**
-     * Sets the permitted and effective capability sets of this process.
-     *
-     * @param permittedCapabilities permitted set
-     * @param effectiveCapabilities effective set
-     * @throws IOException on error
-     */
-    static native void setCapabilities(
-            long permittedCapabilities,
-            long effectiveCapabilities) throws IOException;
-
-    /**
      * Invokes select() on the provider array of file descriptors (selecting
      * for readability only). Array elements of null are ignored.
      *
diff --git a/core/java/com/android/internal/util/FastXmlSerializer.java b/core/java/com/android/internal/util/FastXmlSerializer.java
index 592a8fa..7a04080 100644
--- a/core/java/com/android/internal/util/FastXmlSerializer.java
+++ b/core/java/com/android/internal/util/FastXmlSerializer.java
@@ -50,6 +50,8 @@
 
     private static final int BUFFER_LEN = 8192;
 
+    private static String sSpace = "                                                              ";
+
     private final char[] mText = new char[BUFFER_LEN];
     private int mPos;
 
@@ -59,8 +61,12 @@
     private CharsetEncoder mCharset;
     private ByteBuffer mBytes = ByteBuffer.allocate(BUFFER_LEN);
 
+    private boolean mIndent = false;
     private boolean mInTag;
 
+    private int mNesting = 0;
+    private boolean mLineStart = true;
+
     private void append(char c) throws IOException {
         int pos = mPos;
         if (pos >= (BUFFER_LEN-1)) {
@@ -113,6 +119,14 @@
         append(str, 0, str.length());
     }
 
+    private void appendIndent(int indent) throws IOException {
+        indent *= 4;
+        if (indent > sSpace.length()) {
+            indent = sSpace.length();
+        }
+        append(sSpace, 0, indent);
+    }
+
     private void escapeAndAppendString(final String string) throws IOException {
         final int N = string.length();
         final char NE = (char)ESCAPE_TABLE.length;
@@ -161,6 +175,7 @@
 
         escapeAndAppendString(value);
         append('"');
+        mLineStart = false;
         return this;
     }
 
@@ -185,9 +200,13 @@
 
     public XmlSerializer endTag(String namespace, String name) throws IOException,
             IllegalArgumentException, IllegalStateException {
+        mNesting--;
         if (mInTag) {
             append(" />\n");
         } else {
+            if (mIndent && mLineStart) {
+                appendIndent(mNesting);
+            }
             append("</");
             if (namespace != null) {
                 append(namespace);
@@ -196,6 +215,7 @@
             append(name);
             append(">\n");
         }
+        mLineStart = true;
         mInTag = false;
         return this;
     }
@@ -278,6 +298,7 @@
     public void setFeature(String name, boolean state) throws IllegalArgumentException,
             IllegalStateException {
         if (name.equals("http://xmlpull.org/v1/doc/features.html#indent-output")) {
+            mIndent = true;
             return;
         }
         throw new UnsupportedOperationException();
@@ -325,6 +346,7 @@
             IllegalArgumentException, IllegalStateException {
         append("<?xml version='1.0' encoding='utf-8' standalone='"
                 + (standalone ? "yes" : "no") + "' ?>\n");
+        mLineStart = true;
     }
 
     public XmlSerializer startTag(String namespace, String name) throws IOException,
@@ -332,6 +354,10 @@
         if (mInTag) {
             append(">\n");
         }
+        if (mIndent) {
+            appendIndent(mNesting);
+        }
+        mNesting++;
         append('<');
         if (namespace != null) {
             append(namespace);
@@ -339,6 +365,7 @@
         }
         append(name);
         mInTag = true;
+        mLineStart = false;
         return this;
     }
 
@@ -349,6 +376,9 @@
             mInTag = false;
         }
         escapeAndAppendString(buf, start, len);
+        if (mIndent) {
+            mLineStart = buf[start+len-1] == '\n';
+        }
         return this;
     }
 
@@ -359,6 +389,9 @@
             mInTag = false;
         }
         escapeAndAppendString(text);
+        if (mIndent) {
+            mLineStart = text.length() > 0 && (text.charAt(text.length()-1) == '\n');
+        }
         return this;
     }
 
diff --git a/core/java/com/android/internal/util/IndentingPrintWriter.java b/core/java/com/android/internal/util/IndentingPrintWriter.java
index dd5918b..d01a817 100644
--- a/core/java/com/android/internal/util/IndentingPrintWriter.java
+++ b/core/java/com/android/internal/util/IndentingPrintWriter.java
@@ -21,29 +21,47 @@
 
 /**
  * Lightweight wrapper around {@link PrintWriter} that automatically indents
- * newlines based on internal state. Delays writing indent until first actual
- * write on a newline, enabling indent modification after newline.
+ * newlines based on internal state. It also automatically wraps long lines
+ * based on given line length.
+ * <p>
+ * Delays writing indent until first actual write on a newline, enabling indent
+ * modification after newline.
  */
 public class IndentingPrintWriter extends PrintWriter {
-    private final String mIndent;
+    private final String mSingleIndent;
+    private final int mWrapLength;
 
-    private StringBuilder mBuilder = new StringBuilder();
-    private char[] mCurrent;
+    /** Mutable version of current indent */
+    private StringBuilder mIndentBuilder = new StringBuilder();
+    /** Cache of current {@link #mIndentBuilder} value */
+    private char[] mCurrentIndent;
+    /** Length of current line being built, excluding any indent */
+    private int mCurrentLength;
+
+    /**
+     * Flag indicating if we're currently sitting on an empty line, and that
+     * next write should be prefixed with the current indent.
+     */
     private boolean mEmptyLine = true;
 
-    public IndentingPrintWriter(Writer writer, String indent) {
+    public IndentingPrintWriter(Writer writer, String singleIndent) {
+        this(writer, singleIndent, -1);
+    }
+
+    public IndentingPrintWriter(Writer writer, String singleIndent, int wrapLength) {
         super(writer);
-        mIndent = indent;
+        mSingleIndent = singleIndent;
+        mWrapLength = wrapLength;
     }
 
     public void increaseIndent() {
-        mBuilder.append(mIndent);
-        mCurrent = null;
+        mIndentBuilder.append(mSingleIndent);
+        mCurrentIndent = null;
     }
 
     public void decreaseIndent() {
-        mBuilder.delete(0, mIndent.length());
-        mCurrent = null;
+        mIndentBuilder.delete(0, mSingleIndent.length());
+        mCurrentIndent = null;
     }
 
     public void printPair(String key, Object value) {
@@ -52,33 +70,56 @@
 
     @Override
     public void write(char[] buf, int offset, int count) {
+        final int indentLength = mIndentBuilder.length();
         final int bufferEnd = offset + count;
         int lineStart = offset;
         int lineEnd = offset;
+
+        // March through incoming buffer looking for newlines
         while (lineEnd < bufferEnd) {
             char ch = buf[lineEnd++];
+            mCurrentLength++;
             if (ch == '\n') {
-                writeIndent();
+                maybeWriteIndent();
                 super.write(buf, lineStart, lineEnd - lineStart);
                 lineStart = lineEnd;
                 mEmptyLine = true;
+                mCurrentLength = 0;
+            }
+
+            // Wrap if we've pushed beyond line length
+            if (mWrapLength > 0 && mCurrentLength >= mWrapLength - indentLength) {
+                if (!mEmptyLine) {
+                    // Give ourselves a fresh line to work with
+                    super.write('\n');
+                    mEmptyLine = true;
+                    mCurrentLength = lineEnd - lineStart;
+                } else {
+                    // We need more than a dedicated line, slice it hard
+                    maybeWriteIndent();
+                    super.write(buf, lineStart, lineEnd - lineStart);
+                    super.write('\n');
+                    mEmptyLine = true;
+                    lineStart = lineEnd;
+                    mCurrentLength = 0;
+                }
             }
         }
 
         if (lineStart != lineEnd) {
-            writeIndent();
+            maybeWriteIndent();
             super.write(buf, lineStart, lineEnd - lineStart);
         }
     }
 
-    private void writeIndent() {
+    private void maybeWriteIndent() {
         if (mEmptyLine) {
             mEmptyLine = false;
-            if (mBuilder.length() != 0) {
-                if (mCurrent == null) {
-                    mCurrent = mBuilder.toString().toCharArray();
+            if (mIndentBuilder.length() != 0) {
+                if (mCurrentIndent == null) {
+                    mCurrentIndent = mIndentBuilder.toString().toCharArray();
                 }
-                super.write(mCurrent, 0, mCurrent.length);
+                super.write(mCurrentIndent, 0, mCurrentIndent.length);
             }
         }
     }
diff --git a/core/java/com/android/internal/util/StateMachine.java b/core/java/com/android/internal/util/StateMachine.java
index 1e5a97a..6641f2c 100644
--- a/core/java/com/android/internal/util/StateMachine.java
+++ b/core/java/com/android/internal/util/StateMachine.java
@@ -27,6 +27,7 @@
 import java.io.PrintWriter;
 import java.util.ArrayList;
 import java.util.Calendar;
+import java.util.Collection;
 import java.util.HashMap;
 import java.util.Vector;
 
@@ -81,8 +82,8 @@
  * machine will cause <code>haltedProcessMessage</code> to be invoked.</p>
  *
  * <p>If it is desirable to completely stop the state machine call <code>quit</code> or
- * <code>abort</code>. These will call <code>exit</code> of the current state and its parents, call
- * <code>onQuiting</code> and then exit Thread/Loopers.</p>
+ * <code>quitNow</code>. These will call <code>exit</code> of the current state and its parents,
+ * call <code>onQuiting</code> and then exit Thread/Loopers.</p>
  *
  * <p>In addition to <code>processMessage</code> each <code>State</code> has
  * an <code>enter</code> method and <code>exit</exit> method which may be overridden.</p>
@@ -444,12 +445,13 @@
      * {@hide}
      */
     public static class LogRec {
+        private StateMachine mSm;
         private long mTime;
         private int mWhat;
         private String mInfo;
-        private State mState;
-        private State mOrgState;
-        private State mTransitionToState;
+        private IState mState;
+        private IState mOrgState;
+        private IState mDstState;
 
         /**
          * Constructor
@@ -461,26 +463,26 @@
          * @param transToState is the state that was transitioned to after the message was
          * processed.
          */
-        LogRec(Message msg, String info, State state, State orgState, State transToState) {
-            update(msg, info, state, orgState, transToState);
+        LogRec(StateMachine sm, Message msg, String info, IState state, IState orgState,
+                IState transToState) {
+            update(sm, msg, info, state, orgState, transToState);
         }
 
         /**
          * Update the information in the record.
          * @param state that handled the message
-         * @param orgState is the first state the received the message but
-         * did not processes the message.
-         * @param transToState is the state that was transitioned to after the message was
-         * processed.
+         * @param orgState is the first state the received the message
+         * @param dstState is the state that was the transition target when logging
          */
-        public void update(Message msg, String info, State state, State orgState,
-                State transToState) {
+        public void update(StateMachine sm, Message msg, String info, IState state, IState orgState,
+                IState dstState) {
+            mSm = sm;
             mTime = System.currentTimeMillis();
             mWhat = (msg != null) ? msg.what : 0;
             mInfo = info;
             mState = state;
             mOrgState = orgState;
-            mTransitionToState = transToState;
+            mDstState = dstState;
         }
 
         /**
@@ -507,21 +509,27 @@
         /**
          * @return the state that handled this message
          */
-        public State getState() {
+        public IState getState() {
             return mState;
         }
 
         /**
+         * @return the state destination state if a transition is occurring or null if none.
+         */
+        public IState getDestState() {
+            return mDstState;
+        }
+
+
+        /**
          * @return the original state that received the message.
          */
-        public State getOriginalState() {
+        public IState getOriginalState() {
             return mOrgState;
         }
 
-        /**
-         * @return as string
-         */
-        public String toString(StateMachine sm) {
+        @Override
+        public String toString() {
             StringBuilder sb = new StringBuilder();
             sb.append("time=");
             Calendar c = Calendar.getInstance();
@@ -532,9 +540,9 @@
             sb.append(" org=");
             sb.append(mOrgState == null ? "<null>" : mOrgState.getName());
             sb.append(" dest=");
-            sb.append(mTransitionToState == null ? "<null>" : mTransitionToState.getName());
+            sb.append(mDstState == null ? "<null>" : mDstState.getName());
             sb.append(" what=");
-            String what = sm.getWhatToString(mWhat);
+            String what = mSm != null ? mSm.getWhatToString(mWhat) : "";
             if (TextUtils.isEmpty(what)) {
                 sb.append(mWhat);
                 sb.append("(0x");
@@ -647,18 +655,19 @@
          * processed.
          *
          */
-        synchronized void add(Message msg, String messageInfo, State state, State orgState,
-                State transToState) {
+        synchronized void add(StateMachine sm, Message msg, String messageInfo, IState state,
+                IState orgState,
+                IState transToState) {
             mCount += 1;
             if (mLogRecVector.size() < mMaxSize) {
-                mLogRecVector.add(new LogRec(msg, messageInfo, state, orgState, transToState));
+                mLogRecVector.add(new LogRec(sm, msg, messageInfo, state, orgState, transToState));
             } else {
                 LogRec pmi = mLogRecVector.get(mOldestIndex);
                 mOldestIndex += 1;
                 if (mOldestIndex >= mMaxSize) {
                     mOldestIndex = 0;
                 }
-                pmi.update(msg, messageInfo, state, orgState, transToState);
+                pmi.update(sm, msg, messageInfo, state, orgState, transToState);
             }
         }
     }
@@ -788,55 +797,79 @@
                 throw new RuntimeException("StateMachine.handleMessage: " +
                             "The start method not called, received msg: " + msg);
             }
-            performTransitions(msgProcessedState);
+            performTransitions(msgProcessedState, msg);
 
-            if (mDbg) mSm.log("handleMessage: X");
+            // We need to check if mSm == null here as we could be quitting.
+            if (mDbg && mSm != null) mSm.log("handleMessage: X");
         }
 
         /**
          * Do any transitions
          * @param msgProcessedState is the state that processed the message
          */
-        private void performTransitions(State msgProcessedState) {
+        private void performTransitions(State msgProcessedState, Message msg) {
             /**
              * If transitionTo has been called, exit and then enter
              * the appropriate states. We loop on this to allow
              * enter and exit methods to use transitionTo.
              */
-            State destState = null;
             State orgState = mStateStack[mStateStackTopIndex].state;
 
-            /** Record whether message needs to be logged before transitions */
-            boolean recordLogMsg = mSm.recordLogRec(mMsg);
+            /**
+             * Record whether message needs to be logged before we transition and
+             * and we won't log special messages SM_INIT_CMD or SM_QUIT_CMD which
+             * always set msg.obj to the handler.
+             */
+            boolean recordLogMsg = mSm.recordLogRec(mMsg) && (msg.obj == mSmHandlerObj);
 
-            while (mDestState != null) {
-                if (mDbg) mSm.log("handleMessage: new destination call exit");
+            if (mLogRecords.logOnlyTransitions()) {
+                /** Record only if there is a transition */
+                if (mDestState != null) {
+                    mLogRecords.add(mSm, mMsg, mSm.getLogRecString(mMsg), msgProcessedState,
+                            orgState, mDestState);
+                }
+            } else if (recordLogMsg) {
+                /** Record message */
+               mLogRecords.add(mSm, mMsg, mSm.getLogRecString(mMsg), msgProcessedState,
+                        orgState, mDestState);
+            }
 
+            State destState = mDestState;
+            if (destState != null) {
                 /**
-                 * Save mDestState locally and set to null
-                 * to know if enter/exit use transitionTo.
+                 * Process the transitions including transitions in the enter/exit methods
                  */
-                destState = mDestState;
+                while (true) {
+                    if (mDbg) mSm.log("handleMessage: new destination call exit/enter");
+
+                    /**
+                     * Determine the states to exit and enter and return the
+                     * common ancestor state of the enter/exit states. Then
+                     * invoke the exit methods then the enter methods.
+                     */
+                    StateInfo commonStateInfo = setupTempStateStackWithStatesToEnter(destState);
+                    invokeExitMethods(commonStateInfo);
+                    int stateStackEnteringIndex = moveTempStateStackToStateStack();
+                    invokeEnterMethods(stateStackEnteringIndex);
+
+
+                    /**
+                     * Since we have transitioned to a new state we need to have
+                     * any deferred messages moved to the front of the message queue
+                     * so they will be processed before any other messages in the
+                     * message queue.
+                     */
+                    moveDeferredMessageAtFrontOfQueue();
+
+                    if (destState != mDestState) {
+                        // A new mDestState so continue looping
+                        destState = mDestState;
+                    } else {
+                        // No change in mDestState so we're done
+                        break;
+                    }
+                }
                 mDestState = null;
-
-                /**
-                 * Determine the states to exit and enter and return the
-                 * common ancestor state of the enter/exit states. Then
-                 * invoke the exit methods then the enter methods.
-                 */
-                StateInfo commonStateInfo = setupTempStateStackWithStatesToEnter(destState);
-                invokeExitMethods(commonStateInfo);
-                int stateStackEnteringIndex = moveTempStateStackToStateStack();
-                invokeEnterMethods(stateStackEnteringIndex);
-
-
-                /**
-                 * Since we have transitioned to a new state we need to have
-                 * any deferred messages moved to the front of the message queue
-                 * so they will be processed before any other messages in the
-                 * message queue.
-                 */
-                moveDeferredMessageAtFrontOfQueue();
             }
 
             /**
@@ -859,21 +892,6 @@
                     mSm.onHalting();
                 }
             }
-
-            // Log only if state machine has not quit
-            if (mSm != null) {
-                if (mLogRecords.logOnlyTransitions()) {
-                    /** Record only if there is a transition */
-                    if (destState != null) {
-                        mLogRecords.add(mMsg, mSm.getLogRecString(mMsg), msgProcessedState,
-                                orgState, destState);
-                    }
-                } else if (recordLogMsg) {
-                    /** Record message */
-                    mLogRecords.add(mMsg, mSm.getLogRecString(mMsg), msgProcessedState,
-                            orgState, destState);
-                }
-            }
         }
 
         /**
@@ -1255,20 +1273,6 @@
     }
 
     /**
-     * @return current message
-     */
-    protected final Message getCurrentMessage() {
-        return mSmHandler.getCurrentMessage();
-    }
-
-    /**
-     * @return current state
-     */
-    protected final IState getCurrentState() {
-        return mSmHandler.getCurrentState();
-    }
-
-    /**
      * Add a new state to the state machine, parent will be null
      * @param state to add
      */
@@ -1287,6 +1291,26 @@
     }
 
     /**
+     * @return current message
+     */
+    protected final Message getCurrentMessage() {
+        // mSmHandler can be null if the state machine has quit.
+        SmHandler smh = mSmHandler;
+        if (smh == null) return null;
+        return smh.getCurrentMessage();
+    }
+
+    /**
+     * @return current state
+     */
+    protected final IState getCurrentState() {
+        // mSmHandler can be null if the state machine has quit.
+        SmHandler smh = mSmHandler;
+        if (smh == null) return null;
+        return smh.getCurrentState();
+    }
+
+    /**
      * transition to destination state. Upon returning
      * from processMessage the current state's exit will
      * be executed and upon the next message arriving
@@ -1390,21 +1414,44 @@
      * @return number of log records
      */
     public final int getLogRecSize() {
-        return mSmHandler.mLogRecords.size();
+        // mSmHandler can be null if the state machine has quit.
+        SmHandler smh = mSmHandler;
+        if (smh == null) return 0;
+        return smh.mLogRecords.size();
     }
 
     /**
      * @return the total number of records processed
      */
     public final int getLogRecCount() {
-        return mSmHandler.mLogRecords.count();
+        // mSmHandler can be null if the state machine has quit.
+        SmHandler smh = mSmHandler;
+        if (smh == null) return 0;
+        return smh.mLogRecords.count();
     }
 
     /**
-     * @return a log record
+     * @return a log record, or null if index is out of range
      */
     public final LogRec getLogRec(int index) {
-        return mSmHandler.mLogRecords.get(index);
+        // mSmHandler can be null if the state machine has quit.
+        SmHandler smh = mSmHandler;
+        if (smh == null) return null;
+        return smh.mLogRecords.get(index);
+    }
+
+    /**
+     * @return a copy of LogRecs as a collection
+     */
+    public final Collection<LogRec> copyLogRecs() {
+        Vector<LogRec> vlr = new Vector<LogRec>();
+        SmHandler smh = mSmHandler;
+        if (smh != null) {
+            for (LogRec lr : smh.mLogRecords.mLogRecVector) {
+                vlr.add(lr);
+            }
+        }
+        return vlr;
     }
 
     /**
@@ -1413,17 +1460,11 @@
      * @param string
      */
     protected void addLogRec(String string) {
-        mSmHandler.mLogRecords.add(null, string, null, null, null);
-    }
-
-    /**
-     * Add the string and state to LogRecords
-     *
-     * @param string
-     * @param state current state
-     */
-    protected void addLogRec(String string, State state) {
-        mSmHandler.mLogRecords.add(null, string, state, null, null);
+        // mSmHandler can be null if the state machine has quit.
+        SmHandler smh = mSmHandler;
+        if (smh == null) return;
+        smh.mLogRecords.add(this, smh.getCurrentMessage(), string, smh.getCurrentState(),
+                smh.mStateStack[smh.mStateStackTopIndex].state, smh.mDestState);
     }
 
     /**
@@ -1452,168 +1493,217 @@
     }
 
     /**
-     * @return Handler
+     * @return Handler, maybe null if state machine has quit.
      */
     public final Handler getHandler() {
         return mSmHandler;
     }
 
     /**
-     * Get a message and set Message.target = this.
+     * Get a message and set Message.target state machine handler.
      *
-     * @return message or null if SM has quit
+     * Note: The handler can be null if the state machine has quit,
+     * which means target will be null and may cause a AndroidRuntimeException
+     * in MessageQueue#enqueMessage if sent directly or if sent using
+     * StateMachine#sendMessage the message will just be ignored.
+     *
+     * @return  A Message object from the global pool
      */
     public final Message obtainMessage()
     {
-        if (mSmHandler == null) return null;
-
         return Message.obtain(mSmHandler);
     }
 
     /**
-     * Get a message and set Message.target = this and what
+     * Get a message and set Message.target state machine handler, what.
+     *
+     * Note: The handler can be null if the state machine has quit,
+     * which means target will be null and may cause a AndroidRuntimeException
+     * in MessageQueue#enqueMessage if sent directly or if sent using
+     * StateMachine#sendMessage the message will just be ignored.
      *
      * @param what is the assigned to Message.what.
-     * @return message or null if SM has quit
+     * @return  A Message object from the global pool
      */
     public final Message obtainMessage(int what) {
-        if (mSmHandler == null) return null;
-
         return Message.obtain(mSmHandler, what);
     }
 
     /**
-     * Get a message and set Message.target = this,
+     * Get a message and set Message.target state machine handler,
      * what and obj.
      *
+     * Note: The handler can be null if the state machine has quit,
+     * which means target will be null and may cause a AndroidRuntimeException
+     * in MessageQueue#enqueMessage if sent directly or if sent using
+     * StateMachine#sendMessage the message will just be ignored.
+     *
      * @param what is the assigned to Message.what.
      * @param obj is assigned to Message.obj.
-     * @return message or null if SM has quit
+     * @return  A Message object from the global pool
      */
     public final Message obtainMessage(int what, Object obj)
     {
-        if (mSmHandler == null) return null;
-
         return Message.obtain(mSmHandler, what, obj);
     }
 
     /**
-     * Get a message and set Message.target = this,
+     * Get a message and set Message.target state machine handler,
      * what, arg1 and arg2
      *
+     * Note: The handler can be null if the state machine has quit,
+     * which means target will be null and may cause a AndroidRuntimeException
+     * in MessageQueue#enqueMessage if sent directly or if sent using
+     * StateMachine#sendMessage the message will just be ignored.
+     *
      * @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 or null if
-     *          SM has quit
+     * @return  A Message object from the global pool
      */
     public final Message obtainMessage(int what, int arg1, int arg2)
     {
-        if (mSmHandler == null) return null;
-
         return Message.obtain(mSmHandler, what, arg1, arg2);
     }
 
     /**
-     * Get a message and set Message.target = this,
+     * Get a message and set Message.target state machine handler,
      * what, arg1, arg2 and obj
      *
+     * Note: The handler can be null if the state machine has quit,
+     * which means target will be null and may cause a AndroidRuntimeException
+     * in MessageQueue#enqueMessage if sent directly or if sent using
+     * StateMachine#sendMessage the message will just be ignored.
+     *
      * @param what  is assigned to Message.what
      * @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 or null if
-     *          SM has quit
+     * @return  A Message object from the global pool
      */
     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);
     }
 
     /**
      * Enqueue a message to this state machine.
+     *
+     * Message is ignored if state machine has quit.
      */
     public final void sendMessage(int what) {
         // mSmHandler can be null if the state machine has quit.
-        if (mSmHandler == null) return;
+        SmHandler smh = mSmHandler;
+        if (smh == null) return;
 
-        mSmHandler.sendMessage(obtainMessage(what));
+        smh.sendMessage(obtainMessage(what));
     }
 
     /**
      * Enqueue a message to this state machine.
+     *
+     * Message is ignored if state machine has quit.
      */
     public final void sendMessage(int what, Object obj) {
         // mSmHandler can be null if the state machine has quit.
-        if (mSmHandler == null) return;
+        SmHandler smh = mSmHandler;
+        if (smh == null) return;
 
-        mSmHandler.sendMessage(obtainMessage(what,obj));
+        smh.sendMessage(obtainMessage(what,obj));
     }
 
     /**
      * Enqueue a message to this state machine.
+     *
+     * Message is ignored if state machine has quit.
      */
     public final void sendMessage(Message msg) {
         // mSmHandler can be null if the state machine has quit.
-        if (mSmHandler == null) return;
+        SmHandler smh = mSmHandler;
+        if (smh == null) return;
 
-        mSmHandler.sendMessage(msg);
+        smh.sendMessage(msg);
     }
 
     /**
      * Enqueue a message to this state machine after a delay.
+     *
+     * Message is ignored if state machine has quit.
      */
     public final void sendMessageDelayed(int what, long delayMillis) {
         // mSmHandler can be null if the state machine has quit.
-        if (mSmHandler == null) return;
+        SmHandler smh = mSmHandler;
+        if (smh == null) return;
 
-        mSmHandler.sendMessageDelayed(obtainMessage(what), delayMillis);
+        smh.sendMessageDelayed(obtainMessage(what), delayMillis);
     }
 
     /**
      * Enqueue a message to this state machine after a delay.
+     *
+     * Message is ignored if state machine has quit.
      */
     public final void sendMessageDelayed(int what, Object obj, long delayMillis) {
         // mSmHandler can be null if the state machine has quit.
-        if (mSmHandler == null) return;
+        SmHandler smh = mSmHandler;
+        if (smh == null) return;
 
-        mSmHandler.sendMessageDelayed(obtainMessage(what, obj), delayMillis);
+        smh.sendMessageDelayed(obtainMessage(what, obj), delayMillis);
     }
 
     /**
      * Enqueue a message to this state machine after a delay.
+     *
+     * Message is ignored if state machine has quit.
      */
     public final void sendMessageDelayed(Message msg, long delayMillis) {
         // mSmHandler can be null if the state machine has quit.
-        if (mSmHandler == null) return;
+        SmHandler smh = mSmHandler;
+        if (smh == null) return;
 
-        mSmHandler.sendMessageDelayed(msg, delayMillis);
+        smh.sendMessageDelayed(msg, delayMillis);
     }
 
     /**
      * Enqueue a message to the front of the queue for this state machine.
      * Protected, may only be called by instances of StateMachine.
+     *
+     * Message is ignored if state machine has quit.
      */
     protected final void sendMessageAtFrontOfQueue(int what, Object obj) {
-        mSmHandler.sendMessageAtFrontOfQueue(obtainMessage(what, obj));
+        // mSmHandler can be null if the state machine has quit.
+        SmHandler smh = mSmHandler;
+        if (smh == null) return;
+
+        smh.sendMessageAtFrontOfQueue(obtainMessage(what, obj));
     }
 
     /**
      * Enqueue a message to the front of the queue for this state machine.
      * Protected, may only be called by instances of StateMachine.
+     *
+     * Message is ignored if state machine has quit.
      */
     protected final void sendMessageAtFrontOfQueue(int what) {
-        mSmHandler.sendMessageAtFrontOfQueue(obtainMessage(what));
+        // mSmHandler can be null if the state machine has quit.
+        SmHandler smh = mSmHandler;
+        if (smh == null) return;
+
+        smh.sendMessageAtFrontOfQueue(obtainMessage(what));
     }
 
     /**
      * Enqueue a message to the front of the queue for this state machine.
      * Protected, may only be called by instances of StateMachine.
+     *
+     * Message is ignored if state machine has quit.
      */
     protected final void sendMessageAtFrontOfQueue(Message msg) {
-        mSmHandler.sendMessageAtFrontOfQueue(msg);
+        // mSmHandler can be null if the state machine has quit.
+        SmHandler smh = mSmHandler;
+        if (smh == null) return;
+
+        smh.sendMessageAtFrontOfQueue(msg);
     }
 
     /**
@@ -1621,7 +1711,23 @@
      * Protected, may only be called by instances of StateMachine.
      */
     protected final void removeMessages(int what) {
-        mSmHandler.removeMessages(what);
+        // mSmHandler can be null if the state machine has quit.
+        SmHandler smh = mSmHandler;
+        if (smh == null) return;
+
+        smh.removeMessages(what);
+    }
+
+    /**
+     * Validate that the message was sent by
+     * {@link StateMachine#quit} or {@link StateMachine#quitNow}.
+     * */
+    protected final boolean isQuit(Message msg) {
+        // mSmHandler can be null if the state machine has quit.
+        SmHandler smh = mSmHandler;
+        if (smh == null) return msg.what == SM_QUIT_CMD;
+
+        return smh.isQuit(msg);
     }
 
     /**
@@ -1629,9 +1735,10 @@
      */
     protected final void quit() {
         // mSmHandler can be null if the state machine is already stopped.
-        if (mSmHandler == null) return;
+        SmHandler smh = mSmHandler;
+        if (smh == null) return;
 
-        mSmHandler.quit();
+        smh.quit();
     }
 
     /**
@@ -1639,9 +1746,10 @@
      */
     protected final void quitNow() {
         // mSmHandler can be null if the state machine is already stopped.
-        if (mSmHandler == null) return;
+        SmHandler smh = mSmHandler;
+        if (smh == null) return;
 
-        mSmHandler.quitNow();
+        smh.quitNow();
     }
 
     /**
@@ -1649,9 +1757,10 @@
      */
     public boolean isDbg() {
         // mSmHandler can be null if the state machine has quit.
-        if (mSmHandler == null) return false;
+        SmHandler smh = mSmHandler;
+        if (smh == null) return false;
 
-        return mSmHandler.isDbg();
+        return smh.isDbg();
     }
 
     /**
@@ -1661,9 +1770,10 @@
      */
     public void setDbg(boolean dbg) {
         // mSmHandler can be null if the state machine has quit.
-        if (mSmHandler == null) return;
+        SmHandler smh = mSmHandler;
+        if (smh == null) return;
 
-        mSmHandler.setDbg(dbg);
+        smh.setDbg(dbg);
     }
 
     /**
@@ -1671,10 +1781,11 @@
      */
     public void start() {
         // mSmHandler can be null if the state machine has quit.
-        if (mSmHandler == null) return;
+        SmHandler smh = mSmHandler;
+        if (smh == null) return;
 
         /** Send the complete construction message */
-        mSmHandler.completeConstruction();
+        smh.completeConstruction();
     }
 
     /**
@@ -1688,7 +1799,7 @@
         pw.println(getName() + ":");
         pw.println(" total records=" + getLogRecCount());
         for (int i=0; i < getLogRecSize(); i++) {
-            pw.printf(" rec[%d]: %s\n", i, getLogRec(i).toString(this));
+            pw.printf(" rec[%d]: %s\n", i, getLogRec(i).toString());
             pw.flush();
         }
         pw.println("curState=" + getCurrentState().getName());
diff --git a/core/jni/android_view_GLES20Canvas.cpp b/core/jni/android_view_GLES20Canvas.cpp
index de14826..f4fcc81 100644
--- a/core/jni/android_view_GLES20Canvas.cpp
+++ b/core/jni/android_view_GLES20Canvas.cpp
@@ -479,7 +479,7 @@
             rects.push(r.fTop);
             rects.push(r.fRight);
             rects.push(r.fBottom);
-            count++;
+            count += 4;
             it.next();
         }
         renderer->drawRects(rects.array(), count, paint);
diff --git a/core/jni/com_android_internal_os_ZygoteInit.cpp b/core/jni/com_android_internal_os_ZygoteInit.cpp
index 7e5dede..bc8c4a7 100644
--- a/core/jni/com_android_internal_os_ZygoteInit.cpp
+++ b/core/jni/com_android_internal_os_ZygoteInit.cpp
@@ -163,32 +163,6 @@
     }
 }
 
-static void com_android_internal_os_ZygoteInit_setCapabilities (JNIEnv *env,
-    jobject clazz, jlong permitted, jlong effective)
-{
-    struct __user_cap_header_struct capheader;
-    struct __user_cap_data_struct capdata;
-    int err;
-
-    memset (&capheader, 0, sizeof(capheader));
-    memset (&capdata, 0, sizeof(capdata));
-
-    capheader.version = _LINUX_CAPABILITY_VERSION;
-    capheader.pid = 0;
-
-    // As of this writing, capdata is __u32, but that's expected
-    // to change...
-    capdata.effective = effective;
-    capdata.permitted = permitted;
-
-    err = capset (&capheader, &capdata);
-
-    if (err < 0) {
-        jniThrowIOException(env, errno);
-        return;
-    }
-}
-
 static jlong com_android_internal_os_ZygoteInit_capgetPermitted (JNIEnv *env,
     jobject clazz, jint pid)
 {
@@ -304,8 +278,6 @@
             (void *) com_android_internal_os_ZygoteInit_reopenStdio},
     { "setCloseOnExec", "(Ljava/io/FileDescriptor;Z)V",
         (void *)  com_android_internal_os_ZygoteInit_setCloseOnExec},
-    { "setCapabilities", "(JJ)V",
-        (void *) com_android_internal_os_ZygoteInit_setCapabilities },
     { "capgetPermitted", "(I)J",
         (void *) com_android_internal_os_ZygoteInit_capgetPermitted },
     { "selectReadable", "([Ljava/io/FileDescriptor;)I",
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index aafc4bf..692c17c 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -532,6 +532,31 @@
         android:label="@string/permlab_addVoicemail"
         android:description="@string/permdesc_addVoicemail" />
 
+    <!-- =============================================== -->
+    <!-- Permissions for enabling accessibility features -->
+    <!-- =============================================== -->
+
+    <!-- Used for permissions that allow requesting certain accessibility features. -->
+    <permission-group android:name="android.permission-group.ACCESSIBILITY_FEATURES"
+        android:label="@string/permgrouplab_accessibilityFeatures"
+        android:icon="@drawable/perm_group_accessibility_features"
+        android:description="@string/permgroupdesc_accessibilityFeatures"
+        android:priority="380" />
+
+    <!-- Allows an accessibility service to request touch exploration mode. -->
+    <permission android:name="android.permission.CAN_REQUEST_TOUCH_EXPLORATION_MODE"
+        android:permissionGroup="android.permission-group.ACCESSIBILITY_FEATURES"
+        android:label="@string/permlab_canRequestTouchExplorationMode"
+        android:description="@string/permdesc_canRequestTouchExplorationMode"
+        android:protectionLevel="dangerous" />
+
+    <!-- Allows an accessibility service to request enhanced web accessibility. -->
+    <permission android:name="android.permission.CAN_REQUEST_ENHANCED_WEB_ACCESSIBILITY"
+        android:permissionGroup="android.permission-group.ACCESSIBILITY_FEATURES"
+        android:label="@string/permlab_canRequestEnahncedWebAccessibility"
+        android:description="@string/permdesc_canRequestEnahncedWebAccessibility"
+        android:protectionLevel="dangerous" />
+
     <!-- ======================================= -->
     <!-- Permissions for accessing location info -->
     <!-- ======================================= -->
@@ -690,6 +715,12 @@
         android:permissionGroup="android.permission-group.NETWORK"
         android:protectionLevel="signature|system" />
 
+    <!-- Allows access to the loop radio (Android@Home mesh network) device.
+	@hide -->
+    <permission android:name="android.permission.LOOP_RADIO"
+	android:permissionGroup="android.permission-group.NETWORK"
+	android:protectionLevel="signature|system" />
+    
     <!-- ================================== -->
     <!-- Permissions for accessing accounts -->
     <!-- ================================== -->
@@ -1724,7 +1755,7 @@
         android:description="@string/permdesc_bindInputMethod"
         android:protectionLevel="signature" />
 
-        <!-- Must be required by an {@link android.accessibilityservice.AccessibilityService},
+    <!-- Must be required by an {@link android.accessibilityservice.AccessibilityService},
          to ensure that only the system can bind to it. -->
     <permission android:name="android.permission.BIND_ACCESSIBILITY_SERVICE"
         android:label="@string/permlab_bindAccessibilityService"
diff --git a/core/res/res/drawable-hdpi/perm_group_accessibility_features.png b/core/res/res/drawable-hdpi/perm_group_accessibility_features.png
new file mode 100755
index 0000000..849c19c
--- /dev/null
+++ b/core/res/res/drawable-hdpi/perm_group_accessibility_features.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/perm_group_accessibility_features.png b/core/res/res/drawable-mdpi/perm_group_accessibility_features.png
new file mode 100755
index 0000000..ba86d3d
--- /dev/null
+++ b/core/res/res/drawable-mdpi/perm_group_accessibility_features.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/perm_group_accessibility_features.png b/core/res/res/drawable-xhdpi/perm_group_accessibility_features.png
new file mode 100644
index 0000000..2fec7a3
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/perm_group_accessibility_features.png
Binary files differ
diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml
index f0ad4bf..c4d456b 100644
--- a/core/res/res/values-am/strings.xml
+++ b/core/res/res/values-am/strings.xml
@@ -299,10 +299,8 @@
     <string name="permdesc_shutdown" msgid="7046500838746291775">"የእንቅስቃሴውን አደራጅ ወደ ዝጋ ሁነታ አስቀምጥ።ሙሉ ለሙሉ ዝጋ አያከናውንም።"</string>
     <string name="permlab_stopAppSwitches" msgid="4138608610717425573">"የትግበራ መቀያየርን ተከላከል"</string>
     <string name="permdesc_stopAppSwitches" msgid="8262195802582255021">"ተጠቃሚው ከሌላ መተግበሪያ ከመቀየር ይከላከላል።"</string>
-    <!-- no translation found for permlab_getTopActivityInfo (2537922311411546016) -->
-    <skip />
-    <!-- no translation found for permdesc_getTopActivityInfo (2512448855496067131) -->
-    <skip />
+    <string name="permlab_getTopActivityInfo" msgid="2537922311411546016">"የአሁኑ የመተግበሪያ መረጃ ያግኙ"</string>
+    <string name="permdesc_getTopActivityInfo" msgid="2512448855496067131">"ያዢው በማያ ገጹ ፊት ላይ ስላለው የአሁኑ መተግበሪያ የግል መረጃ እንዲያመጣ ያስችለዋል።"</string>
     <string name="permlab_runSetActivityWatcher" msgid="892239094867182656">"ሁሉንም መተግበሪያ ማስነሻ አሳይ እና ተቆጣጠር"</string>
     <string name="permdesc_runSetActivityWatcher" msgid="6003603162578577406">"እንቅስቃሴዎችን ስርዓቱ እንዴት እንደሚያስጀምር ለመከታተል እና ለመቆጣጠር ለመተግበሪያው ይፈቅዳሉ፡፡ ተንኮል አዘል መተግበሪያዎች የስርዓቱን ክብረ ገመና ሙሉለሙሉ ሊያጋልጡ ይችላሉ፡፡ ይህ ፍቃድ የሚያስፈልገው ለግንባታ ብቻ ነው፤ ለመደበኛ አጠቃቀም ፈጽሞ አይደለም፡፡"</string>
     <string name="permlab_broadcastPackageRemoved" msgid="2576333434893532475">"አካታች የተወገደለት ስርጭት ላክ"</string>
diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
index c2f5a35..39a31d5 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -783,7 +783,7 @@
     <string name="lockscreen_transport_pause_description" msgid="7659088786780128001">"زر الإيقاف المؤقت"</string>
     <string name="lockscreen_transport_play_description" msgid="5888422938351019426">"زر التشغيل"</string>
     <string name="lockscreen_transport_stop_description" msgid="4562318378766987601">"زر الإيقاف"</string>
-    <string name="emergency_calls_only" msgid="6733978304386365407">"مكالمات الطوارئ فقط"</string>
+    <string name="emergency_calls_only" msgid="6733978304386365407">"مكالمات طوارئ فقط"</string>
     <string name="lockscreen_network_locked_message" msgid="143389224986028501">"الشبكة مؤمّنة"</string>
     <string name="lockscreen_sim_puk_locked_message" msgid="7441797339976230">"بطاقة SIM مؤمّنة بكود PUK."</string>
     <string name="lockscreen_sim_puk_locked_instructions" msgid="8127916255245181063">"راجع دليل المستخدم أو اتصل بخدمة العملاء."</string>
diff --git a/core/res/res/values-be/strings.xml b/core/res/res/values-be/strings.xml
index 0f1fda4..294b528 100644
--- a/core/res/res/values-be/strings.xml
+++ b/core/res/res/values-be/strings.xml
@@ -299,10 +299,8 @@
     <string name="permdesc_shutdown" msgid="7046500838746291775">"Спыняе дзейнасць менеджэра. Не выконвае поўнае адключэнне."</string>
     <string name="permlab_stopAppSwitches" msgid="4138608610717425573">"прадухіляць пераключэнне прыкладанняў"</string>
     <string name="permdesc_stopAppSwitches" msgid="8262195802582255021">"Не дазваляе карыстальніку пераходзіць да іншага прыкладання."</string>
-    <!-- no translation found for permlab_getTopActivityInfo (2537922311411546016) -->
-    <skip />
-    <!-- no translation found for permdesc_getTopActivityInfo (2512448855496067131) -->
-    <skip />
+    <string name="permlab_getTopActivityInfo" msgid="2537922311411546016">"атрымаць бягучую інфармацыю прыкладання"</string>
+    <string name="permdesc_getTopActivityInfo" msgid="2512448855496067131">"Дазваляе ўладальніку атрымлiваць асабістую інфармацыю аб бягучым прыкладаннi на пярэднім плане экрана."</string>
     <string name="permlab_runSetActivityWatcher" msgid="892239094867182656">"адсочваць і кантраляваць запуск усіх прыкладанняў"</string>
     <string name="permdesc_runSetActivityWatcher" msgid="6003603162578577406">"Дазваляе прыкладанню сачыць і кантраляваць, як сістэма запускае працэсы. Шкоднасныя прыкладанні могуць цалкам парушыць працу сістэмы. Гэты дазвол патрэбны толькі для распрацоўкі, ніколі для звычайнага выкарыстання."</string>
     <string name="permlab_broadcastPackageRemoved" msgid="2576333434893532475">"трансляваць паведамленні аб выдаленні пакетаў"</string>
@@ -1458,7 +1456,7 @@
     <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Вы няправільна ўвялі графічны ключ разблакiроўкi пэўную колькасць разоў: <xliff:g id="NUMBER_0">%d</xliff:g>. Пасля яшчэ некалькiх няўдалых спроб (<xliff:g id="NUMBER_1">%d</xliff:g>) вам будзе прапанавана разблакiраваць тэлефон, увайшоўшы ў Google."\n\n" Паўтарыце спробу праз <xliff:g id="NUMBER_2">%d</xliff:g> с."</string>
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Вы няправільна ўвялі графічны ключ разблакiроўкi пэўную колькасць разоў: <xliff:g id="NUMBER_0">%d</xliff:g>. Пасля яшчэ некалькiх няўдалых спроб (<xliff:g id="NUMBER_1">%d</xliff:g>) вам будзе прапанавана разблакiраваць тэлефон, увайшоўшы ў Google."\n\n" Паўтарыце спробу праз <xliff:g id="NUMBER_2">%d</xliff:g> с."</string>
     <string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" — "</string>
-    <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Выдаліць"</string>
+    <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Выдалiць"</string>
     <string name="safe_media_volume_warning" product="default" msgid="7382971871993371648">"Павялiчыць гук больш за рэкамендаваны ўзровень?"\n"Доўгае слуханне музыкi на вялiкай гучнасцi можа пашкодзiць ваш слых."</string>
     <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"Утрымлiвайце два пальцы, каб уключыць доступ."</string>
     <string name="accessibility_enabled" msgid="1381972048564547685">"Даступнасць уключана."</string>
diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml
index 54b6198..6a4afa3 100644
--- a/core/res/res/values-bg/strings.xml
+++ b/core/res/res/values-bg/strings.xml
@@ -299,10 +299,8 @@
     <string name="permdesc_shutdown" msgid="7046500838746291775">"Изключва диспечера на дейностите. Не извършва пълно изключване."</string>
     <string name="permlab_stopAppSwitches" msgid="4138608610717425573">"предотвратяване на превключването между приложения"</string>
     <string name="permdesc_stopAppSwitches" msgid="8262195802582255021">"Не позволява на потребителя да превключва към друго приложение."</string>
-    <!-- no translation found for permlab_getTopActivityInfo (2537922311411546016) -->
-    <skip />
-    <!-- no translation found for permdesc_getTopActivityInfo (2512448855496067131) -->
-    <skip />
+    <string name="permlab_getTopActivityInfo" msgid="2537922311411546016">"извличане на информация за текущото приложение"</string>
+    <string name="permdesc_getTopActivityInfo" msgid="2512448855496067131">"Разрешава на собственика да извлича частна информация за текущото приложение на преден план на екрана."</string>
     <string name="permlab_runSetActivityWatcher" msgid="892239094867182656">"наблюдение и контрол на стартирането на всички приложения"</string>
     <string name="permdesc_runSetActivityWatcher" msgid="6003603162578577406">"Разрешава на приложението да наблюдава и контролира как системата стартира дейности. Злонамерените приложения могат изцяло да компрометират системата. Това разрешение е нужно само за програмиране, никога за нормална употреба."</string>
     <string name="permlab_broadcastPackageRemoved" msgid="2576333434893532475">"изпращане на излъчване при премахнат пакет"</string>
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index 5acb723..cf8192a 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -299,10 +299,8 @@
     <string name="permdesc_shutdown" msgid="7046500838746291775">"Posa el gestor d\'activitats en estat d\'apagada. No fa una apagada completa."</string>
     <string name="permlab_stopAppSwitches" msgid="4138608610717425573">"impedir els canvis d\'aplicació"</string>
     <string name="permdesc_stopAppSwitches" msgid="8262195802582255021">"Impedeix que l\'usuari canviï a una altra aplicació."</string>
-    <!-- no translation found for permlab_getTopActivityInfo (2537922311411546016) -->
-    <skip />
-    <!-- no translation found for permdesc_getTopActivityInfo (2512448855496067131) -->
-    <skip />
+    <string name="permlab_getTopActivityInfo" msgid="2537922311411546016">"obtenció d\'informació de l\'aplicació actual"</string>
+    <string name="permdesc_getTopActivityInfo" msgid="2512448855496067131">"Permet que el titular recuperi informació privada sobre l\'aplicació actual al primer pla de la pantalla."</string>
     <string name="permlab_runSetActivityWatcher" msgid="892239094867182656">"supervisa i controla tots els inicis d\'aplicacions"</string>
     <string name="permdesc_runSetActivityWatcher" msgid="6003603162578577406">"Permet que l\'aplicació supervisi i controli com el sistema inicia activitats. Les aplicacions malicioses poden comprometre totalment el sistema. Aquest permís només és necessari per al desenvolupament, mai per a l\'ús normal."</string>
     <string name="permlab_broadcastPackageRemoved" msgid="2576333434893532475">"enviar difusió d\'eliminació de paquet"</string>
diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
index f10a217..2420ef2 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -299,10 +299,8 @@
     <string name="permdesc_shutdown" msgid="7046500838746291775">"Uvede správce činností do vypnutého stavu. Nedojde však k úplnému vypnutí."</string>
     <string name="permlab_stopAppSwitches" msgid="4138608610717425573">"zabránění přepínání aplikací"</string>
     <string name="permdesc_stopAppSwitches" msgid="8262195802582255021">"Zabrání uživateli přepnout na jinou aplikaci."</string>
-    <!-- no translation found for permlab_getTopActivityInfo (2537922311411546016) -->
-    <skip />
-    <!-- no translation found for permdesc_getTopActivityInfo (2512448855496067131) -->
-    <skip />
+    <string name="permlab_getTopActivityInfo" msgid="2537922311411546016">"získat informace o aktuální aplikaci"</string>
+    <string name="permdesc_getTopActivityInfo" msgid="2512448855496067131">"Umožňuje držiteli získat soukromé informace o aktuální aplikaci na popředí obrazovky."</string>
     <string name="permlab_runSetActivityWatcher" msgid="892239094867182656">"sledování a řízení spouštění všech aplikací"</string>
     <string name="permdesc_runSetActivityWatcher" msgid="6003603162578577406">"Umožňuje aplikaci sledovat a řídit spouštění činností systémem. Škodlivé aplikace mohou systém zcela ovládnout. Toto oprávnění je požadováno pouze pro účely vývoje, nikdy pro běžné použití."</string>
     <string name="permlab_broadcastPackageRemoved" msgid="2576333434893532475">"odeslání vysílání o odstranění balíčku"</string>
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index eec3dd4..7a7035a 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -299,10 +299,8 @@
     <string name="permdesc_shutdown" msgid="7046500838746291775">"Sætter aktivitetsadministratoren i lukningstilstand. Lukker ikke helt ned."</string>
     <string name="permlab_stopAppSwitches" msgid="4138608610717425573">"undgå programskift"</string>
     <string name="permdesc_stopAppSwitches" msgid="8262195802582255021">"Forhindrer brugeren i at skifte til en anden app."</string>
-    <!-- no translation found for permlab_getTopActivityInfo (2537922311411546016) -->
-    <skip />
-    <!-- no translation found for permdesc_getTopActivityInfo (2512448855496067131) -->
-    <skip />
+    <string name="permlab_getTopActivityInfo" msgid="2537922311411546016">"få aktuelle app-oplysninger"</string>
+    <string name="permdesc_getTopActivityInfo" msgid="2512448855496067131">"Tillader, at brugeren henter private oplysninger om den aktuelle applikation i forgrunden på ​​skærmen."</string>
     <string name="permlab_runSetActivityWatcher" msgid="892239094867182656">"overvåge og kontrollere åbning af alle apps"</string>
     <string name="permdesc_runSetActivityWatcher" msgid="6003603162578577406">"Tillader, at appen kan overvåge og kontrollere, hvordan systemet starter aktiviteter. Ondsindede apps kan fuldstændig kompromittere systemet. Denne tilladelse er kun nødvendig til udvikling, aldrig til normal brug."</string>
     <string name="permlab_broadcastPackageRemoved" msgid="2576333434893532475">"send udsendelse om fjernet pakke"</string>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index d5a67f0..d870d8a 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -299,10 +299,8 @@
     <string name="permdesc_shutdown" msgid="7046500838746291775">"Versetzt den Aktivitätsmanager in einen heruntergefahrenen Zustand. Führt kein vollständiges Herunterfahren aus."</string>
     <string name="permlab_stopAppSwitches" msgid="4138608610717425573">"App-Wechsel verhindern"</string>
     <string name="permdesc_stopAppSwitches" msgid="8262195802582255021">"Hindert den Nutzer daran, zu einer anderen App zu wechseln"</string>
-    <!-- no translation found for permlab_getTopActivityInfo (2537922311411546016) -->
-    <skip />
-    <!-- no translation found for permdesc_getTopActivityInfo (2512448855496067131) -->
-    <skip />
+    <string name="permlab_getTopActivityInfo" msgid="2537922311411546016">"Informationen zur aktuellen App abrufen"</string>
+    <string name="permdesc_getTopActivityInfo" msgid="2512448855496067131">"Ermöglicht es dem Inhaber, private Informationen zur aktuellen App im Vordergrund des Bildschirms abzurufen"</string>
     <string name="permlab_runSetActivityWatcher" msgid="892239094867182656">"Start von Apps überwachen und steuern"</string>
     <string name="permdesc_runSetActivityWatcher" msgid="6003603162578577406">"Ermöglicht der App, den Start von Systemaktivitäten zu überwachen und zu steuern. Schädliche Apps können so das gesamte System beeinträchtigen. Diese Berechtigung wird nur zu Entwicklungszwecken und nie für die normale Nutzung benötigt."</string>
     <string name="permlab_broadcastPackageRemoved" msgid="2576333434893532475">"Broadcast ohne Paket senden"</string>
diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml
index cf42a41..3bfcef5 100644
--- a/core/res/res/values-el/strings.xml
+++ b/core/res/res/values-el/strings.xml
@@ -299,10 +299,8 @@
     <string name="permdesc_shutdown" msgid="7046500838746291775">"Θέτει το πρόγραμμα διαχείρισης δραστηριοτήτων σε κατάσταση τερματισμού λειτουργιών. Δεν εκτελεί πλήρη τερματισμό λειτουργιών."</string>
     <string name="permlab_stopAppSwitches" msgid="4138608610717425573">"αποτροπή εναλλαγών εφαρμογών"</string>
     <string name="permdesc_stopAppSwitches" msgid="8262195802582255021">"Δεν επιτρέπει στο χρήστη να μεταβεί σε άλλη εφαρμογή."</string>
-    <!-- no translation found for permlab_getTopActivityInfo (2537922311411546016) -->
-    <skip />
-    <!-- no translation found for permdesc_getTopActivityInfo (2512448855496067131) -->
-    <skip />
+    <string name="permlab_getTopActivityInfo" msgid="2537922311411546016">"λήψη πληροφοριών σχετικά με την τρέχουσα εφαρμογή"</string>
+    <string name="permdesc_getTopActivityInfo" msgid="2512448855496067131">"Δίνει στον κάτοχο τη δυνατότητα ανάκτησης απόρρητων πληροφοριών σχετικά με την τρέχουσα εφαρμογή στο προσκήνιο της οθόνης."</string>
     <string name="permlab_runSetActivityWatcher" msgid="892239094867182656">"παρακολούθηση και έλεγχος όλων των εκκινήσεων εφαρμογών"</string>
     <string name="permdesc_runSetActivityWatcher" msgid="6003603162578577406">"Επιτρέπει στην εφαρμογή να παρακολουθεί και να ελέγχει τον τρόπο με τον οποίο το σύστημα εκκινεί δραστηριότητες. Τυχόν κακόβουλες εφαρμογές ενδέχεται να θέσουν σε κίνδυνο το σύστημα. Αυτή η άδεια είναι απαραίτητη μόνο για σκοπούς ανάπτυξης και ποτέ για συνήθη χρήση."</string>
     <string name="permlab_broadcastPackageRemoved" msgid="2576333434893532475">"αποστολή εκπομπής χωρίς πακέτο"</string>
diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml
index 73ee358..368c814c 100644
--- a/core/res/res/values-en-rGB/strings.xml
+++ b/core/res/res/values-en-rGB/strings.xml
@@ -299,10 +299,8 @@
     <string name="permdesc_shutdown" msgid="7046500838746291775">"Puts the activity manager into a shut-down state. Does not perform a complete shut down."</string>
     <string name="permlab_stopAppSwitches" msgid="4138608610717425573">"prevent app switches"</string>
     <string name="permdesc_stopAppSwitches" msgid="8262195802582255021">"Prevents the user from switching to another app."</string>
-    <!-- no translation found for permlab_getTopActivityInfo (2537922311411546016) -->
-    <skip />
-    <!-- no translation found for permdesc_getTopActivityInfo (2512448855496067131) -->
-    <skip />
+    <string name="permlab_getTopActivityInfo" msgid="2537922311411546016">"get current app info"</string>
+    <string name="permdesc_getTopActivityInfo" msgid="2512448855496067131">"Allows the holder to retrieve private information about the current application in the foreground of the screen."</string>
     <string name="permlab_runSetActivityWatcher" msgid="892239094867182656">"monitor and control all app launching"</string>
     <string name="permdesc_runSetActivityWatcher" msgid="6003603162578577406">"Allows the app to monitor and control how the system launches activities. Malicious apps may completely compromise the system. This permission is only needed for development, never for normal use."</string>
     <string name="permlab_broadcastPackageRemoved" msgid="2576333434893532475">"send package removed broadcast"</string>
diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml
index 6bb8e44..f36a03b 100644
--- a/core/res/res/values-es-rUS/strings.xml
+++ b/core/res/res/values-es-rUS/strings.xml
@@ -299,10 +299,8 @@
     <string name="permdesc_shutdown" msgid="7046500838746291775">"Pone al administrador de la actividad en estado de cierre. No realiza un cierre completo."</string>
     <string name="permlab_stopAppSwitches" msgid="4138608610717425573">"impedir conmutadores de aplicación"</string>
     <string name="permdesc_stopAppSwitches" msgid="8262195802582255021">"Evita que el usuario cambie a otra aplicación."</string>
-    <!-- no translation found for permlab_getTopActivityInfo (2537922311411546016) -->
-    <skip />
-    <!-- no translation found for permdesc_getTopActivityInfo (2512448855496067131) -->
-    <skip />
+    <string name="permlab_getTopActivityInfo" msgid="2537922311411546016">"Obtener información de aplicación actual"</string>
+    <string name="permdesc_getTopActivityInfo" msgid="2512448855496067131">"Permite que el titular recupere información privada sobre la aplicación actual en el primer plano de la pantalla."</string>
     <string name="permlab_runSetActivityWatcher" msgid="892239094867182656">"supervisar y controlar la ejecución de todas las aplicaciones"</string>
     <string name="permdesc_runSetActivityWatcher" msgid="6003603162578577406">"Permite que la aplicación supervise y controle la manera en la que el sistema inicia actividades. Las aplicaciones maliciosas pueden comprometer el sistema por completo. Este permiso es necesario solo para el desarrollo, nunca para el uso habitual."</string>
     <string name="permlab_broadcastPackageRemoved" msgid="2576333434893532475">"enviar emisión de paquete eliminado"</string>
@@ -897,7 +895,7 @@
     <string name="permlab_updateLock" msgid="3527558366616680889">"no realizar actualizaciones automáticas"</string>
     <string name="permdesc_updateLock" msgid="1655625832166778492">"Permite a su propietario ofrecer información al sistema acerca de cuándo sería adecuado reiniciar el sistema de forma no interactiva y actualizar el dispositivo."</string>
     <string name="save_password_message" msgid="767344687139195790">"¿Quieres recordar esta contraseña en el navegador?"</string>
-    <string name="save_password_notnow" msgid="6389675316706699758">"Ahora no."</string>
+    <string name="save_password_notnow" msgid="6389675316706699758">"Ahora no"</string>
     <string name="save_password_remember" msgid="6491879678996749466">"Recuerda"</string>
     <string name="save_password_never" msgid="8274330296785855105">"Nunca"</string>
     <string name="open_permission_deny" msgid="7374036708316629800">"No tienes permiso para abrir esta página."</string>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index fbbcf89..62ed107 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -299,10 +299,8 @@
     <string name="permdesc_shutdown" msgid="7046500838746291775">"Pone el administrador de actividades en estado de cierre. No realiza un cierre completo."</string>
     <string name="permlab_stopAppSwitches" msgid="4138608610717425573">"evitar cambios de aplicación"</string>
     <string name="permdesc_stopAppSwitches" msgid="8262195802582255021">"Evita que el usuario cambie a otra aplicación."</string>
-    <!-- no translation found for permlab_getTopActivityInfo (2537922311411546016) -->
-    <skip />
-    <!-- no translation found for permdesc_getTopActivityInfo (2512448855496067131) -->
-    <skip />
+    <string name="permlab_getTopActivityInfo" msgid="2537922311411546016">"obtener información de la aplicación actual"</string>
+    <string name="permdesc_getTopActivityInfo" msgid="2512448855496067131">"Permite que el titular recupere información privada sobre la aplicación actual en el primer plano de la pantalla."</string>
     <string name="permlab_runSetActivityWatcher" msgid="892239094867182656">"supervisar y controlar la ejecución de todas las aplicaciones"</string>
     <string name="permdesc_runSetActivityWatcher" msgid="6003603162578577406">"Permite que la aplicación supervise y controle la ejecución de las actividades del sistema. Las aplicaciones malintencionadas pueden vulnerar la seguridad del sistema. Este permiso es necesario únicamente para tareas de desarrollo, nunca para el uso habitual."</string>
     <string name="permlab_broadcastPackageRemoved" msgid="2576333434893532475">"enviar emisión eliminada de paquete"</string>
diff --git a/core/res/res/values-et/strings.xml b/core/res/res/values-et/strings.xml
index 00b5c2d..3141dab 100644
--- a/core/res/res/values-et/strings.xml
+++ b/core/res/res/values-et/strings.xml
@@ -299,10 +299,8 @@
     <string name="permdesc_shutdown" msgid="7046500838746291775">"Lülitab tegevushalduri väljalülitusolekusse. Ei lülita lõplikult välja."</string>
     <string name="permlab_stopAppSwitches" msgid="4138608610717425573">"väldi rakenduste ümberlülitamist"</string>
     <string name="permdesc_stopAppSwitches" msgid="8262195802582255021">"Takistab kasutaja lülitumist teisele rakendusele."</string>
-    <!-- no translation found for permlab_getTopActivityInfo (2537922311411546016) -->
-    <skip />
-    <!-- no translation found for permdesc_getTopActivityInfo (2512448855496067131) -->
-    <skip />
+    <string name="permlab_getTopActivityInfo" msgid="2537922311411546016">"aktiivse rakenduse teabe hankimine"</string>
+    <string name="permdesc_getTopActivityInfo" msgid="2512448855496067131">"Lubab õiguste saajal hankida privaatset teavet ekraanil esiplaanil oleva aktiivse rakenduse kohta."</string>
     <string name="permlab_runSetActivityWatcher" msgid="892239094867182656">"Kõigi rakenduste käivitumise jälgimine ja juhtimine"</string>
     <string name="permdesc_runSetActivityWatcher" msgid="6003603162578577406">"Võimaldab rakendusel jälgida ja juhtida, kuidas süsteem tegevusi käivitab. Pahatahtlikud rakendused võivad süsteemi täielikult rikkuda. Seda õigust on vaja ainult arenduseks, mitte tavakasutuse korral."</string>
     <string name="permlab_broadcastPackageRemoved" msgid="2576333434893532475">"saada paketist eemaldatud saade"</string>
diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml
index c4dfd6c..cd0b05d 100644
--- a/core/res/res/values-fi/strings.xml
+++ b/core/res/res/values-fi/strings.xml
@@ -299,10 +299,8 @@
     <string name="permdesc_shutdown" msgid="7046500838746291775">"Asettaa toimintojen hallinnan sulkeutumistilaan. Ei sulje puhelinta kokonaan."</string>
     <string name="permlab_stopAppSwitches" msgid="4138608610717425573">"estä sovellusten vaihto"</string>
     <string name="permdesc_stopAppSwitches" msgid="8262195802582255021">"Estää käyttäjää siirtymästä toiseen sovellukseen."</string>
-    <!-- no translation found for permlab_getTopActivityInfo (2537922311411546016) -->
-    <skip />
-    <!-- no translation found for permdesc_getTopActivityInfo (2512448855496067131) -->
-    <skip />
+    <string name="permlab_getTopActivityInfo" msgid="2537922311411546016">"hae nykyisen sovelluksen tiedot"</string>
+    <string name="permdesc_getTopActivityInfo" msgid="2512448855496067131">"Antaa sovellukselle luvan noutaa nykyistä sovellusta koskevia yksityisiä tietoja ruudun etualalla."</string>
     <string name="permlab_runSetActivityWatcher" msgid="892239094867182656">"kaikkien sovellusten käynnistämisen valvonta ja hallinta"</string>
     <string name="permdesc_runSetActivityWatcher" msgid="6003603162578577406">"Antaa sovelluksen valvoa ja hallita sitä, miten laite käynnistää toimintoja. Haitalliset sovellukset voivat vaarantaa laitteen käytön. Tätä oikeutta tarvitaan vain kehityskäyttöön eikä koskaan tavalliseen käyttöön."</string>
     <string name="permlab_broadcastPackageRemoved" msgid="2576333434893532475">"lähetä paketeista poistettuja lähetyksiä"</string>
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index ea1ef50..420bbcf 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -299,10 +299,8 @@
     <string name="permdesc_shutdown" msgid="7046500838746291775">"Place le gestionnaire d\'activités en état d\'arrêt. N\'effectue pas un arrêt complet."</string>
     <string name="permlab_stopAppSwitches" msgid="4138608610717425573">"empêcher les changements d\'applications"</string>
     <string name="permdesc_stopAppSwitches" msgid="8262195802582255021">"Empêche l\'utilisateur de changer d\'application."</string>
-    <!-- no translation found for permlab_getTopActivityInfo (2537922311411546016) -->
-    <skip />
-    <!-- no translation found for permdesc_getTopActivityInfo (2512448855496067131) -->
-    <skip />
+    <string name="permlab_getTopActivityInfo" msgid="2537922311411546016">"Récupérer des informations sur l\'application actuelle"</string>
+    <string name="permdesc_getTopActivityInfo" msgid="2512448855496067131">"Permet à l\'application autorisée de récupérer des informations confidentielles à propos de l\'application exécutée au premier plan sur l\'écran."</string>
     <string name="permlab_runSetActivityWatcher" msgid="892239094867182656">"suivre et contrôler le lancement de toutes les applications"</string>
     <string name="permdesc_runSetActivityWatcher" msgid="6003603162578577406">"Permet à l\'application de surveiller et de contrôler la façon dont le système lance les activités. Des applications malveillantes peuvent exploiter cette fonctionnalité pour totalement compromettre le système. Cette autorisation est uniquement destinée aux développeurs. Elle ne doit jamais être activée dans le cadre d\'une utilisation standard."</string>
     <string name="permlab_broadcastPackageRemoved" msgid="2576333434893532475">"Envoyer une diffusion sans paquet"</string>
diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml
index c3ef672..2a08254 100644
--- a/core/res/res/values-hi/strings.xml
+++ b/core/res/res/values-hi/strings.xml
@@ -299,10 +299,8 @@
     <string name="permdesc_shutdown" msgid="7046500838746291775">"गतिविधि प्रबंधक को शटडाउन स्‍थिति में रखता है. पूर्ण शटडाउन निष्‍पादित नहीं करता है."</string>
     <string name="permlab_stopAppSwitches" msgid="4138608610717425573">"एप्‍लिकेशन स्‍विच करने से रोकता है"</string>
     <string name="permdesc_stopAppSwitches" msgid="8262195802582255021">"उपयोगकर्ता को दूसरे एप्‍लिकेशन पर स्‍विच करने से रोकता है."</string>
-    <!-- no translation found for permlab_getTopActivityInfo (2537922311411546016) -->
-    <skip />
-    <!-- no translation found for permdesc_getTopActivityInfo (2512448855496067131) -->
-    <skip />
+    <string name="permlab_getTopActivityInfo" msgid="2537922311411546016">"वर्तमान एप्लिकेशन की जानकारी प्राप्त करें"</string>
+    <string name="permdesc_getTopActivityInfo" msgid="2512448855496067131">"धारक को स्क्रीन के अग्रभाग में स्थित वर्तमान एप्लिकेशन के बारे में निजी जानकारी प्राप्त करने देती है."</string>
     <string name="permlab_runSetActivityWatcher" msgid="892239094867182656">"सभी एप्‍लिकेशन की लॉन्‍चिंग की निगरानी करें और उसे नियंत्रित करें"</string>
     <string name="permdesc_runSetActivityWatcher" msgid="6003603162578577406">"एप्लिकेशन को यह निगरानी और नियंत्रित करने देता है कि सिस्टम कैसे गतिविधियां लॉन्च करता है. दुर्भावनापूर्ण एप्लिकेशन सिस्टम को पूरी तरह से जोखिम में डाल सकते हैं. इस अनुमति की आवश्यकता केवल विकास के लिए है, सामान्य उपयोग के लिए कभी नहीं."</string>
     <string name="permlab_broadcastPackageRemoved" msgid="2576333434893532475">"पैकेज निकाले गए प्रसारण भेजें"</string>
diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml
index 72aad27..607afdf 100644
--- a/core/res/res/values-hr/strings.xml
+++ b/core/res/res/values-hr/strings.xml
@@ -299,10 +299,8 @@
     <string name="permdesc_shutdown" msgid="7046500838746291775">"Postavlja upravitelja za aktivnost u stanje mirovanja. Ne isključuje ga u potpunosti."</string>
     <string name="permlab_stopAppSwitches" msgid="4138608610717425573">"sprečavanje promjene aplikacije"</string>
     <string name="permdesc_stopAppSwitches" msgid="8262195802582255021">"Sprječava korisnika u prebacivanju na drugu aplikaciju."</string>
-    <!-- no translation found for permlab_getTopActivityInfo (2537922311411546016) -->
-    <skip />
-    <!-- no translation found for permdesc_getTopActivityInfo (2512448855496067131) -->
-    <skip />
+    <string name="permlab_getTopActivityInfo" msgid="2537922311411546016">"dohvaćanje informacija o trenutačnoj aplikaciji"</string>
+    <string name="permdesc_getTopActivityInfo" msgid="2512448855496067131">"Omogućuje nositelju dohvaćanje privatnih informacija o trenutačnoj aplikaciji u prednjem planu na zaslonu."</string>
     <string name="permlab_runSetActivityWatcher" msgid="892239094867182656">"praćenje i nadzor svih pokretanja aplikacija"</string>
     <string name="permdesc_runSetActivityWatcher" msgid="6003603162578577406">"Omogućuje aplikaciji nadzor i upravljanje načinom na koji sustav pokreće aktivnosti. Zlonamjerne aplikacije mogu posve ugroziti sustav. Ta je dozvola potrebna samo za razvoj, nikada za uobičajenu upotrebu."</string>
     <string name="permlab_broadcastPackageRemoved" msgid="2576333434893532475">"slanje paketno uklonjenog prijenosa"</string>
diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml
index 6dd4f8f..cca48c8 100644
--- a/core/res/res/values-hu/strings.xml
+++ b/core/res/res/values-hu/strings.xml
@@ -299,10 +299,8 @@
     <string name="permdesc_shutdown" msgid="7046500838746291775">"Leállítás állapotba helyezi a tevékenységkezelőt. Nem hajtja végre a teljes leállítást."</string>
     <string name="permlab_stopAppSwitches" msgid="4138608610717425573">"alkalmazásváltás megakadályozása"</string>
     <string name="permdesc_stopAppSwitches" msgid="8262195802582255021">"Megakadályozza, hogy a felhasználó átváltson egy másik alkalmazásra."</string>
-    <!-- no translation found for permlab_getTopActivityInfo (2537922311411546016) -->
-    <skip />
-    <!-- no translation found for permdesc_getTopActivityInfo (2512448855496067131) -->
-    <skip />
+    <string name="permlab_getTopActivityInfo" msgid="2537922311411546016">"az alkalmazás aktuális információinak lekérése"</string>
+    <string name="permdesc_getTopActivityInfo" msgid="2512448855496067131">"Lehetővé teszi, hogy a felhasználó privát adatokat kérjen le az aktuális alkalmazásról a képernyő előterében."</string>
     <string name="permlab_runSetActivityWatcher" msgid="892239094867182656">"alkalmazásindítások nyomon követése és vezérlése"</string>
     <string name="permdesc_runSetActivityWatcher" msgid="6003603162578577406">"Lehetővé teszi az alkalmazás számára, hogy figyelje és vezérelje, hogy a rendszer hogyan indít el tevékenységeket. A rosszindulatú alkalmazások teljesen tönkretehetik a rendszert. Ez az engedély csak fejlesztéshez szükséges, normál használathoz sosem."</string>
     <string name="permlab_broadcastPackageRemoved" msgid="2576333434893532475">"eltávolított csomagú üzenetek küldése"</string>
diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml
index 8d3c139..1fdc861 100644
--- a/core/res/res/values-in/strings.xml
+++ b/core/res/res/values-in/strings.xml
@@ -299,10 +299,8 @@
     <string name="permdesc_shutdown" msgid="7046500838746291775">"Letakkan pengelola aktivitas dalam kondisi mati. Tidak melakukan penonaktifan penuh."</string>
     <string name="permlab_stopAppSwitches" msgid="4138608610717425573">"cegah pergantian aplikasi"</string>
     <string name="permdesc_stopAppSwitches" msgid="8262195802582255021">"Mencegah pengguna beralih ke apl lain."</string>
-    <!-- no translation found for permlab_getTopActivityInfo (2537922311411546016) -->
-    <skip />
-    <!-- no translation found for permdesc_getTopActivityInfo (2512448855496067131) -->
-    <skip />
+    <string name="permlab_getTopActivityInfo" msgid="2537922311411546016">"dapatkan info tentang aplikasi yang aktif"</string>
+    <string name="permdesc_getTopActivityInfo" msgid="2512448855496067131">"Memungkinkan pemegang mengambil informasi pribadi tentang aplikasi yang aktif di latar depan layar."</string>
     <string name="permlab_runSetActivityWatcher" msgid="892239094867182656">"memantau dan mengontrol semua peluncuran apl"</string>
     <string name="permdesc_runSetActivityWatcher" msgid="6003603162578577406">"Mengizinkan apl memantau dan mengontrol cara sistem meluncurkan kegiatan. Apl berbahaya dapat meretas sistem sepenuhnya. Izin ini hanya diperlukan untuk pengembangan, tidak pernah diperlukan untuk penggunaan normal."</string>
     <string name="permlab_broadcastPackageRemoved" msgid="2576333434893532475">"kirim siaran paket dihapus"</string>
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index 7fc8b73..73a743e 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -299,10 +299,8 @@
     <string name="permdesc_shutdown" msgid="7046500838746291775">"Mette il gestore delle attività in uno stato di chiusura. Non esegue una chiusura completa."</string>
     <string name="permlab_stopAppSwitches" msgid="4138608610717425573">"impedire commutazione applicazione"</string>
     <string name="permdesc_stopAppSwitches" msgid="8262195802582255021">"Impedisce all\'utente di passare a un\'altra applicazione."</string>
-    <!-- no translation found for permlab_getTopActivityInfo (2537922311411546016) -->
-    <skip />
-    <!-- no translation found for permdesc_getTopActivityInfo (2512448855496067131) -->
-    <skip />
+    <string name="permlab_getTopActivityInfo" msgid="2537922311411546016">"recupero di informazioni sull\'app corrente"</string>
+    <string name="permdesc_getTopActivityInfo" msgid="2512448855496067131">"Consente al titolare di recuperare le informazioni private sull\'app correntemente in primo piano sullo schermo."</string>
     <string name="permlab_runSetActivityWatcher" msgid="892239094867182656">"monitoraggio e controllo avvio di tutte le applicazioni"</string>
     <string name="permdesc_runSetActivityWatcher" msgid="6003603162578577406">"Consente all\'applicazione di monitorare e controllare l\'avvio delle attività da parte del sistema. Le applicazioni dannose potrebbero compromettere completamente il sistema. Questa autorizzazione è necessaria solo per lo sviluppo, mai per l\'utilizzo normale."</string>
     <string name="permlab_broadcastPackageRemoved" msgid="2576333434893532475">"invio broadcast rimossi dal pacchetto"</string>
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index 0afcbf7..5115890 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -299,10 +299,8 @@
     <string name="permdesc_shutdown" msgid="7046500838746291775">"アクティビティマネージャをシャットダウン状態にします。完全なシャットダウンは実行しません。"</string>
     <string name="permlab_stopAppSwitches" msgid="4138608610717425573">"アプリケーションの切り替えを禁止する"</string>
     <string name="permdesc_stopAppSwitches" msgid="8262195802582255021">"ユーザーが別のアプリに切り替えられないようにします。"</string>
-    <!-- no translation found for permlab_getTopActivityInfo (2537922311411546016) -->
-    <skip />
-    <!-- no translation found for permdesc_getTopActivityInfo (2512448855496067131) -->
-    <skip />
+    <string name="permlab_getTopActivityInfo" msgid="2537922311411546016">"現在のアプリ情報の取得"</string>
+    <string name="permdesc_getTopActivityInfo" msgid="2512448855496067131">"画面のフォアグラウンドで現在のアプリに関する非公開情報を取得することを所有者に許可します。"</string>
     <string name="permlab_runSetActivityWatcher" msgid="892239094867182656">"すべてのアプリ起動の監視と制御"</string>
     <string name="permdesc_runSetActivityWatcher" msgid="6003603162578577406">"システムによるアクティビティ起動方法を監視し制御することをアプリに許可します。この許可を悪意のあるアプリに利用されると、システム全体のセキュリティが侵害される恐れがあります。この許可は開発時にのみ必要で、通常の使用では不要です。"</string>
     <string name="permlab_broadcastPackageRemoved" msgid="2576333434893532475">"パッケージ削除ブロードキャストの送信"</string>
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index 85b35a7..9bac0d5 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -299,10 +299,8 @@
     <string name="permdesc_shutdown" msgid="7046500838746291775">"작업 관리자를 종료 상태로 설정합니다. 전체 종료를 수행하지는 않습니다."</string>
     <string name="permlab_stopAppSwitches" msgid="4138608610717425573">"애플리케이션 전환 방지"</string>
     <string name="permdesc_stopAppSwitches" msgid="8262195802582255021">"사용자가 다른 앱으로 전환하지 못하게 합니다."</string>
-    <!-- no translation found for permlab_getTopActivityInfo (2537922311411546016) -->
-    <skip />
-    <!-- no translation found for permdesc_getTopActivityInfo (2512448855496067131) -->
-    <skip />
+    <string name="permlab_getTopActivityInfo" msgid="2537922311411546016">"현재 앱 정보 얻기"</string>
+    <string name="permdesc_getTopActivityInfo" msgid="2512448855496067131">"권한을 가진 프로그램이 화면의 포그라운드에서 현재 애플리케이션에 대한 비공개 정보를 검색하도록 허용합니다."</string>
     <string name="permlab_runSetActivityWatcher" msgid="892239094867182656">"실행 중인 모든 앱 모니터링 및 제어"</string>
     <string name="permdesc_runSetActivityWatcher" msgid="6003603162578577406">"앱이 시스템에서 활동이 시작되는 방식을 모니터링하고 관리할 수 있도록 허용합니다. 이 경우 악성 앱이 이 기능을 이용하여 시스템을 완전히 손상시킬 수 있습니다. 이 권한은 개발 과정에만 필요하며 일반 사용 시에는 필요하지 않습니다."</string>
     <string name="permlab_broadcastPackageRemoved" msgid="2576333434893532475">"패키지 제거 브로드캐스트 보내기"</string>
diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml
index 86262e9..9ad75b3 100644
--- a/core/res/res/values-lt/strings.xml
+++ b/core/res/res/values-lt/strings.xml
@@ -299,10 +299,8 @@
     <string name="permdesc_shutdown" msgid="7046500838746291775">"Veiklos tvarkyklę perjungia į išsijungimo būseną. Neišjungia visiškai."</string>
     <string name="permlab_stopAppSwitches" msgid="4138608610717425573">"neleisti perjungti programų"</string>
     <string name="permdesc_stopAppSwitches" msgid="8262195802582255021">"Neleidžiama naudotojui perjungti į kitą programą."</string>
-    <!-- no translation found for permlab_getTopActivityInfo (2537922311411546016) -->
-    <skip />
-    <!-- no translation found for permdesc_getTopActivityInfo (2512448855496067131) -->
-    <skip />
+    <string name="permlab_getTopActivityInfo" msgid="2537922311411546016">"gauti esamos programos informaciją"</string>
+    <string name="permdesc_getTopActivityInfo" msgid="2512448855496067131">"Savininkui leidžiama gauti privačią esamos pirmaeilės ekrano programos informaciją."</string>
     <string name="permlab_runSetActivityWatcher" msgid="892239094867182656">"stebėti ir valdyti visų programų paleidimą"</string>
     <string name="permdesc_runSetActivityWatcher" msgid="6003603162578577406">"Leidžiama programai stebėti ir valdyti, kaip sistema paleidžia veiklą. Kenkėjiškos programos gali visiškai pažeisti sistemą. Šis leidimas reikalingas tik kuriant ir jo niekada nereikia naudojant įprastai."</string>
     <string name="permlab_broadcastPackageRemoved" msgid="2576333434893532475">"siųsti pašalinto paketo perdavimą"</string>
diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml
index cd28e58..71f4b41 100644
--- a/core/res/res/values-lv/strings.xml
+++ b/core/res/res/values-lv/strings.xml
@@ -299,10 +299,8 @@
     <string name="permdesc_shutdown" msgid="7046500838746291775">"Liek darbību pārvaldniekam pāriet izslēgšanas stāvoklī. Neveic pilnīgu izslēgšanu."</string>
     <string name="permlab_stopAppSwitches" msgid="4138608610717425573">"novērst lietojumprogrammu pārslēgšanu"</string>
     <string name="permdesc_stopAppSwitches" msgid="8262195802582255021">"Novērš lietotāja pārslēgšanos uz citu lietotni."</string>
-    <!-- no translation found for permlab_getTopActivityInfo (2537922311411546016) -->
-    <skip />
-    <!-- no translation found for permdesc_getTopActivityInfo (2512448855496067131) -->
-    <skip />
+    <string name="permlab_getTopActivityInfo" msgid="2537922311411546016">"pašreizējās lietotnes informācijas iegūšana"</string>
+    <string name="permdesc_getTopActivityInfo" msgid="2512448855496067131">"Ļauj īpašniekam izgūt privātu informāciju par pašreizējo lietojumprogrammu ekrāna priekšplānā."</string>
     <string name="permlab_runSetActivityWatcher" msgid="892239094867182656">"pārraudzīt un kontrolēt visu lietotņu atvēršanu"</string>
     <string name="permdesc_runSetActivityWatcher" msgid="6003603162578577406">"Ļauj lietotnei pārraudzīt un kontrolēt, kā sistēmā tiek palaistas darbības. Ļaunprātīgas lietotnes var pilnībā uzlauzt sistēmu. Šī atļauja ir nepieciešama tikai izstrādei, taču ne parastai lietošanai."</string>
     <string name="permlab_broadcastPackageRemoved" msgid="2576333434893532475">"sūtīt apraidi par pakotnes noņemšanu"</string>
diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml
index 0969c34..9ad7a50 100644
--- a/core/res/res/values-nb/strings.xml
+++ b/core/res/res/values-nb/strings.xml
@@ -299,10 +299,8 @@
     <string name="permdesc_shutdown" msgid="7046500838746291775">"Lar applikasjonen sette aktivitetshåndtereren i avslutningstilstand. Slår ikke systemet helt av."</string>
     <string name="permlab_stopAppSwitches" msgid="4138608610717425573">"forhindre applikasjonsbytte"</string>
     <string name="permdesc_stopAppSwitches" msgid="8262195802582255021">"Hindrer brukeren i å bytte til en annen app."</string>
-    <!-- no translation found for permlab_getTopActivityInfo (2537922311411546016) -->
-    <skip />
-    <!-- no translation found for permdesc_getTopActivityInfo (2512448855496067131) -->
-    <skip />
+    <string name="permlab_getTopActivityInfo" msgid="2537922311411546016">"få informasjon om appen"</string>
+    <string name="permdesc_getTopActivityInfo" msgid="2512448855496067131">"Tillater brukeren å innhente privat informasjon om den aktuelle appen i forgrunnen på skjermen."</string>
     <string name="permlab_runSetActivityWatcher" msgid="892239094867182656">"avervåke og kontrollere all oppstart av apper"</string>
     <string name="permdesc_runSetActivityWatcher" msgid="6003603162578577406">"Lar appen overvåke og kontrollere hvordan systemet starter opp aktiviteter. Ondsinnede apper kan utsette hele systemet for sikkerhetsbrudd. Denne tillatelsen er bare nødvendig for utviklere, aldri for vanlig bruk."</string>
     <string name="permlab_broadcastPackageRemoved" msgid="2576333434893532475">"kringkaste melding om fjernet pakke"</string>
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index f82e5dc..272f9c4 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -299,10 +299,8 @@
     <string name="permdesc_shutdown" msgid="7046500838746291775">"Hiermee wordt activiteitenbeheer uitgeschakeld. Er wordt geen volledige uitschakeling uitgevoerd."</string>
     <string name="permlab_stopAppSwitches" msgid="4138608610717425573">"schakelen tussen apps voorkomen"</string>
     <string name="permdesc_stopAppSwitches" msgid="8262195802582255021">"Hiermee wordt voorkomen dat de gebruiker overschakelt naar een andere app."</string>
-    <!-- no translation found for permlab_getTopActivityInfo (2537922311411546016) -->
-    <skip />
-    <!-- no translation found for permdesc_getTopActivityInfo (2512448855496067131) -->
-    <skip />
+    <string name="permlab_getTopActivityInfo" msgid="2537922311411546016">"huidige appgegevens ophalen"</string>
+    <string name="permdesc_getTopActivityInfo" msgid="2512448855496067131">"De houder kan hiermee persoonlijke gegevens ophalen over de applicatie die momenteel op de voorgrond wordt weergegeven."</string>
     <string name="permlab_runSetActivityWatcher" msgid="892239094867182656">"alle startende apps bijhouden en beheren"</string>
     <string name="permdesc_runSetActivityWatcher" msgid="6003603162578577406">"Hiermee kan de app de manier bijhouden en beheren waarop het systeem activiteiten start. Schadelijke apps kunnen het systeem volledig in gevaar brengen. Deze machtiging is alleen voor ontwikkeling vereist, nooit voor normaal gebruik."</string>
     <string name="permlab_broadcastPackageRemoved" msgid="2576333434893532475">"melding verzenden dat pakket is verwijderd"</string>
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index 749a73e..6818152 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -299,10 +299,8 @@
     <string name="permdesc_shutdown" msgid="7046500838746291775">"Przełącza menedżera aktywności w stan wyłączenia. Nie wykonuje pełnego wyłączenia."</string>
     <string name="permlab_stopAppSwitches" msgid="4138608610717425573">"zapobieganie przełączaniu aplikacji"</string>
     <string name="permdesc_stopAppSwitches" msgid="8262195802582255021">"Uniemożliwia użytkownikowi przełączenie na inną aplikację."</string>
-    <!-- no translation found for permlab_getTopActivityInfo (2537922311411546016) -->
-    <skip />
-    <!-- no translation found for permdesc_getTopActivityInfo (2512448855496067131) -->
-    <skip />
+    <string name="permlab_getTopActivityInfo" msgid="2537922311411546016">"pobierz informacje o bieżącej aplikacji"</string>
+    <string name="permdesc_getTopActivityInfo" msgid="2512448855496067131">"Zezwala posiadaczowi na pobieranie prywatnych informacji o bieżącej aplikacji i wyświetlanie ich na pierwszym planie ekranu."</string>
     <string name="permlab_runSetActivityWatcher" msgid="892239094867182656">"monitorowanie i kontrolowanie wszystkich uruchamianych aplikacji"</string>
     <string name="permdesc_runSetActivityWatcher" msgid="6003603162578577406">"Pozwala aplikacji na monitorowanie i kontrolowanie sposobu uruchamiania działań przez system. Złośliwe aplikacje mogą całkowicie naruszyć zabezpieczenia systemu. To uprawnienie nigdy nie jest potrzebne podczas normalnego użytkowania, a jedynie podczas programowania."</string>
     <string name="permlab_broadcastPackageRemoved" msgid="2576333434893532475">"wysyłanie transmisji informującej o usuniętym pakiecie"</string>
diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml
index 09a3d1f..1b42240 100644
--- a/core/res/res/values-pt-rPT/strings.xml
+++ b/core/res/res/values-pt-rPT/strings.xml
@@ -299,10 +299,8 @@
     <string name="permdesc_shutdown" msgid="7046500838746291775">"Coloca o gestor de actividade num estado de encerramento. Não executa um encerramento completo."</string>
     <string name="permlab_stopAppSwitches" msgid="4138608610717425573">"impedir trocas de aplicações"</string>
     <string name="permdesc_stopAppSwitches" msgid="8262195802582255021">"Impede que o utilizador mude para outra aplicação."</string>
-    <!-- no translation found for permlab_getTopActivityInfo (2537922311411546016) -->
-    <skip />
-    <!-- no translation found for permdesc_getTopActivityInfo (2512448855496067131) -->
-    <skip />
+    <string name="permlab_getTopActivityInfo" msgid="2537922311411546016">"obter informações da aplicação atual"</string>
+    <string name="permdesc_getTopActivityInfo" msgid="2512448855496067131">"Permite ao titular recuperar informações privadas acerca da aplicação atual no primeiro plano do ecrã."</string>
     <string name="permlab_runSetActivityWatcher" msgid="892239094867182656">"monitorizar e controlar a iniciação de todas as aplicações"</string>
     <string name="permdesc_runSetActivityWatcher" msgid="6003603162578577406">"Permite que uma aplicação monitorize e controle a forma como o sistema inicia atividades. As aplicações maliciosas podem comprometer totalmente o sistema. Esta autorização só é necessária para programação, nunca para utilização normal."</string>
     <string name="permlab_broadcastPackageRemoved" msgid="2576333434893532475">"enviar difusão de pacote removido"</string>
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index 3d5f68e..ba6c0aa 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -299,10 +299,8 @@
     <string name="permdesc_shutdown" msgid="7046500838746291775">"Coloca o gerenciador de atividades em um estado de desligamento. Não executa o desligamento completo."</string>
     <string name="permlab_stopAppSwitches" msgid="4138608610717425573">"evitar trocas de aplicativo"</string>
     <string name="permdesc_stopAppSwitches" msgid="8262195802582255021">"Impede que o usuário alterne para outro aplicativo."</string>
-    <!-- no translation found for permlab_getTopActivityInfo (2537922311411546016) -->
-    <skip />
-    <!-- no translation found for permdesc_getTopActivityInfo (2512448855496067131) -->
-    <skip />
+    <string name="permlab_getTopActivityInfo" msgid="2537922311411546016">"obter informações do aplicativo atual"</string>
+    <string name="permdesc_getTopActivityInfo" msgid="2512448855496067131">"Permite ao titular recuperar informações particulares sobre o aplicativo atual em primeiro plano na tela."</string>
     <string name="permlab_runSetActivityWatcher" msgid="892239094867182656">"monitorar e controlar todos os aplicativos que estão sendo iniciados"</string>
     <string name="permdesc_runSetActivityWatcher" msgid="6003603162578577406">"Permite que o aplicativo monitore e controle a forma como o sistema inicia atividades. Aplicativos maliciosos podem comprometer completamente o sistema. Esta permissão só é necessária para o desenvolvimento, nunca para o uso normal."</string>
     <string name="permlab_broadcastPackageRemoved" msgid="2576333434893532475">"enviar transmissão removida do pacote"</string>
diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
index ecfef60..1892bfc 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -299,10 +299,8 @@
     <string name="permdesc_shutdown" msgid="7046500838746291775">"Plasează Managerul de activităţi într-o stare de închidere. Nu efectuează o închidere completă."</string>
     <string name="permlab_stopAppSwitches" msgid="4138608610717425573">"împiedicare comutare între aplicaţii"</string>
     <string name="permdesc_stopAppSwitches" msgid="8262195802582255021">"Împiedică trecerea utilizatorului la o altă aplicaţie."</string>
-    <!-- no translation found for permlab_getTopActivityInfo (2537922311411546016) -->
-    <skip />
-    <!-- no translation found for permdesc_getTopActivityInfo (2512448855496067131) -->
-    <skip />
+    <string name="permlab_getTopActivityInfo" msgid="2537922311411546016">"obținere informații despre aplicația curentă"</string>
+    <string name="permdesc_getTopActivityInfo" msgid="2512448855496067131">"Permite proprietarului să preia informațiile private despre aplicația curentă în prim-planul ecranului."</string>
     <string name="permlab_runSetActivityWatcher" msgid="892239094867182656">"monitorizare şi control asupra lansării tuturor aplicaţiilor"</string>
     <string name="permdesc_runSetActivityWatcher" msgid="6003603162578577406">"Permite aplicaţiei să monitorizeze şi să controleze modul în care sistemul lansează activităţi. Aplicaţiile rău intenţionate pot să compromită sistemul în întregime. Această permisiune este necesară doar pentru dezvoltare şi niciodată pentru utilizarea normală."</string>
     <string name="permlab_broadcastPackageRemoved" msgid="2576333434893532475">"trimitere mesaj difuzat privind extragerea din pachet"</string>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index f2908f4..6ac3ea4 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -299,10 +299,8 @@
     <string name="permdesc_shutdown" msgid="7046500838746291775">"Завершает работу диспетчера активности. Не выполняет полное завершение работы."</string>
     <string name="permlab_stopAppSwitches" msgid="4138608610717425573">"запретить переключение приложений"</string>
     <string name="permdesc_stopAppSwitches" msgid="8262195802582255021">"Запрещает пользователям переключаться между приложениями."</string>
-    <!-- no translation found for permlab_getTopActivityInfo (2537922311411546016) -->
-    <skip />
-    <!-- no translation found for permdesc_getTopActivityInfo (2512448855496067131) -->
-    <skip />
+    <string name="permlab_getTopActivityInfo" msgid="2537922311411546016">"показывать информацию о текущем приложении"</string>
+    <string name="permdesc_getTopActivityInfo" msgid="2512448855496067131">"На экране будут отображаться сведения о текущем приложении."</string>
     <string name="permlab_runSetActivityWatcher" msgid="892239094867182656">"отслеживание и управление запуском всех приложений"</string>
     <string name="permdesc_runSetActivityWatcher" msgid="6003603162578577406">"Приложение сможет отслеживать запуск системных процессов и управлять им. Вредоносные программы смогут получить полный контроль над системой. Это разрешение необходимо только для разработки и не нужно в обычном режиме."</string>
     <string name="permlab_broadcastPackageRemoved" msgid="2576333434893532475">"отправлять рассылку об удалении пакета"</string>
diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml
index 9f6702b..170aae2 100644
--- a/core/res/res/values-sk/strings.xml
+++ b/core/res/res/values-sk/strings.xml
@@ -299,10 +299,8 @@
     <string name="permdesc_shutdown" msgid="7046500838746291775">"Uvedie správcu činností do vypnutého stavu. Úplné vypnutie však nenastane."</string>
     <string name="permlab_stopAppSwitches" msgid="4138608610717425573">"zabrániť prepínaniu aplikácií"</string>
     <string name="permdesc_stopAppSwitches" msgid="8262195802582255021">"Zabráni používateľovi prepnúť na inú aplikáciu."</string>
-    <!-- no translation found for permlab_getTopActivityInfo (2537922311411546016) -->
-    <skip />
-    <!-- no translation found for permdesc_getTopActivityInfo (2512448855496067131) -->
-    <skip />
+    <string name="permlab_getTopActivityInfo" msgid="2537922311411546016">"získať informácie o aktuálnej aplikácii"</string>
+    <string name="permdesc_getTopActivityInfo" msgid="2512448855496067131">"Umožňuje držiteľovi povolenia načítať súkromné ​​informácie o aktuálnej aplikácii v popredí obrazovky."</string>
     <string name="permlab_runSetActivityWatcher" msgid="892239094867182656">"sledovať a ovládať všetky spustenia aplikácií"</string>
     <string name="permdesc_runSetActivityWatcher" msgid="6003603162578577406">"Umožňuje aplikácii sledovať a ovládať spúšťanie aktivít systémom. Škodlivé aplikácie môžu systém úplne ovládnuť. Toto povolenie je potrebné len na účely vývoja, nikdy nie na bežné používanie."</string>
     <string name="permlab_broadcastPackageRemoved" msgid="2576333434893532475">"odoslanie vysielania o odstránení balíčka"</string>
diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml
index 20e23ce..07e96e0 100644
--- a/core/res/res/values-sl/strings.xml
+++ b/core/res/res/values-sl/strings.xml
@@ -299,10 +299,8 @@
     <string name="permdesc_shutdown" msgid="7046500838746291775">"Upravitelja dejavnosti preklopi v stanje za zaustavitev. Ne izvede celotne zaustavitve."</string>
     <string name="permlab_stopAppSwitches" msgid="4138608610717425573">"preprečevanje preklopa programov"</string>
     <string name="permdesc_stopAppSwitches" msgid="8262195802582255021">"Uporabniku preprečuje preklop v drug program."</string>
-    <!-- no translation found for permlab_getTopActivityInfo (2537922311411546016) -->
-    <skip />
-    <!-- no translation found for permdesc_getTopActivityInfo (2512448855496067131) -->
-    <skip />
+    <string name="permlab_getTopActivityInfo" msgid="2537922311411546016">"pridobivanje podatkov o trenutni aplikaciji"</string>
+    <string name="permdesc_getTopActivityInfo" msgid="2512448855496067131">"Omogoča imetniku pridobivanje zasebnih podatkov o trenutni aplikaciji v ospredju zaslona."</string>
     <string name="permlab_runSetActivityWatcher" msgid="892239094867182656">"spremljanje in nadzor vseh zagonov programov"</string>
     <string name="permdesc_runSetActivityWatcher" msgid="6003603162578577406">"Programu omogoča spremljanje in nadziranje načina, kako sistem zažene dejavnosti. Zlonamerni programi lahko v celoti ogrozijo varnost sistema. To dovoljenje je potrebno samo za razvoj, vendar nikoli za običajno uporabo."</string>
     <string name="permlab_broadcastPackageRemoved" msgid="2576333434893532475">"pošiljanje oddaje brez paketa"</string>
diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml
index b4f2096..e8b3cbd 100644
--- a/core/res/res/values-sr/strings.xml
+++ b/core/res/res/values-sr/strings.xml
@@ -299,10 +299,8 @@
     <string name="permdesc_shutdown" msgid="7046500838746291775">"Ставља менаџера активности у стање искључивања. Не искључује га у потпуности."</string>
     <string name="permlab_stopAppSwitches" msgid="4138608610717425573">"спречавање пребацивања са једне апликације на другу"</string>
     <string name="permdesc_stopAppSwitches" msgid="8262195802582255021">"Спречава да корисник пређе на другу апликацију."</string>
-    <!-- no translation found for permlab_getTopActivityInfo (2537922311411546016) -->
-    <skip />
-    <!-- no translation found for permdesc_getTopActivityInfo (2512448855496067131) -->
-    <skip />
+    <string name="permlab_getTopActivityInfo" msgid="2537922311411546016">"преузимање информација о актуелној апликацији"</string>
+    <string name="permdesc_getTopActivityInfo" msgid="2512448855496067131">"Дозвољава власнику да преузима приватне информације о актуелној апликацији у првом плану екрана."</string>
     <string name="permlab_runSetActivityWatcher" msgid="892239094867182656">"надгледање и контрола покретања свих апликација"</string>
     <string name="permdesc_runSetActivityWatcher" msgid="6003603162578577406">"Дозвољава апликацији да прати начин на који систем покреће активности и да њиме управља. Злонамерне апликације могу у потпуности да угрозе систем. Ова дозвола је потребна само за програмирање, а никада за уобичајено коришћење."</string>
     <string name="permlab_broadcastPackageRemoved" msgid="2576333434893532475">"слање емитовања уклоњеног пакета"</string>
diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml
index f858d54..6bbd38f 100644
--- a/core/res/res/values-sv/strings.xml
+++ b/core/res/res/values-sv/strings.xml
@@ -299,10 +299,8 @@
     <string name="permdesc_shutdown" msgid="7046500838746291775">"Sätter aktivitetshanteraren i avstängningsläge. Utför inte en fullständig avstängning."</string>
     <string name="permlab_stopAppSwitches" msgid="4138608610717425573">"förhindrar programbyten"</string>
     <string name="permdesc_stopAppSwitches" msgid="8262195802582255021">"Hindrar användaren från att byta till en annan app."</string>
-    <!-- no translation found for permlab_getTopActivityInfo (2537922311411546016) -->
-    <skip />
-    <!-- no translation found for permdesc_getTopActivityInfo (2512448855496067131) -->
-    <skip />
+    <string name="permlab_getTopActivityInfo" msgid="2537922311411546016">"hämta information om aktuell app"</string>
+    <string name="permdesc_getTopActivityInfo" msgid="2512448855496067131">"Innehavaren tillåts att hämta privat information om den app som för tillfället är i förgrunden på skärmen."</string>
     <string name="permlab_runSetActivityWatcher" msgid="892239094867182656">"övervaka och styra alla appar som öppnas"</string>
     <string name="permdesc_runSetActivityWatcher" msgid="6003603162578577406">"Tillåter att appen övervakar och styr hur systemet startar aktiviteter. Skadliga appar kan kompromettera systemet helt. Den här behörigheten behövs bara för programmering, aldrig för vanlig användning."</string>
     <string name="permlab_broadcastPackageRemoved" msgid="2576333434893532475">"skicka meddelande om borttaget paket"</string>
@@ -595,7 +593,7 @@
     <string name="permlab_sdcardRead" product="default" msgid="8235341515605559677">"testa åtkomst till skyddad lagringsenhet"</string>
     <string name="permdesc_sdcardRead" product="nosdcard" msgid="3642473292348132072">"Tillåter att appen testar behörighet till USB-enheter för användning på framtida enheter."</string>
     <string name="permdesc_sdcardRead" product="default" msgid="5914402684685848828">"Tillåter appen att testa behörighet till SD-kortet för användning på framtida enheter."</string>
-    <string name="permlab_sdcardWrite" product="nosdcard" msgid="8485979062254666748">"ändra eller ta bort innehållet"</string>
+    <string name="permlab_sdcardWrite" product="nosdcard" msgid="8485979062254666748">"ändra eller ta bort innehåll på USB-enheten"</string>
     <string name="permlab_sdcardWrite" product="default" msgid="8805693630050458763">"ändra eller ta bort innehåll på SD-kortet"</string>
     <string name="permdesc_sdcardWrite" product="nosdcard" msgid="6175406299445710888">"Gör att app skriver till USB."</string>
     <string name="permdesc_sdcardWrite" product="default" msgid="4337417790936632090">"Tillåter att appen skriver till SD-kortet."</string>
diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml
index 4430ed5..4070ac0 100644
--- a/core/res/res/values-sw/strings.xml
+++ b/core/res/res/values-sw/strings.xml
@@ -299,10 +299,8 @@
     <string name="permdesc_shutdown" msgid="7046500838746291775">"Huweka kisimamia shughuli katika hali ya kuzima. Haiadhiri uzimaji kamili"</string>
     <string name="permlab_stopAppSwitches" msgid="4138608610717425573">"zuia swichi za app"</string>
     <string name="permdesc_stopAppSwitches" msgid="8262195802582255021">"Huzuia mtumiaji dhidi ya kubadilisha na kwenda kwa programu nyingine."</string>
-    <!-- no translation found for permlab_getTopActivityInfo (2537922311411546016) -->
-    <skip />
-    <!-- no translation found for permdesc_getTopActivityInfo (2512448855496067131) -->
-    <skip />
+    <string name="permlab_getTopActivityInfo" msgid="2537922311411546016">"pata maelezo ya sasa kuhusu programu"</string>
+    <string name="permdesc_getTopActivityInfo" msgid="2512448855496067131">"Huruhusu mmiliki kurejesha maelezo ya faragha kuhusu programu ya sasa katika mandharimbele ya skrini."</string>
     <string name="permlab_runSetActivityWatcher" msgid="892239094867182656">"Fuatilia na kudhibiti uzinduzi wote wa programu"</string>
     <string name="permdesc_runSetActivityWatcher" msgid="6003603162578577406">"Inaruhusu programu kufuatilia na kudhibiti jinsi mfumo unazindua shughuli. Programu hasidi zinaweza kutia mfumo hatarini. Ruhusa inahitajika tu kwa usanidi, kamwe sio kwa matumizi ya kawaida."</string>
     <string name="permlab_broadcastPackageRemoved" msgid="2576333434893532475">"furushi lililotumwa limeondoa tangazo"</string>
diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml
index 1cad285..1e0e266 100644
--- a/core/res/res/values-th/strings.xml
+++ b/core/res/res/values-th/strings.xml
@@ -299,10 +299,8 @@
     <string name="permdesc_shutdown" msgid="7046500838746291775">"กำหนดให้ตัวจัดการกิจกรรมอยู่ในสถานะปิดระบบ โดยไม่ได้ปิดระบบอย่างสมบูรณ์"</string>
     <string name="permlab_stopAppSwitches" msgid="4138608610717425573">"ป้องกันการเปลี่ยนแอปพลิเคชัน"</string>
     <string name="permdesc_stopAppSwitches" msgid="8262195802582255021">"ป้องกันไม่ให้ผู้ใช้สลับไปใช้แอปพลิเคชันอื่น"</string>
-    <!-- no translation found for permlab_getTopActivityInfo (2537922311411546016) -->
-    <skip />
-    <!-- no translation found for permdesc_getTopActivityInfo (2512448855496067131) -->
-    <skip />
+    <string name="permlab_getTopActivityInfo" msgid="2537922311411546016">"รับข้อมูลแอปพลิเคชันปัจจุบัน"</string>
+    <string name="permdesc_getTopActivityInfo" msgid="2512448855496067131">"ช่วยให้เจ้าของสามารถดึงข้อมูลส่วนตัวเกี่ยวกับแอปพลิเคชันปัจจุบันในส่วนหน้าของหน้าจอ"</string>
     <string name="permlab_runSetActivityWatcher" msgid="892239094867182656">"ตรวจสอบและควบคุมแอปพลิเคชันทั้งหมดที่เปิดใช้งาน"</string>
     <string name="permdesc_runSetActivityWatcher" msgid="6003603162578577406">"อนุญาตให้แอปพลิเคชันตรวจสอบและควบคุมวิธีการที่ระบบเปิดกิจกรรมต่างๆ แอปพลิเคชันที่เป็นอันตรายอาจทำอันตรายแก่ระบบได้อย่างสิ้นเชิง การอนุญาตนี้จำเป็นสำหรับการพัฒนาเท่านั้น ไม่ใช้สำหรับแอปพลิเคชันทั่วไปโดยเด็ดขาด"</string>
     <string name="permlab_broadcastPackageRemoved" msgid="2576333434893532475">"ส่งการกระจายข้อมูลว่ามีการนำแพคเกจออก"</string>
diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml
index 6798be9..7f4de43 100644
--- a/core/res/res/values-tl/strings.xml
+++ b/core/res/res/values-tl/strings.xml
@@ -299,10 +299,8 @@
     <string name="permdesc_shutdown" msgid="7046500838746291775">"Inilalagay ang tagapamahala ng aktibidad sa katayuan ng pag-shutdown. Hindi nagsasagawa ng kumpletong pag-shutdown."</string>
     <string name="permlab_stopAppSwitches" msgid="4138608610717425573">"pigilan ang mga paglipat ng app"</string>
     <string name="permdesc_stopAppSwitches" msgid="8262195802582255021">"Pinipigilan ang mga user sa paglipat sa isa pang app."</string>
-    <!-- no translation found for permlab_getTopActivityInfo (2537922311411546016) -->
-    <skip />
-    <!-- no translation found for permdesc_getTopActivityInfo (2512448855496067131) -->
-    <skip />
+    <string name="permlab_getTopActivityInfo" msgid="2537922311411546016">"kunin ang impormasyon ng kasalukuyang app"</string>
+    <string name="permdesc_getTopActivityInfo" msgid="2512448855496067131">"Pinapayagan ang may-ari na bawiin ang pribadong impormasyon tungkol sa kasalukuyang application sa foreground ng screen."</string>
     <string name="permlab_runSetActivityWatcher" msgid="892239094867182656">"subaybayan at kontrolin ang lahat ng paglunsad ng app"</string>
     <string name="permdesc_runSetActivityWatcher" msgid="6003603162578577406">"Pinapayagan ang app na subaybayan at kontrolin kung paano naglulunsad ng mga aktibidad ang system. Maaaring ganap na ikompromiso ng nakakahamak na apps ang system. Kinakailangan lamang ang pahintulot na ito para sa pagpapabuti, hindi kailanman para sa normal na paggamit."</string>
     <string name="permlab_broadcastPackageRemoved" msgid="2576333434893532475">"magpadala ng package inalis ang broadcast"</string>
diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
index 015fe1b..f79fbf5 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -299,10 +299,8 @@
     <string name="permdesc_shutdown" msgid="7046500838746291775">"Eylem yöneticisini kapalı duruma getirir. Tam kapatma işlemi gerçekleştirmez."</string>
     <string name="permlab_stopAppSwitches" msgid="4138608610717425573">"uygulama değişimlerini engelle"</string>
     <string name="permdesc_stopAppSwitches" msgid="8262195802582255021">"Kullanıcının başka bir uygulamaya geçiş yapmasını engeller."</string>
-    <!-- no translation found for permlab_getTopActivityInfo (2537922311411546016) -->
-    <skip />
-    <!-- no translation found for permdesc_getTopActivityInfo (2512448855496067131) -->
-    <skip />
+    <string name="permlab_getTopActivityInfo" msgid="2537922311411546016">"geçerli uygulama bilgilerini al"</string>
+    <string name="permdesc_getTopActivityInfo" msgid="2512448855496067131">"İzin sahibine, ekranın ön planındaki geçerli uygulama hakkında gizli bilgileri alma olanağı verir."</string>
     <string name="permlab_runSetActivityWatcher" msgid="892239094867182656">"tüm uygulama başlatma işlemlerini izle ve denetle"</string>
     <string name="permdesc_runSetActivityWatcher" msgid="6003603162578577406">"Uygulamaya, sistemin etkinlikleri nasıl başlattığını izleme ve denetleme izni verir. Kötü amaçlı uygulamalar sistemi tamamen tehlikeye atabilir. Bu izin normal kullanım için değildir, sadece geliştirme süreçlerinde kullanılır."</string>
     <string name="permlab_broadcastPackageRemoved" msgid="2576333434893532475">"paket ile kaldırılan yayını gönder"</string>
diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml
index 17f545c..0a5c65a 100644
--- a/core/res/res/values-uk/strings.xml
+++ b/core/res/res/values-uk/strings.xml
@@ -299,10 +299,8 @@
     <string name="permdesc_shutdown" msgid="7046500838746291775">"Переводить диспетчер дій у стан завершення роботи. Не виконує повне завершення роботи."</string>
     <string name="permlab_stopAppSwitches" msgid="4138608610717425573">"запобіг. зміні програм"</string>
     <string name="permdesc_stopAppSwitches" msgid="8262195802582255021">"Запобігати переходу користувача до іншої програми."</string>
-    <!-- no translation found for permlab_getTopActivityInfo (2537922311411546016) -->
-    <skip />
-    <!-- no translation found for permdesc_getTopActivityInfo (2512448855496067131) -->
-    <skip />
+    <string name="permlab_getTopActivityInfo" msgid="2537922311411546016">"отримати інформацію про поточну програму"</string>
+    <string name="permdesc_getTopActivityInfo" msgid="2512448855496067131">"Дозволяє власникові отримувати приватну інформацію про поточну програму на передньому плані екрана."</string>
     <string name="permlab_runSetActivityWatcher" msgid="892239094867182656">"відстежувати та контролювати запуски всіх програм"</string>
     <string name="permdesc_runSetActivityWatcher" msgid="6003603162578577406">"Дозволяє програмі відстежувати та контролювати, як саме система запускає дії. Шкідливі програми можуть отримати повний контроль над системою. Цей дозвіл потрібний лише для розробки, а не для звичайного користування."</string>
     <string name="permlab_broadcastPackageRemoved" msgid="2576333434893532475">"надсил. запис про видал. пакета"</string>
diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml
index d26ee14..d65fea2 100644
--- a/core/res/res/values-vi/strings.xml
+++ b/core/res/res/values-vi/strings.xml
@@ -299,10 +299,8 @@
     <string name="permdesc_shutdown" msgid="7046500838746291775">"Đặt trình quản lý hoạt động sang trạng thái tắt. Không thực hiện tắt hoàn toàn."</string>
     <string name="permlab_stopAppSwitches" msgid="4138608610717425573">"ngăn chuyển đổi ứng dụng"</string>
     <string name="permdesc_stopAppSwitches" msgid="8262195802582255021">"Ngăn người dùng chuyển sang ứng dụng khác."</string>
-    <!-- no translation found for permlab_getTopActivityInfo (2537922311411546016) -->
-    <skip />
-    <!-- no translation found for permdesc_getTopActivityInfo (2512448855496067131) -->
-    <skip />
+    <string name="permlab_getTopActivityInfo" msgid="2537922311411546016">"truy cập thông tin ứng dụng hiện tại"</string>
+    <string name="permdesc_getTopActivityInfo" msgid="2512448855496067131">"Cho phép chủ sở hữu truy xuất thông tin cá nhân về ứng dụng hiện tại ở nền trước của màn hình."</string>
     <string name="permlab_runSetActivityWatcher" msgid="892239094867182656">"giám sát và kiểm soát tất cả hoạt động khởi chạy ứng dụng"</string>
     <string name="permdesc_runSetActivityWatcher" msgid="6003603162578577406">"Cho phép ứng dụng giám sát và kiểm soát cách hệ thống khởi chạy các hoạt động. Ứng dụng độc hại hoàn toàn có thể làm tổn hại hệ thống. Quyền này chỉ cần cho mục đích phát triển, không dành cho mục đích sử dụng thông thường."</string>
     <string name="permlab_broadcastPackageRemoved" msgid="2576333434893532475">"gửi truyền phát đã xóa của gói"</string>
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index 87faf15..9fe3783 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -299,10 +299,8 @@
     <string name="permdesc_shutdown" msgid="7046500838746291775">"使活动管理器进入关闭状态。不执行彻底关机。"</string>
     <string name="permlab_stopAppSwitches" msgid="4138608610717425573">"禁止切换应用"</string>
     <string name="permdesc_stopAppSwitches" msgid="8262195802582255021">"阻止用户切换到其他应用。"</string>
-    <!-- no translation found for permlab_getTopActivityInfo (2537922311411546016) -->
-    <skip />
-    <!-- no translation found for permdesc_getTopActivityInfo (2512448855496067131) -->
-    <skip />
+    <string name="permlab_getTopActivityInfo" msgid="2537922311411546016">"获取目前的应用信息"</string>
+    <string name="permdesc_getTopActivityInfo" msgid="2512448855496067131">"允许应用针对目前在屏幕前台运行的应用检索相关隐私信息。"</string>
     <string name="permlab_runSetActivityWatcher" msgid="892239094867182656">"监控所有应用的启动"</string>
     <string name="permdesc_runSetActivityWatcher" msgid="6003603162578577406">"允许应用监视和控制系统是如何启动活动的。恶意应用可能会完全破坏系统。此权限只有在进行开发时才需要,正常使用情况下绝不需要。"</string>
     <string name="permlab_broadcastPackageRemoved" msgid="2576333434893532475">"发送包删除的广播"</string>
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index 6d1f3bd..dab5091 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -299,10 +299,8 @@
     <string name="permdesc_shutdown" msgid="7046500838746291775">"讓活動管理員進入關機狀態,而不執行完整的關機程序。"</string>
     <string name="permlab_stopAppSwitches" msgid="4138608610717425573">"防止切換應用程式"</string>
     <string name="permdesc_stopAppSwitches" msgid="8262195802582255021">"防止使用者切換到其他應用程式。"</string>
-    <!-- no translation found for permlab_getTopActivityInfo (2537922311411546016) -->
-    <skip />
-    <!-- no translation found for permdesc_getTopActivityInfo (2512448855496067131) -->
-    <skip />
+    <string name="permlab_getTopActivityInfo" msgid="2537922311411546016">"取得目前的應用程式資訊"</string>
+    <string name="permdesc_getTopActivityInfo" msgid="2512448855496067131">"允許應用程式針對目前在螢幕前景運作的應用程式擷取私人資訊。"</string>
     <string name="permlab_runSetActivityWatcher" msgid="892239094867182656">"監視及控制所有應用程式的啟動程序"</string>
     <string name="permdesc_runSetActivityWatcher" msgid="6003603162578577406">"允許應用程式監視和控制系統啟動活動的方式。請注意,惡意應用程式可能利用此功能破壞整個系統。這個權限只有開發人員才需要,一般使用者不需使用這個權限。"</string>
     <string name="permlab_broadcastPackageRemoved" msgid="2576333434893532475">"傳送程式已移除廣播"</string>
diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml
index dafec7c..ece5e2a 100644
--- a/core/res/res/values-zu/strings.xml
+++ b/core/res/res/values-zu/strings.xml
@@ -299,10 +299,8 @@
     <string name="permdesc_shutdown" msgid="7046500838746291775">"Ibeka imeneja yomsebenzi kwisimo sokuvala shaqa. Ayenzi ukuvala shaqa okuphelele."</string>
     <string name="permlab_stopAppSwitches" msgid="4138608610717425573">"gwema ukushintsha kohlelo lokusebenza"</string>
     <string name="permdesc_stopAppSwitches" msgid="8262195802582255021">"Igwema umsebenzisi ukuthi ashintshele kolunye uhlelo lokusebenza."</string>
-    <!-- no translation found for permlab_getTopActivityInfo (2537922311411546016) -->
-    <skip />
-    <!-- no translation found for permdesc_getTopActivityInfo (2512448855496067131) -->
-    <skip />
+    <string name="permlab_getTopActivityInfo" msgid="2537922311411546016">"thola ulwazi lohlelo lokusebenza lwamanje"</string>
+    <string name="permdesc_getTopActivityInfo" msgid="2512448855496067131">"Ivumela umphathi ukuthi athole ulwazi oluyimfihlo mayelana nohlelo lokusebenza lwamanje ngaphambili kwesikrini."</string>
     <string name="permlab_runSetActivityWatcher" msgid="892239094867182656">"qapha futhi ulawule ukuqaliswa kwazo zonke izinsiza"</string>
     <string name="permdesc_runSetActivityWatcher" msgid="6003603162578577406">"Ivumela insiza ukuthi ihlole futhi ilawule ukuthi isistimu iziqalisa kanjani izehlakalo. Izinzisa ezinobungozi zingensa isistimu ibe sebungozini. Lemvume idingakalela intuthuku kuphela hhay ukusetshenziswa okwejwayelekile."</string>
     <string name="permlab_broadcastPackageRemoved" msgid="2576333434893532475">"thumela iphakheji yomsakazo okhishiwe"</string>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index dc921e6..ab2bd3a 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -2510,6 +2510,8 @@
             <flag name="flagIncludeNotImportantViews" value="0x00000002" />
             <!-- Has flag {@link android.accessibilityservice.AccessibilityServiceInfo#FLAG_REQUEST_TOUCH_EXPLORATION_MODE} -->
             <flag name="flagRequestTouchExplorationMode" value="0x00000004" />
+            <!-- Has flag {@link android.accessibilityservice.AccessibilityServiceInfo#FLAG_REQUEST_ENHANCED_WEB_ACCESSIBILITY} -->
+            <flag name="flagRequestEnhancedWebAccessibility" value="0x00000008" />
         </attr>
         <!-- Component name of an activity that allows the user to modify
              the settings for this service. This setting cannot be changed at runtime. -->
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 7f0fc0b..8f8f32d 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -535,6 +535,11 @@
     <!-- 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_storage" product="default">Access the SD card.</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_accessibilityFeatures">Accessibility features</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_accessibilityFeatures">Features that assistive technology can request.</string>
+
     <!--  Permissions -->
 
     <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
@@ -935,6 +940,20 @@
         interface of an accessibility service. Should never be needed for normal 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_canRequestTouchExplorationMode">request explore by touch</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_canRequestTouchExplorationMode">Allows the hoder to request an
+        interaction mode in which touched items are spoken aloud and the UI can be explored
+        via gestures.</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_canRequestEnahncedWebAccessibility">request enhanced web accessibility</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_canRequestEnahncedWebAccessibility">Allows the hoder to request
+        enabling of web accessibility enhancements. For example, installing scripts from
+        Google to make app content more accessible.</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_bindTextService">bind to a text service</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_bindTextService">Allows the holder to bind to the top-level
@@ -2695,25 +2714,6 @@
     <!-- SearchView accessibility description for voice button [CHAR LIMIT=NONE] -->
     <string name="searchview_description_voice">Voice search</string>
 
-    <!-- Title for a warning message about the interaction model changes after allowing an accessibility
-         service to put the device into explore by touch mode, displayed as a dialog message when
-         the user selects to enables the service. (default). [CHAR LIMIT=45] -->
-    <string name="enable_explore_by_touch_warning_title">Enable Explore by Touch?</string>
-    <!-- Summary for a warning message about the interaction model changes after allowing an accessibility
-         service to put the device into explore by touch mode, displayed as a dialog message when
-         the user selects to enables the service. (tablet). [CHAR LIMIT=NONE] -->
-    <string name="enable_explore_by_touch_warning_message" product="tablet">
-            <xliff:g id="accessibility_service_name">%1$s</xliff:g> wants to enable Explore by Touch.
-            When Explore by Touch is turned on, you can hear or see descriptions of what\'s under
-            your finger or perform gestures to interact with the tablet.</string>
-    <!-- Summary for a warning message about the interaction model changes after allowing an accessibility
-         service to put the device into explore by touch mode, displayed as a dialog message when
-         the user selects to enables the service. (default). [CHAR LIMIT=NONE] -->
-    <string name="enable_explore_by_touch_warning_message" product="default">
-            <xliff:g id="accessibility_service_name">%1$s</xliff:g> wants to enable Explore by Touch.
-            When Explore by Touch is turned on, you can hear or see descriptions of what\'s under
-            your finger or perform gestures to interact with the phone.</string>
-
     <!-- String used to display the date. This is the string to say something happened 1 month ago. -->
     <string name="oneMonthDurationPast">1 month ago</string>
     <!-- String used to display the date. This is the string to say something happened more than 1 month ago. -->
diff --git a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerTestActivity.java b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerTestActivity.java
index 245f537..463e999 100644
--- a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerTestActivity.java
+++ b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerTestActivity.java
@@ -60,13 +60,14 @@
 
     public static final String LOG_TAG = "ConnectivityManagerTestActivity";
     public static final int WAIT_FOR_SCAN_RESULT = 10 * 1000; //10 seconds
-    public static final int WIFI_SCAN_TIMEOUT = 50 * 1000;
-    public static final int SHORT_TIMEOUT = 5 * 1000;
-    public static final long LONG_TIMEOUT = 50 * 1000;
+    public static final int WIFI_SCAN_TIMEOUT = 50 * 1000; // 50 seconds
+    public static final int SHORT_TIMEOUT = 5 * 1000; // 5 seconds
+    public static final long LONG_TIMEOUT = 50 * 1000;  // 50 seconds
+    public static final long WIFI_CONNECTION_TIMEOUT = 5 * 60 * 1000; // 5 minutes
     // 2 minutes timer between wifi stop and start
-    public static final long  WIFI_STOP_START_INTERVAL = 2 * 60 * 1000;
+    public static final long  WIFI_STOP_START_INTERVAL = 2 * 60 * 1000; // 2 minutes
     // Set ping test timer to be 3 minutes
-    public static final long PING_TIMER = 3 * 60 *1000;
+    public static final long PING_TIMER = 3 * 60 *1000; // 3 minutes
     public static final int SUCCESS = 0;  // for Wifi tethering state change
     public static final int FAILURE = 1;
     public static final int INIT = -1;
@@ -573,7 +574,7 @@
         String ssid = config.SSID;
         config.SSID = convertToQuotedString(ssid);
 
-        //If Wifi is not enabled, enable it
+        // If Wifi is not enabled, enable it
         if (!mWifiManager.isWifiEnabled()) {
             log("Wifi is not enabled, enable it");
             mWifiManager.setWifiEnabled(true);
@@ -584,59 +585,16 @@
             }
         }
 
-        boolean foundApInScanResults = false;
-        for (int retry = 0; retry < 5; retry++) {
-            List<ScanResult> netList = mWifiManager.getScanResults();
-            if (netList != null) {
-                log("size of scan result list: " + netList.size());
-                for (int i = 0; i < netList.size(); i++) {
-                    ScanResult sr= netList.get(i);
-                    if (sr.SSID.equals(ssid)) {
-                        log("found " + ssid + " in the scan result list");
-                        log("retry: " + retry);
-                        foundApInScanResults = true;
-                        mWifiManager.connect(config,
-                                new WifiManager.ActionListener() {
-                                    public void onSuccess() {
-                                    }
-                                    public void onFailure(int reason) {
-                                        log("connect failure " + reason);
-                                    }
-                                });
-                        break;
-                   }
+        // Save network configuration and connect to network without scanning
+        mWifiManager.connect(config,
+            new WifiManager.ActionListener() {
+                public void onSuccess() {
                 }
-            }
-            if (foundApInScanResults) {
-                return true;
-            } else {
-                // Start an active scan
-                mWifiManager.startScanActive();
-                mScanResultIsAvailable = false;
-                long startTime = System.currentTimeMillis();
-                while (!mScanResultIsAvailable) {
-                    if ((System.currentTimeMillis() - startTime) > WIFI_SCAN_TIMEOUT) {
-                        log("wait for scan results timeout");
-                        return false;
-                    }
-                    // wait for the scan results to be available
-                    synchronized (this) {
-                        // wait for the scan result to be available
-                        try {
-                            this.wait(WAIT_FOR_SCAN_RESULT);
-                        } catch (InterruptedException e) {
-                            e.printStackTrace();
-                        }
-                        if ((mWifiManager.getScanResults() == null) ||
-                                (mWifiManager.getScanResults().size() <= 0)) {
-                            continue;
-                        }
-                        mScanResultIsAvailable = true;
-                    }
+                public void onFailure(int reason) {
+                    log("connect failure " + reason);
                 }
-            }
-        }
-        return false;
+            });
+        return true;
     }
 
     /*
diff --git a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/ConnectivityManagerMobileTest.java b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/ConnectivityManagerMobileTest.java
index 7928822..3111489 100644
--- a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/ConnectivityManagerMobileTest.java
+++ b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/ConnectivityManagerMobileTest.java
@@ -126,7 +126,7 @@
         cmActivity.disableWifi();
 
         assertTrue(cmActivity.waitForNetworkState(ConnectivityManager.TYPE_WIFI,
-                State.DISCONNECTED, ConnectivityManagerTestActivity.LONG_TIMEOUT));
+                State.DISCONNECTED,  ConnectivityManagerTestActivity.LONG_TIMEOUT));
         assertTrue(cmActivity.waitForNetworkState(ConnectivityManager.TYPE_MOBILE,
                 State.CONNECTED, ConnectivityManagerTestActivity.LONG_TIMEOUT));
         // Wait for 10 seconds for broadcasts to be sent out
@@ -184,7 +184,7 @@
                 ConnectivityManagerTestActivity.LONG_TIMEOUT));
         log("wifi state is enabled");
         assertTrue(cmActivity.waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.CONNECTED,
-                ConnectivityManagerTestActivity.LONG_TIMEOUT));
+                ConnectivityManagerTestActivity.WIFI_CONNECTION_TIMEOUT));
         if (!mWifiOnlyFlag) {
             assertTrue(cmActivity.waitForNetworkState(ConnectivityManager.TYPE_MOBILE,
                     State.DISCONNECTED, ConnectivityManagerTestActivity.LONG_TIMEOUT));
@@ -217,7 +217,7 @@
         assertTrue(cmActivity.waitForWifiState(WifiManager.WIFI_STATE_ENABLED,
                 ConnectivityManagerTestActivity.LONG_TIMEOUT));
         assertTrue(cmActivity.waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.CONNECTED,
-                ConnectivityManagerTestActivity.LONG_TIMEOUT));
+                ConnectivityManagerTestActivity.WIFI_CONNECTION_TIMEOUT));
 
         sleep(ConnectivityManagerTestActivity.SHORT_TIMEOUT);
         // Disable Wifi
@@ -257,7 +257,7 @@
 
         // Wait for Wifi to be connected and mobile to be disconnected
         assertTrue(cmActivity.waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.CONNECTED,
-                ConnectivityManagerTestActivity.LONG_TIMEOUT));
+                ConnectivityManagerTestActivity.WIFI_CONNECTION_TIMEOUT));
         if (!mWifiOnlyFlag) {
             assertTrue(cmActivity.waitForNetworkState(ConnectivityManager.TYPE_MOBILE,
                     State.DISCONNECTED, ConnectivityManagerTestActivity.LONG_TIMEOUT));
@@ -279,10 +279,10 @@
 
         // connect to Wifi
         assertTrue("failed to connect to " + mTestAccessPoint,
-                   cmActivity.connectToWifi(mTestAccessPoint));
+                cmActivity.connectToWifi(mTestAccessPoint));
 
         assertTrue(cmActivity.waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.CONNECTED,
-            ConnectivityManagerTestActivity.LONG_TIMEOUT));
+                ConnectivityManagerTestActivity.WIFI_CONNECTION_TIMEOUT));
 
         // Wait for a few seconds to avoid the state that both Mobile and Wifi is connected
         sleep(ConnectivityManagerTestActivity.SHORT_TIMEOUT);
@@ -418,9 +418,9 @@
 
         // Connect to Wifi
         assertTrue("failed to connect to " + mTestAccessPoint,
-                   cmActivity.connectToWifi(mTestAccessPoint));
+                cmActivity.connectToWifi(mTestAccessPoint));
         assertTrue(cmActivity.waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.CONNECTED,
-                            ConnectivityManagerTestActivity.LONG_TIMEOUT));
+                ConnectivityManagerTestActivity.WIFI_CONNECTION_TIMEOUT));
 
         // validate state and broadcast
         if (!cmActivity.validateNetworkStates(ConnectivityManager.TYPE_WIFI)) {
@@ -454,7 +454,7 @@
                 cmActivity.connectToWifi(mTestAccessPoint));
 
         assertTrue(cmActivity.waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.CONNECTED,
-                ConnectivityManagerTestActivity.LONG_TIMEOUT));
+                ConnectivityManagerTestActivity.WIFI_CONNECTION_TIMEOUT));
 
         try {
             Thread.sleep(ConnectivityManagerTestActivity.SHORT_TIMEOUT);
@@ -484,7 +484,7 @@
         cmActivity.setAirplaneMode(getInstrumentation().getContext(), false);
 
         assertTrue(cmActivity.waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.CONNECTED,
-                            ConnectivityManagerTestActivity.LONG_TIMEOUT));
+                ConnectivityManagerTestActivity.WIFI_CONNECTION_TIMEOUT));
         if (!mWifiOnlyFlag) {
             assertTrue(cmActivity.waitForNetworkState(ConnectivityManager.TYPE_MOBILE,
                     State.DISCONNECTED, ConnectivityManagerTestActivity.LONG_TIMEOUT));
@@ -505,11 +505,11 @@
         assertNotNull("SSID is null", mTestAccessPoint);
         //Connect to mTestAccessPoint
         assertTrue("failed to connect to " + mTestAccessPoint,
-                   cmActivity.connectToWifi(mTestAccessPoint));
+                cmActivity.connectToWifi(mTestAccessPoint));
         assertTrue(cmActivity.waitForWifiState(WifiManager.WIFI_STATE_ENABLED,
                 ConnectivityManagerTestActivity.LONG_TIMEOUT));
         assertTrue(cmActivity.waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.CONNECTED,
-                            ConnectivityManagerTestActivity.LONG_TIMEOUT));
+                ConnectivityManagerTestActivity.WIFI_CONNECTION_TIMEOUT));
         assertNotNull("Not associated with any AP",
                       cmActivity.mWifiManager.getConnectionInfo().getBSSID());
 
diff --git a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/WifiConnectionTest.java b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/WifiConnectionTest.java
index 81075ef..de0298e 100644
--- a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/WifiConnectionTest.java
+++ b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/WifiConnectionTest.java
@@ -118,7 +118,7 @@
 
         // step 2: verify Wifi state and network state;
         assertTrue(mAct.waitForNetworkState(ConnectivityManager.TYPE_WIFI,
-                State.CONNECTED, 6 * ConnectivityManagerTestActivity.LONG_TIMEOUT));
+                State.CONNECTED, ConnectivityManagerTestActivity.WIFI_CONNECTION_TIMEOUT));
 
         // step 3: verify the current connected network is the given SSID
         assertNotNull("Wifi connection returns null", mAct.mWifiManager.getConnectionInfo());
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 7bfb594..53876a5 100644
--- a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/stress/WifiStressTest.java
+++ b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/stress/WifiStressTest.java
@@ -248,7 +248,7 @@
         assertTrue(mAct.waitForWifiState(WifiManager.WIFI_STATE_ENABLED,
                 ConnectivityManagerTestActivity.SHORT_TIMEOUT));
         assertTrue(mAct.waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.CONNECTED,
-                ConnectivityManagerTestActivity.LONG_TIMEOUT));
+                ConnectivityManagerTestActivity.WIFI_CONNECTION_TIMEOUT));
         // Run ping test to verify the data connection
         assertTrue("Wi-Fi is connected, but no data connection.", mAct.pingTest(null));
 
@@ -302,7 +302,7 @@
                     ConnectivityManagerTestActivity.SHORT_TIMEOUT));
             assertTrue("Wait for Wi-Fi connection timeout after wake up",
                     mAct.waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.CONNECTED,
-                    6 * ConnectivityManagerTestActivity.LONG_TIMEOUT));
+                    ConnectivityManagerTestActivity.WIFI_CONNECTION_TIMEOUT));
             long connectionTime = System.currentTimeMillis() - startTime;
             sum += connectionTime;
             log("average reconnection time is: " + sum/(i+1));
diff --git a/core/tests/coretests/src/com/android/internal/util/FastXmlSerializerTest.java b/core/tests/coretests/src/com/android/internal/util/FastXmlSerializerTest.java
new file mode 100644
index 0000000..be7116d
--- /dev/null
+++ b/core/tests/coretests/src/com/android/internal/util/FastXmlSerializerTest.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.util;
+
+import junit.framework.TestCase;
+
+import org.xmlpull.v1.XmlSerializer;
+
+import java.io.ByteArrayOutputStream;
+
+/**
+ * Tests for {@link FastXmlSerializer}
+ */
+public class FastXmlSerializerTest extends TestCase {
+    public void testEmptyText() throws Exception {
+        final ByteArrayOutputStream stream = new ByteArrayOutputStream();
+
+        final XmlSerializer out = new FastXmlSerializer();
+        out.setOutput(stream, "utf-8");
+        out.startDocument(null, true);
+        out.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true);
+
+        out.startTag(null, "string");
+        out.attribute(null, "name", "meow");
+        out.text("");
+        out.endTag(null, "string");
+
+        out.endDocument();
+
+        assertEquals("<?xml version='1.0' encoding='utf-8' standalone='yes' ?>\n"
+                + "<string name=\"meow\"></string>", stream.toString());
+    }
+}
diff --git a/core/tests/coretests/src/com/android/internal/util/IndentingPrintWriterTest.java b/core/tests/coretests/src/com/android/internal/util/IndentingPrintWriterTest.java
new file mode 100644
index 0000000..6773612
--- /dev/null
+++ b/core/tests/coretests/src/com/android/internal/util/IndentingPrintWriterTest.java
@@ -0,0 +1,132 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.util;
+
+import junit.framework.TestCase;
+
+import java.io.ByteArrayOutputStream;
+import java.io.PrintWriter;
+
+/**
+ * Tests for {@link IndentingPrintWriter}.
+ */
+public class IndentingPrintWriterTest extends TestCase {
+
+    private ByteArrayOutputStream mStream;
+    private PrintWriter mWriter;
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+
+        mStream = new ByteArrayOutputStream();
+        mWriter = new PrintWriter(mStream);
+    }
+
+    public void testMultipleIndents() throws Exception {
+        final IndentingPrintWriter pw = new IndentingPrintWriter(mWriter, "  ");
+
+        pw.print("Hello");
+        pw.increaseIndent();
+        pw.println();
+        pw.print("World");
+        pw.increaseIndent();
+        pw.println();
+        pw.print("And");
+        pw.decreaseIndent();
+        pw.println();
+        pw.print("Goodbye");
+        pw.decreaseIndent();
+        pw.println();
+        pw.print("World");
+        pw.println();
+
+        pw.flush();
+        assertEquals("Hello\n  World\n    And\n  Goodbye\nWorld\n", mStream.toString());
+    }
+
+    public void testAdjustIndentAfterNewline() throws Exception {
+        final IndentingPrintWriter pw = new IndentingPrintWriter(mWriter, "  ");
+
+        pw.println("Hello");
+        pw.increaseIndent();
+        pw.println("World");
+
+        pw.flush();
+        assertEquals("Hello\n  World\n", mStream.toString());
+    }
+
+    public void testWrapping() throws Exception {
+        final IndentingPrintWriter pw = new IndentingPrintWriter(mWriter, "", 10);
+
+        pw.print("dog ");
+        pw.print("cat ");
+        pw.print("cow ");
+        pw.print("meow ");
+
+        pw.flush();
+        assertEquals("dog cat \ncow meow ", mStream.toString());
+    }
+
+    public void testWrappingIndented() throws Exception {
+        final IndentingPrintWriter pw = new IndentingPrintWriter(mWriter, "    ", 10);
+
+        pw.increaseIndent();
+        pw.print("dog ");
+        pw.print("meow ");
+        pw.print("a ");
+        pw.print("b ");
+        pw.print("cow ");
+
+        pw.flush();
+        assertEquals("    dog \n    meow \n    a b \n    cow ", mStream.toString());
+    }
+
+    public void testWrappingEmbeddedNewlines() throws Exception {
+        final IndentingPrintWriter pw = new IndentingPrintWriter(mWriter, "  ", 10);
+
+        pw.increaseIndent();
+        pw.print("Lorem ipsum \ndolor sit \namet, consectetur \nadipiscing elit.");
+
+        pw.flush();
+        assertEquals("  Lorem ip\n  sum \n  dolor si\n  t \n  amet, co\n"
+                + "  nsectetu\n  r \n  adipisci\n  ng elit.\n", mStream.toString());
+    }
+
+    public void testWrappingSingleGiant() throws Exception {
+        final IndentingPrintWriter pw = new IndentingPrintWriter(mWriter, "  ", 10);
+
+        pw.increaseIndent();
+        pw.print("Lorem ipsum dolor sit amet, consectetur adipiscing elit.");
+
+        pw.flush();
+        assertEquals("  Lorem ip\n  sum dolo\n  r sit am\n  et, cons\n"
+                + "  ectetur \n  adipisci\n  ng elit.\n", mStream.toString());
+    }
+
+    public void testWrappingPrefixedGiant() throws Exception {
+        final IndentingPrintWriter pw = new IndentingPrintWriter(mWriter, "  ", 10);
+
+        pw.increaseIndent();
+        pw.print("foo");
+        pw.print("Lorem ipsum dolor sit amet, consectetur adipiscing elit.");
+
+        pw.flush();
+        assertEquals("  foo\n  Lorem ip\n  sum dolo\n  r sit am\n  et, cons\n"
+                + "  ectetur \n  adipisci\n  ng elit.\n", mStream.toString());
+    }
+}
diff --git a/core/tests/coretests/src/com/android/internal/util/StateMachineTest.java b/core/tests/coretests/src/com/android/internal/util/StateMachineTest.java
index 418bbd6..2a2c24e 100644
--- a/core/tests/coretests/src/com/android/internal/util/StateMachineTest.java
+++ b/core/tests/coretests/src/com/android/internal/util/StateMachineTest.java
@@ -16,6 +16,9 @@
 
 package com.android.internal.util;
 
+import java.util.Collection;
+import java.util.Iterator;
+
 import android.os.Debug;
 import android.os.HandlerThread;
 import android.os.Looper;
@@ -58,11 +61,28 @@
         }
     }
 
+    private void dumpLogRecs(StateMachine sm) {
+        int size = sm.getLogRecSize();
+        tlog("size=" + size + " count=" + sm.getLogRecCount());
+        for (int i = 0; i < size; i++) {
+            LogRec lr = sm.getLogRec(i);
+            tlog(lr.toString());
+        }
+    }
+
+    private void dumpLogRecs(Collection<LogRec> clr) {
+        int size = clr.size();
+        tlog("size=" + size);
+        for (LogRec lr : clr) {
+            tlog(lr.toString());
+        }
+    }
+
     /**
      * Tests {@link StateMachine#quit()}.
      */
     class StateMachineQuitTest extends StateMachine {
-        Object mWaitUntilTestDone = new Object();
+        Collection<LogRec> mLogRecs;
 
         StateMachineQuitTest(String name) {
             super(name);
@@ -78,39 +98,32 @@
 
         @Override
         public void onQuitting() {
-            Log.d(TAG, "onQuitting");
+            log("onQuitting");
             addLogRec(ON_QUITTING);
+            mLogRecs = mThisSm.copyLogRecs();
             synchronized (mThisSm) {
                 mThisSm.notifyAll();
             }
-
-            // Don't leave onQuitting before the test is done as everything is cleared
-            // including the log records.
-            synchronized (mWaitUntilTestDone) {
-                try {
-                    mWaitUntilTestDone.wait();
-                } catch(InterruptedException e) {
-                }
-            }
         }
 
         class S1 extends State {
+            @Override
             public void exit() {
-                Log.d(TAG, "S1.exit");
-                addLogRec(EXIT, mS1);
+                log("S1.exit");
+                addLogRec(EXIT);
             }
             @Override
             public boolean processMessage(Message message) {
                 switch(message.what) {
                     // Sleep and assume the other messages will be queued up.
                     case TEST_CMD_1: {
-                        Log.d(TAG, "TEST_CMD_1");
+                        log("TEST_CMD_1");
                         sleep(500);
                         quit();
                         break;
                     }
                     default: {
-                        Log.d(TAG, "default what=" + message.what);
+                        log("default what=" + message.what);
                         break;
                     }
                 }
@@ -128,7 +141,7 @@
 
         StateMachineQuitTest smQuitTest = new StateMachineQuitTest("smQuitTest");
         smQuitTest.start();
-        if (smQuitTest.isDbg()) Log.d(TAG, "testStateMachineQuit E");
+        if (smQuitTest.isDbg()) tlog("testStateMachineQuit E");
 
         synchronized (smQuitTest) {
 
@@ -141,38 +154,36 @@
                 // wait for the messages to be handled
                 smQuitTest.wait();
             } catch (InterruptedException e) {
-                Log.e(TAG, "testStateMachineQuit: exception while waiting " + e.getMessage());
+                tloge("testStateMachineQuit: exception while waiting " + e.getMessage());
             }
         }
 
-        assertEquals(8, smQuitTest.getLogRecCount());
+        dumpLogRecs(smQuitTest.mLogRecs);
+        assertEquals(8, smQuitTest.mLogRecs.size());
 
         LogRec lr;
-
-        for (int i = 0; i < 6; i++) {
-            lr = smQuitTest.getLogRec(i);
-            assertEquals(i+1, lr.getWhat());
+        Iterator<LogRec> itr = smQuitTest.mLogRecs.iterator();
+        for (int i = 1; i <= 6; i++) {
+            lr = itr.next();
+            assertEquals(i, lr.getWhat());
             assertEquals(smQuitTest.mS1, lr.getState());
             assertEquals(smQuitTest.mS1, lr.getOriginalState());
         }
-        lr = smQuitTest.getLogRec(6);
+        lr = itr.next();
         assertEquals(EXIT, lr.getInfo());
         assertEquals(smQuitTest.mS1, lr.getState());
 
-        lr = smQuitTest.getLogRec(7);
+        lr = itr.next();
         assertEquals(ON_QUITTING, lr.getInfo());
 
-        synchronized (smQuitTest.mWaitUntilTestDone) {
-            smQuitTest.mWaitUntilTestDone.notifyAll();
-        }
-        if (smQuitTest.isDbg()) Log.d(TAG, "testStateMachineQuit X");
+        if (smQuitTest.isDbg()) tlog("testStateMachineQuit X");
     }
 
     /**
      * Tests {@link StateMachine#quitNow()}
      */
     class StateMachineQuitNowTest extends StateMachine {
-        Object mWaitUntilTestDone = new Object();
+        public Collection<LogRec> mLogRecs = null;
 
         StateMachineQuitNowTest(String name) {
             super(name);
@@ -188,39 +199,34 @@
 
         @Override
         public void onQuitting() {
-            Log.d(TAG, "onQuitting");
+            log("onQuitting");
             addLogRec(ON_QUITTING);
+            // Get a copy of the log records since we're quitting and they will disappear
+            mLogRecs = mThisSm.copyLogRecs();
+
             synchronized (mThisSm) {
                 mThisSm.notifyAll();
             }
-
-            // Don't leave onQuitting before the test is done as everything is cleared
-            // including the log records.
-            synchronized (mWaitUntilTestDone) {
-                try {
-                    mWaitUntilTestDone.wait();
-                } catch(InterruptedException e) {
-                }
-            }
         }
 
         class S1 extends State {
+            @Override
             public void exit() {
-                Log.d(TAG, "S1.exit");
-                addLogRec(EXIT, mS1);
+                log("S1.exit");
+                addLogRec(EXIT);
             }
             @Override
             public boolean processMessage(Message message) {
                 switch(message.what) {
                     // Sleep and assume the other messages will be queued up.
                     case TEST_CMD_1: {
-                        Log.d(TAG, "TEST_CMD_1");
+                        log("TEST_CMD_1");
                         sleep(500);
                         quitNow();
                         break;
                     }
                     default: {
-                        Log.d(TAG, "default what=" + message.what);
+                        log("default what=" + message.what);
                         break;
                     }
                 }
@@ -238,11 +244,11 @@
 
         StateMachineQuitNowTest smQuitNowTest = new StateMachineQuitNowTest("smQuitNowTest");
         smQuitNowTest.start();
-        if (smQuitNowTest.isDbg()) Log.d(TAG, "testStateMachineQuitNow E");
+        if (smQuitNowTest.isDbg()) tlog("testStateMachineQuitNow E");
 
         synchronized (smQuitNowTest) {
 
-            // Send 6 messages but we'll QuitNow on the first so even though
+            // Send 6 message we'll QuitNow on the first even though
             // we send 6 only one will be processed.
             for (int i = 1; i <= 6; i++) {
                 smQuitNowTest.sendMessage(smQuitNowTest.obtainMessage(i));
@@ -252,31 +258,27 @@
                 // wait for the messages to be handled
                 smQuitNowTest.wait();
             } catch (InterruptedException e) {
-                Log.e(TAG, "testStateMachineQuitNow: exception while waiting " + e.getMessage());
+                tloge("testStateMachineQuitNow: exception while waiting " + e.getMessage());
             }
         }
 
-        // Only three records because we executed quitNow.
-        assertEquals(3, smQuitNowTest.getLogRecCount());
+        tlog("testStateMachineQuiteNow: logRecs=" + smQuitNowTest.mLogRecs);
+        assertEquals(3, smQuitNowTest.mLogRecs.size());
 
-        LogRec lr;
-
-        lr = smQuitNowTest.getLogRec(0);
+        Iterator<LogRec> itr = smQuitNowTest.mLogRecs.iterator();
+        LogRec lr = itr.next();
         assertEquals(1, lr.getWhat());
         assertEquals(smQuitNowTest.mS1, lr.getState());
         assertEquals(smQuitNowTest.mS1, lr.getOriginalState());
 
-        lr = smQuitNowTest.getLogRec(1);
+        lr = itr.next();
         assertEquals(EXIT, lr.getInfo());
         assertEquals(smQuitNowTest.mS1, lr.getState());
 
-        lr = smQuitNowTest.getLogRec(2);
+        lr = itr.next();
         assertEquals(ON_QUITTING, lr.getInfo());
 
-        synchronized (smQuitNowTest.mWaitUntilTestDone) {
-            smQuitNowTest.mWaitUntilTestDone.notifyAll();
-        }
-        if (smQuitNowTest.isDbg()) Log.d(TAG, "testStateMachineQuitNow X");
+        if (smQuitNowTest.isDbg()) tlog("testStateMachineQuitNow X");
     }
 
     /**
@@ -303,39 +305,39 @@
             @Override
             public void enter() {
                 // Test transitions in enter on the initial state work
-                addLogRec(ENTER, mS1);
+                addLogRec(ENTER);
                 transitionTo(mS2);
-                Log.d(TAG, "S1.enter");
+                log("S1.enter");
             }
             @Override
             public void exit() {
-                // Test that message is HSM_INIT_CMD
-                addLogRec(EXIT, mS1);
-                Log.d(TAG, "S1.exit");
+                addLogRec(EXIT);
+                log("S1.exit");
             }
         }
 
         class S2 extends State {
             @Override
             public void enter() {
-                addLogRec(ENTER, mS2);
-                Log.d(TAG, "S2.enter");
+                addLogRec(ENTER);
+                log("S2.enter");
             }
             @Override
             public void exit() {
-                addLogRec(EXIT, mS2);
-                assertEquals(TEST_CMD_1, getCurrentMessage().what);
-
                 // Test transition in exit work
                 transitionTo(mS4);
-                Log.d(TAG, "S2.exit");
+
+                assertEquals(TEST_CMD_1, getCurrentMessage().what);
+                addLogRec(EXIT);
+
+                log("S2.exit");
             }
             @Override
             public boolean processMessage(Message message) {
                 // Start a transition to S3 but it will be
                 // changed to a transition to S4 in exit
                 transitionTo(mS3);
-                Log.d(TAG, "S2.processMessage");
+                log("S2.processMessage");
                 return HANDLED;
             }
         }
@@ -343,28 +345,28 @@
         class S3 extends State {
             @Override
             public void enter() {
-                addLogRec(ENTER, mS3);
-                Log.d(TAG, "S3.enter");
+                addLogRec(ENTER);
+                log("S3.enter");
             }
             @Override
             public void exit() {
-                addLogRec(EXIT, mS3);
-                Log.d(TAG, "S3.exit");
+                addLogRec(EXIT);
+                log("S3.exit");
             }
         }
 
         class S4 extends State {
             @Override
             public void enter() {
-                addLogRec(ENTER, mS4);
+                addLogRec(ENTER);
                 // Test that we can do halting in an enter/exit
                 transitionToHaltingState();
-                Log.d(TAG, "S4.enter");
+                log("S4.enter");
             }
             @Override
             public void exit() {
-                addLogRec(EXIT, mS4);
-                Log.d(TAG, "S4.exit");
+                addLogRec(EXIT);
+                log("S4.exit");
             }
         }
 
@@ -390,7 +392,7 @@
             new StateMachineEnterExitTransitionToTest("smEnterExitTranstionToTest");
         smEnterExitTranstionToTest.start();
         if (smEnterExitTranstionToTest.isDbg()) {
-            Log.d(TAG, "testStateMachineEnterExitTransitionToTest E");
+            tlog("testStateMachineEnterExitTransitionToTest E");
         }
 
         synchronized (smEnterExitTranstionToTest) {
@@ -400,13 +402,14 @@
                 // wait for the messages to be handled
                 smEnterExitTranstionToTest.wait();
             } catch (InterruptedException e) {
-                Log.e(TAG, "testStateMachineEnterExitTransitionToTest: exception while waiting "
+                tloge("testStateMachineEnterExitTransitionToTest: exception while waiting "
                     + e.getMessage());
             }
         }
 
-        assertEquals(smEnterExitTranstionToTest.getLogRecCount(), 9);
+        dumpLogRecs(smEnterExitTranstionToTest);
 
+        assertEquals(9, smEnterExitTranstionToTest.getLogRecCount());
         LogRec lr;
 
         lr = smEnterExitTranstionToTest.getLogRec(0);
@@ -425,29 +428,44 @@
         assertEquals(TEST_CMD_1, lr.getWhat());
         assertEquals(smEnterExitTranstionToTest.mS2, lr.getState());
         assertEquals(smEnterExitTranstionToTest.mS2, lr.getOriginalState());
+        assertEquals(smEnterExitTranstionToTest.mS3, lr.getDestState());
 
         lr = smEnterExitTranstionToTest.getLogRec(4);
-        assertEquals(EXIT, lr.getInfo());
+        assertEquals(TEST_CMD_1, lr.getWhat());
         assertEquals(smEnterExitTranstionToTest.mS2, lr.getState());
+        assertEquals(smEnterExitTranstionToTest.mS2, lr.getOriginalState());
+        assertEquals(smEnterExitTranstionToTest.mS4, lr.getDestState());
+        assertEquals(EXIT, lr.getInfo());
 
         lr = smEnterExitTranstionToTest.getLogRec(5);
+        assertEquals(TEST_CMD_1, lr.getWhat());
         assertEquals(ENTER, lr.getInfo());
         assertEquals(smEnterExitTranstionToTest.mS3, lr.getState());
+        assertEquals(smEnterExitTranstionToTest.mS3, lr.getOriginalState());
+        assertEquals(smEnterExitTranstionToTest.mS4, lr.getDestState());
 
         lr = smEnterExitTranstionToTest.getLogRec(6);
+        assertEquals(TEST_CMD_1, lr.getWhat());
         assertEquals(EXIT, lr.getInfo());
         assertEquals(smEnterExitTranstionToTest.mS3, lr.getState());
+        assertEquals(smEnterExitTranstionToTest.mS3, lr.getOriginalState());
+        assertEquals(smEnterExitTranstionToTest.mS4, lr.getDestState());
 
         lr = smEnterExitTranstionToTest.getLogRec(7);
+        assertEquals(TEST_CMD_1, lr.getWhat());
         assertEquals(ENTER, lr.getInfo());
         assertEquals(smEnterExitTranstionToTest.mS4, lr.getState());
+        assertEquals(smEnterExitTranstionToTest.mS4, lr.getOriginalState());
+        assertEquals(smEnterExitTranstionToTest.mS4, lr.getDestState());
 
         lr = smEnterExitTranstionToTest.getLogRec(8);
+        assertEquals(TEST_CMD_1, lr.getWhat());
         assertEquals(EXIT, lr.getInfo());
         assertEquals(smEnterExitTranstionToTest.mS4, lr.getState());
+        assertEquals(smEnterExitTranstionToTest.mS4, lr.getOriginalState());
 
         if (smEnterExitTranstionToTest.isDbg()) {
-            Log.d(TAG, "testStateMachineEnterExitTransitionToTest X");
+            tlog("testStateMachineEnterExitTransitionToTest X");
         }
     }
 
@@ -495,7 +513,7 @@
 
         StateMachine0 sm0 = new StateMachine0("sm0");
         sm0.start();
-        if (sm0.isDbg()) Log.d(TAG, "testStateMachine0 E");
+        if (sm0.isDbg()) tlog("testStateMachine0 E");
 
         synchronized (sm0) {
             // Send 6 messages
@@ -507,13 +525,15 @@
                 // wait for the messages to be handled
                 sm0.wait();
             } catch (InterruptedException e) {
-                Log.e(TAG, "testStateMachine0: exception while waiting " + e.getMessage());
+                tloge("testStateMachine0: exception while waiting " + e.getMessage());
             }
         }
 
         assertEquals(6, sm0.getLogRecCount());
         assertEquals(3, sm0.getLogRecSize());
 
+        dumpLogRecs(sm0);
+
         LogRec lr;
         lr = sm0.getLogRec(0);
         assertEquals(TEST_CMD_4, lr.getWhat());
@@ -530,7 +550,7 @@
         assertEquals(sm0.mS1, lr.getState());
         assertEquals(sm0.mS1, lr.getOriginalState());
 
-        if (sm0.isDbg()) Log.d(TAG, "testStateMachine0 X");
+        if (sm0.isDbg()) tlog("testStateMachine0 X");
     }
 
     /**
@@ -550,7 +570,7 @@
 
             // Set the initial state
             setInitialState(mS1);
-            if (DBG) Log.d(TAG, "StateMachine1: ctor X");
+            if (DBG) log("StateMachine1: ctor X");
         }
 
         class S1 extends State {
@@ -595,7 +615,7 @@
     public void testStateMachine1() throws Exception {
         StateMachine1 sm1 = new StateMachine1("sm1");
         sm1.start();
-        if (sm1.isDbg()) Log.d(TAG, "testStateMachine1 E");
+        if (sm1.isDbg()) tlog("testStateMachine1 E");
 
         synchronized (sm1) {
             // Send two messages
@@ -606,7 +626,7 @@
                 // wait for the messages to be handled
                 sm1.wait();
             } catch (InterruptedException e) {
-                Log.e(TAG, "testStateMachine1: exception while waiting " + e.getMessage());
+                tloge("testStateMachine1: exception while waiting " + e.getMessage());
             }
         }
 
@@ -629,7 +649,7 @@
         assertEquals(2, sm1.mEnterCount);
         assertEquals(2, sm1.mExitCount);
 
-        if (sm1.isDbg()) Log.d(TAG, "testStateMachine1 X");
+        if (sm1.isDbg()) tlog("testStateMachine1 X");
     }
 
     /**
@@ -651,7 +671,7 @@
 
             // Set the initial state
             setInitialState(mS1);
-            if (DBG) Log.d(TAG, "StateMachine2: ctor X");
+            if (DBG) log("StateMachine2: ctor X");
         }
 
         class S1 extends State {
@@ -702,7 +722,7 @@
     public void testStateMachine2() throws Exception {
         StateMachine2 sm2 = new StateMachine2("sm2");
         sm2.start();
-        if (sm2.isDbg()) Log.d(TAG, "testStateMachine2 E");
+        if (sm2.isDbg()) tlog("testStateMachine2 E");
 
         synchronized (sm2) {
             // Send two messages
@@ -713,7 +733,7 @@
                 // wait for the messages to be handled
                 sm2.wait();
             } catch (InterruptedException e) {
-                Log.e(TAG, "testStateMachine2: exception while waiting " + e.getMessage());
+                tloge("testStateMachine2: exception while waiting " + e.getMessage());
             }
         }
 
@@ -739,7 +759,7 @@
         assertTrue(sm2.mDidEnter);
         assertTrue(sm2.mDidExit);
 
-        if (sm2.isDbg()) Log.d(TAG, "testStateMachine2 X");
+        if (sm2.isDbg()) tlog("testStateMachine2 X");
     }
 
     /**
@@ -760,7 +780,7 @@
 
             // Set the initial state will be the child
             setInitialState(mChildState);
-            if (DBG) Log.d(TAG, "StateMachine3: ctor X");
+            if (DBG) log("StateMachine3: ctor X");
         }
 
         class ParentState extends State {
@@ -796,7 +816,7 @@
     public void testStateMachine3() throws Exception {
         StateMachine3 sm3 = new StateMachine3("sm3");
         sm3.start();
-        if (sm3.isDbg()) Log.d(TAG, "testStateMachine3 E");
+        if (sm3.isDbg()) tlog("testStateMachine3 E");
 
         synchronized (sm3) {
             // Send two messages
@@ -807,7 +827,7 @@
                 // wait for the messages to be handled
                 sm3.wait();
             } catch (InterruptedException e) {
-                Log.e(TAG, "testStateMachine3: exception while waiting " + e.getMessage());
+                tloge("testStateMachine3: exception while waiting " + e.getMessage());
             }
         }
 
@@ -824,7 +844,7 @@
         assertEquals(sm3.mParentState, lr.getState());
         assertEquals(sm3.mChildState, lr.getOriginalState());
 
-        if (sm3.isDbg()) Log.d(TAG, "testStateMachine3 X");
+        if (sm3.isDbg()) tlog("testStateMachine3 X");
     }
 
     /**
@@ -847,7 +867,7 @@
 
             // Set the initial state will be child 1
             setInitialState(mChildState1);
-            if (DBG) Log.d(TAG, "StateMachine4: ctor X");
+            if (DBG) log("StateMachine4: ctor X");
         }
 
         class ParentState extends State {
@@ -892,7 +912,7 @@
     public void testStateMachine4() throws Exception {
         StateMachine4 sm4 = new StateMachine4("sm4");
         sm4.start();
-        if (sm4.isDbg()) Log.d(TAG, "testStateMachine4 E");
+        if (sm4.isDbg()) tlog("testStateMachine4 E");
 
         synchronized (sm4) {
             // Send two messages
@@ -903,7 +923,7 @@
                 // wait for the messages to be handled
                 sm4.wait();
             } catch (InterruptedException e) {
-                Log.e(TAG, "testStateMachine4: exception while waiting " + e.getMessage());
+                tloge("testStateMachine4: exception while waiting " + e.getMessage());
             }
         }
 
@@ -921,7 +941,7 @@
         assertEquals(sm4.mParentState, lr.getState());
         assertEquals(sm4.mChildState2, lr.getOriginalState());
 
-        if (sm4.isDbg()) Log.d(TAG, "testStateMachine4 X");
+        if (sm4.isDbg()) tlog("testStateMachine4 X");
     }
 
     /**
@@ -947,7 +967,7 @@
 
             // Set the initial state will be the child
             setInitialState(mChildState1);
-            if (DBG) Log.d(TAG, "StateMachine5: ctor X");
+            if (DBG) log("StateMachine5: ctor X");
         }
 
         class ParentState1 extends State {
@@ -1187,7 +1207,7 @@
     public void testStateMachine5() throws Exception {
         StateMachine5 sm5 = new StateMachine5("sm5");
         sm5.start();
-        if (sm5.isDbg()) Log.d(TAG, "testStateMachine5 E");
+        if (sm5.isDbg()) tlog("testStateMachine5 E");
 
         synchronized (sm5) {
             // Send 6 messages
@@ -1202,7 +1222,7 @@
                 // wait for the messages to be handled
                 sm5.wait();
             } catch (InterruptedException e) {
-                Log.e(TAG, "testStateMachine5: exception while waiting " + e.getMessage());
+                tloge("testStateMachine5: exception while waiting " + e.getMessage());
             }
         }
 
@@ -1255,7 +1275,7 @@
         assertEquals(sm5.mParentState2, lr.getState());
         assertEquals(sm5.mParentState2, lr.getOriginalState());
 
-        if (sm5.isDbg()) Log.d(TAG, "testStateMachine5 X");
+        if (sm5.isDbg()) tlog("testStateMachine5 X");
     }
 
     /**
@@ -1274,7 +1294,7 @@
 
             // Set the initial state
             setInitialState(mS1);
-            if (DBG) Log.d(TAG, "StateMachine6: ctor X");
+            if (DBG) log("StateMachine6: ctor X");
         }
 
         class S1 extends State {
@@ -1315,7 +1335,7 @@
 
         StateMachine6 sm6 = new StateMachine6("sm6");
         sm6.start();
-        if (sm6.isDbg()) Log.d(TAG, "testStateMachine6 E");
+        if (sm6.isDbg()) tlog("testStateMachine6 E");
 
         synchronized (sm6) {
             // Send a message
@@ -1325,7 +1345,7 @@
                 // wait for the messages to be handled
                 sm6.wait();
             } catch (InterruptedException e) {
-                Log.e(TAG, "testStateMachine6: exception while waiting " + e.getMessage());
+                tloge("testStateMachine6: exception while waiting " + e.getMessage());
             }
         }
 
@@ -1336,11 +1356,11 @@
          */
         long arrivalTimeDiff = sm6.mArrivalTimeMsg2 - sm6.mArrivalTimeMsg1;
         long expectedDelay = DELAY_TIME - DELAY_FUDGE;
-        if (sm6.isDbg()) Log.d(TAG, "testStateMachine6: expect " + arrivalTimeDiff
+        if (sm6.isDbg()) tlog("testStateMachine6: expect " + arrivalTimeDiff
                                     + " >= " + expectedDelay);
         assertTrue(arrivalTimeDiff >= expectedDelay);
 
-        if (sm6.isDbg()) Log.d(TAG, "testStateMachine6 X");
+        if (sm6.isDbg()) tlog("testStateMachine6 X");
     }
 
     /**
@@ -1361,7 +1381,7 @@
 
             // Set the initial state
             setInitialState(mS1);
-            if (DBG) Log.d(TAG, "StateMachine7: ctor X");
+            if (DBG) log("StateMachine7: ctor X");
         }
 
         class S1 extends State {
@@ -1421,7 +1441,7 @@
 
         StateMachine7 sm7 = new StateMachine7("sm7");
         sm7.start();
-        if (sm7.isDbg()) Log.d(TAG, "testStateMachine7 E");
+        if (sm7.isDbg()) tlog("testStateMachine7 E");
 
         synchronized (sm7) {
             // Send a message
@@ -1431,7 +1451,7 @@
                 // wait for the messages to be handled
                 sm7.wait();
             } catch (InterruptedException e) {
-                Log.e(TAG, "testStateMachine7: exception while waiting " + e.getMessage());
+                tloge("testStateMachine7: exception while waiting " + e.getMessage());
             }
         }
 
@@ -1442,11 +1462,11 @@
          */
         long arrivalTimeDiff = sm7.mArrivalTimeMsg3 - sm7.mArrivalTimeMsg2;
         long expectedDelay = sm7.SM7_DELAY_TIME - SM7_DELAY_FUDGE;
-        if (sm7.isDbg()) Log.d(TAG, "testStateMachine7: expect " + arrivalTimeDiff
+        if (sm7.isDbg()) tlog("testStateMachine7: expect " + arrivalTimeDiff
                                     + " >= " + expectedDelay);
         assertTrue(arrivalTimeDiff >= expectedDelay);
 
-        if (sm7.isDbg()) Log.d(TAG, "testStateMachine7 X");
+        if (sm7.isDbg()) tlog("testStateMachine7 X");
     }
 
     /**
@@ -1494,9 +1514,9 @@
     @SmallTest
     public void testStateMachineUnhandledMessage() throws Exception {
 
-        StateMachineUnhandledMessage sm = new StateMachineUnhandledMessage("sm");
+        StateMachineUnhandledMessage sm = new StateMachineUnhandledMessage("smUnhandledMessage");
         sm.start();
-        if (sm.isDbg()) Log.d(TAG, "testStateMachineUnhandledMessage E");
+        if (sm.isDbg()) tlog("testStateMachineUnhandledMessage E");
 
         synchronized (sm) {
             // Send 2 messages
@@ -1508,15 +1528,15 @@
                 // wait for the messages to be handled
                 sm.wait();
             } catch (InterruptedException e) {
-                Log.e(TAG, "testStateMachineUnhandledMessage: exception while waiting "
+                tloge("testStateMachineUnhandledMessage: exception while waiting "
                         + e.getMessage());
             }
         }
 
-        assertEquals(sm.getLogRecCount(), 2);
+        assertEquals(2, sm.getLogRecSize());
         assertEquals(2, sm.mUnhandledMessageCount);
 
-        if (sm.isDbg()) Log.d(TAG, "testStateMachineUnhandledMessage X");
+        if (sm.isDbg()) tlog("testStateMachineUnhandledMessage X");
     }
 
     /**
@@ -1569,7 +1589,7 @@
 
     @MediumTest
     public void testStateMachineSharedThread() throws Exception {
-        if (DBG) Log.d(TAG, "testStateMachineSharedThread E");
+        if (DBG) tlog("testStateMachineSharedThread E");
 
         // Create and start the handler thread
         HandlerThread smThread = new HandlerThread("testStateMachineSharedThread");
@@ -1578,7 +1598,8 @@
         // Create the state machines
         StateMachineSharedThread sms[] = new StateMachineSharedThread[10];
         for (int i = 0; i < sms.length; i++) {
-            sms[i] = new StateMachineSharedThread("sm", smThread.getLooper(), sms.length);
+            sms[i] = new StateMachineSharedThread("smSharedThread",
+                        smThread.getLooper(), sms.length);
             sms[i].start();
         }
 
@@ -1594,14 +1615,14 @@
             try {
                 waitObject.wait();
             } catch (InterruptedException e) {
-                Log.e(TAG, "testStateMachineSharedThread: exception while waiting "
+                tloge("testStateMachineSharedThread: exception while waiting "
                         + e.getMessage());
             }
         }
 
         for (StateMachineSharedThread sm : sms) {
-            assertEquals(sm.getLogRecCount(), 4);
-            for (int i = 0; i < sm.getLogRecCount(); i++) {
+            assertEquals(4, sm.getLogRecCount());
+            for (int i = 0; i < sm.getLogRecSize(); i++) {
                 LogRec lr = sm.getLogRec(i);
                 assertEquals(i+1, lr.getWhat());
                 assertEquals(sm.mS1, lr.getState());
@@ -1609,12 +1630,168 @@
             }
         }
 
-        if (DBG) Log.d(TAG, "testStateMachineSharedThread X");
+        if (DBG) tlog("testStateMachineSharedThread X");
+    }
+
+    static class Hsm1 extends StateMachine {
+        private static final String HSM1_TAG = "hsm1";
+
+        public static final int CMD_1 = 1;
+        public static final int CMD_2 = 2;
+        public static final int CMD_3 = 3;
+        public static final int CMD_4 = 4;
+        public static final int CMD_5 = 5;
+
+        public static Hsm1 makeHsm1() {
+            Log.d(HSM1_TAG, "makeHsm1 E");
+            Hsm1 sm = new Hsm1(HSM1_TAG);
+            sm.start();
+            Log.d(HSM1_TAG, "makeHsm1 X");
+            return sm;
+        }
+
+        Hsm1(String name) {
+            super(name);
+            log("ctor E");
+
+            // Add states, use indentation to show hierarchy
+            addState(mP1);
+                addState(mS1, mP1);
+                addState(mS2, mP1);
+            addState(mP2);
+
+            // Set the initial state
+            setInitialState(mS1);
+            log("ctor X");
+        }
+
+        class P1 extends State {
+            @Override
+            public void enter() {
+                log("P1.enter");
+            }
+            @Override
+            public void exit() {
+                log("P1.exit");
+            }
+            @Override
+            public boolean processMessage(Message message) {
+                boolean retVal;
+                log("P1.processMessage what=" + message.what);
+                switch(message.what) {
+                case CMD_2:
+                    // CMD_2 will arrive in mS2 before CMD_3
+                    sendMessage(CMD_3);
+                    deferMessage(message);
+                    transitionTo(mS2);
+                    retVal = true;
+                    break;
+                default:
+                    // Any message we don't understand in this state invokes unhandledMessage
+                    retVal = false;
+                    break;
+                }
+                return retVal;
+            }
+        }
+
+        class S1 extends State {
+            @Override
+            public void enter() {
+                log("S1.enter");
+            }
+            @Override
+            public void exit() {
+                log("S1.exit");
+            }
+            @Override
+            public boolean processMessage(Message message) {
+                log("S1.processMessage what=" + message.what);
+                if (message.what == CMD_1) {
+                    // Transition to ourself to show that enter/exit is called
+                    transitionTo(mS1);
+                    return HANDLED;
+                } else {
+                    // Let parent process all other messages
+                    return NOT_HANDLED;
+                }
+            }
+        }
+
+        class S2 extends State {
+            @Override
+            public void enter() {
+                log("S2.enter");
+            }
+            @Override
+            public void exit() {
+                log("S2.exit");
+            }
+            @Override
+            public boolean processMessage(Message message) {
+                boolean retVal;
+                log("S2.processMessage what=" + message.what);
+                switch(message.what) {
+                case(CMD_2):
+                    sendMessage(CMD_4);
+                    retVal = true;
+                    break;
+                case(CMD_3):
+                    deferMessage(message);
+                    transitionTo(mP2);
+                    retVal = true;
+                    break;
+                default:
+                    retVal = false;
+                    break;
+                }
+                return retVal;
+            }
+        }
+
+        class P2 extends State {
+            @Override
+            public void enter() {
+                log("P2.enter");
+                sendMessage(CMD_5);
+            }
+            @Override
+            public void exit() {
+                log("P2.exit");
+            }
+            @Override
+            public boolean processMessage(Message message) {
+                log("P2.processMessage what=" + message.what);
+                switch(message.what) {
+                case(CMD_3):
+                    break;
+                case(CMD_4):
+                    break;
+                case(CMD_5):
+                    transitionToHaltingState();
+                    break;
+                }
+                return HANDLED;
+            }
+        }
+
+        @Override
+        protected void onHalting() {
+            log("halting");
+            synchronized (this) {
+                this.notifyAll();
+            }
+        }
+
+        P1 mP1 = new P1();
+        S1 mS1 = new S1();
+        S2 mS2 = new S2();
+        P2 mP2 = new P2();
     }
 
     @MediumTest
     public void testHsm1() throws Exception {
-        if (DBG) Log.d(TAG, "testHsm1 E");
+        if (DBG) tlog("testHsm1 E");
 
         Hsm1 sm = Hsm1.makeHsm1();
 
@@ -1627,11 +1804,14 @@
             try {
                 sm.wait();
             } catch (InterruptedException e) {
-                Log.e(TAG, "testHsm1: exception while waiting " + e.getMessage());
+                tloge("testHsm1: exception while waiting " + e.getMessage());
             }
         }
 
+        dumpLogRecs(sm);
+
         assertEquals(7, sm.getLogRecCount());
+
         LogRec lr = sm.getLogRec(0);
         assertEquals(Hsm1.CMD_1, lr.getWhat());
         assertEquals(sm.mS1, lr.getState());
@@ -1667,162 +1847,14 @@
         assertEquals(sm.mP2, lr.getState());
         assertEquals(sm.mP2, lr.getOriginalState());
 
-        if (DBG) Log.d(TAG, "testStateMachineSharedThread X");
-    }
-}
-
-class Hsm1 extends StateMachine {
-    private static final String TAG = "hsm1";
-
-    public static final int CMD_1 = 1;
-    public static final int CMD_2 = 2;
-    public static final int CMD_3 = 3;
-    public static final int CMD_4 = 4;
-    public static final int CMD_5 = 5;
-
-    public static Hsm1 makeHsm1() {
-        Log.d(TAG, "makeHsm1 E");
-        Hsm1 sm = new Hsm1("hsm1");
-        sm.start();
-        Log.d(TAG, "makeHsm1 X");
-        return sm;
+        if (DBG) tlog("testStateMachineSharedThread X");
     }
 
-    Hsm1(String name) {
-        super(name);
-        Log.d(TAG, "ctor E");
-
-        // Add states, use indentation to show hierarchy
-        addState(mP1);
-            addState(mS1, mP1);
-            addState(mS2, mP1);
-        addState(mP2);
-
-        // Set the initial state
-        setInitialState(mS1);
-        Log.d(TAG, "ctor X");
+    private void tlog(String s) {
+        Log.d(TAG, s);
     }
 
-    class P1 extends State {
-        @Override
-        public void enter() {
-            Log.d(TAG, "P1.enter");
-        }
-        @Override
-        public void exit() {
-            Log.d(TAG, "P1.exit");
-        }
-        @Override
-        public boolean processMessage(Message message) {
-            boolean retVal;
-            Log.d(TAG, "P1.processMessage what=" + message.what);
-            switch(message.what) {
-            case CMD_2:
-                // CMD_2 will arrive in mS2 before CMD_3
-                sendMessage(CMD_3);
-                deferMessage(message);
-                transitionTo(mS2);
-                retVal = true;
-                break;
-            default:
-                // Any message we don't understand in this state invokes unhandledMessage
-                retVal = false;
-                break;
-            }
-            return retVal;
-        }
+    private void tloge(String s) {
+        Log.e(TAG, s);
     }
-
-    class S1 extends State {
-        @Override
-        public void enter() {
-            Log.d(TAG, "S1.enter");
-        }
-        @Override
-        public void exit() {
-            Log.d(TAG, "S1.exit");
-        }
-        @Override
-        public boolean processMessage(Message message) {
-            Log.d(TAG, "S1.processMessage what=" + message.what);
-            if (message.what == CMD_1) {
-                // Transition to ourself to show that enter/exit is called
-                transitionTo(mS1);
-                return HANDLED;
-            } else {
-                // Let parent process all other messages
-                return NOT_HANDLED;
-            }
-        }
-    }
-
-    class S2 extends State {
-        @Override
-        public void enter() {
-            Log.d(TAG, "S2.enter");
-        }
-        @Override
-        public void exit() {
-            Log.d(TAG, "S2.exit");
-        }
-        @Override
-        public boolean processMessage(Message message) {
-            boolean retVal;
-            Log.d(TAG, "S2.processMessage what=" + message.what);
-            switch(message.what) {
-            case(CMD_2):
-                sendMessage(CMD_4);
-                retVal = true;
-                break;
-            case(CMD_3):
-                deferMessage(message);
-                transitionTo(mP2);
-                retVal = true;
-                break;
-            default:
-                retVal = false;
-                break;
-            }
-            return retVal;
-        }
-    }
-
-    class P2 extends State {
-        @Override
-        public void enter() {
-            Log.d(TAG, "P2.enter");
-            sendMessage(CMD_5);
-        }
-        @Override
-        public void exit() {
-            Log.d(TAG, "P2.exit");
-        }
-        @Override
-        public boolean processMessage(Message message) {
-            Log.d(TAG, "P2.processMessage what=" + message.what);
-            switch(message.what) {
-            case(CMD_3):
-                break;
-            case(CMD_4):
-                break;
-            case(CMD_5):
-                transitionToHaltingState();
-                break;
-            }
-            return HANDLED;
-        }
-    }
-
-    @Override
-    protected void onHalting() {
-        Log.d(TAG, "halting");
-        synchronized (this) {
-            this.notifyAll();
-        }
-    }
-
-    P1 mP1 = new P1();
-    S1 mS1 = new S1();
-    S2 mS2 = new S2();
-    P2 mP2 = new P2();
 }
diff --git a/core/tests/inputmethodtests/Android.mk b/core/tests/inputmethodtests/Android.mk
new file mode 100644
index 0000000..4631e65
--- /dev/null
+++ b/core/tests/inputmethodtests/Android.mk
@@ -0,0 +1,18 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+# We only want this apk build for tests.
+LOCAL_MODULE_TAGS := tests
+
+# Include all test java files.
+LOCAL_SRC_FILES := \
+	$(call all-java-files-under, src)
+
+LOCAL_DX_FLAGS := --core-library
+LOCAL_STATIC_JAVA_LIBRARIES := core-tests android-common frameworks-core-util-lib
+LOCAL_JAVA_LIBRARIES := android.test.runner
+LOCAL_PACKAGE_NAME := FrameworksCoreInputMethodTests
+
+LOCAL_CERTIFICATE := platform
+
+include $(BUILD_PACKAGE)
diff --git a/core/tests/inputmethodtests/AndroidManifest.xml b/core/tests/inputmethodtests/AndroidManifest.xml
new file mode 100644
index 0000000..7f0b1aa
--- /dev/null
+++ b/core/tests/inputmethodtests/AndroidManifest.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2013 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+          android:installLocation="internalOnly"
+          package="com.android.frameworks.coretests.inputmethod"
+          android:sharedUserId="android.uid.system">
+
+    <application>
+        <uses-library android:name="android.test.runner" />
+    </application>
+
+    <instrumentation android:name="android.test.InstrumentationTestRunner"
+            android:targetPackage="com.android.frameworks.coretests.inputmethod"
+            android:label="Frameworks InputMethod Core Tests" />
+
+</manifest>
diff --git a/core/tests/inputmethodtests/run_core_inputmethod_test.sh b/core/tests/inputmethodtests/run_core_inputmethod_test.sh
new file mode 100755
index 0000000..5e123ec
--- /dev/null
+++ b/core/tests/inputmethodtests/run_core_inputmethod_test.sh
@@ -0,0 +1,24 @@
+#!/bin/bash
+
+while [[ $# -gt 0 ]]; do
+  case "$1" in
+  --rebuild ) echo Rebuild && rebuild=true;;
+  * ) com_opts+=($1);;
+  esac
+  shift
+done
+
+if [[ -z $ANDROID_PRODUCT_OUT && $rebuilld == true ]]; then
+  echo You must lunch before running this test.
+  exit 0
+fi
+
+if [[ $rebuild == true ]]; then
+  make -j4 FrameworksCoreInputMethodTests
+  TESTAPP=${ANDROID_PRODUCT_OUT}/data/app/FrameworksCoreInputMethodTests.apk
+  COMMAND="adb install -r $TESTAPP"
+  echo $COMMAND
+  $COMMAND
+fi
+
+adb shell am instrument -w -e class android.os.InputMethodTest com.android.frameworks.coretests.inputmethod/android.test.InstrumentationTestRunner
diff --git a/core/tests/inputmethodtests/src/android/os/InputMethodTest.java b/core/tests/inputmethodtests/src/android/os/InputMethodTest.java
new file mode 100644
index 0000000..0a2b50c
--- /dev/null
+++ b/core/tests/inputmethodtests/src/android/os/InputMethodTest.java
@@ -0,0 +1,158 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.os;
+
+import com.android.internal.inputmethod.InputMethodUtils;
+
+import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.ResolveInfo;
+import android.content.pm.ServiceInfo;
+import android.test.InstrumentationTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.view.inputmethod.InputMethodInfo;
+import android.view.inputmethod.InputMethodSubtype;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class InputMethodTest extends InstrumentationTestCase {
+    private static final boolean IS_AUX = true;
+    private static final boolean IS_DEFAULT = true;
+    private static final boolean IS_AUTO = true;
+
+    @SmallTest
+    public void testDefaultEnabledImesWithDefaultVoiceIme() throws Exception {
+        final Context context = getInstrumentation().getTargetContext();
+        final ArrayList<InputMethodInfo> imis = new ArrayList<InputMethodInfo>();
+        imis.add(createDefaultAutoDummyVoiceIme());
+        imis.add(createNonDefaultAutoDummyVoiceIme0());
+        imis.add(createNonDefaultAutoDummyVoiceIme1());
+        imis.add(createNonDefaultDummyVoiceIme2());
+        imis.add(createDefaultDummyEnUSKeyboardIme());
+        imis.add(createNonDefaultDummyJaJPKeyboardIme());
+        final ArrayList<InputMethodInfo> enabledImis = InputMethodUtils.getDefaultEnabledImes(
+                context, true, imis);
+        assertEquals(2, enabledImis.size());
+        for (int i = 0; i < enabledImis.size(); ++i) {
+            final InputMethodInfo imi = enabledImis.get(0);
+            // "DummyDefaultAutoVoiceIme" and "DummyDefaultEnKeyboardIme"
+            if (imi.getPackageName().equals("DummyDefaultAutoVoiceIme")
+                    || imi.getPackageName().equals("DummyDefaultEnKeyboardIme")) {
+                continue;
+            } else {
+                fail("Invalid enabled subtype.");
+            }
+        }
+    }
+
+    @SmallTest
+    public void testDefaultEnabledImesWithOutDefaultVoiceIme() throws Exception {
+        final Context context = getInstrumentation().getTargetContext();
+        final ArrayList<InputMethodInfo> imis = new ArrayList<InputMethodInfo>();
+        imis.add(createNonDefaultAutoDummyVoiceIme0());
+        imis.add(createNonDefaultAutoDummyVoiceIme1());
+        imis.add(createNonDefaultDummyVoiceIme2());
+        imis.add(createDefaultDummyEnUSKeyboardIme());
+        imis.add(createNonDefaultDummyJaJPKeyboardIme());
+        final ArrayList<InputMethodInfo> enabledImis = InputMethodUtils.getDefaultEnabledImes(
+                context, true, imis);
+        assertEquals(3, enabledImis.size());
+        for (int i = 0; i < enabledImis.size(); ++i) {
+            final InputMethodInfo imi = enabledImis.get(0);
+            // "DummyNonDefaultAutoVoiceIme0", "DummyNonDefaultAutoVoiceIme1" and
+            // "DummyDefaultEnKeyboardIme"
+            if (imi.getPackageName().equals("DummyNonDefaultAutoVoiceIme0")
+                    || imi.getPackageName().equals("DummyNonDefaultAutoVoiceIme1")
+                    || imi.getPackageName().equals("DummyDefaultEnKeyboardIme")) {
+                continue;
+            } else {
+                fail("Invalid enabled subtype.");
+            }
+        }
+    }
+
+    private static InputMethodInfo createDummyInputMethodInfo(String packageName, String name,
+            CharSequence label, boolean isAuxIme, boolean isDefault,
+            List<InputMethodSubtype> subtypes) {
+        final ResolveInfo ri = new ResolveInfo();
+        final ServiceInfo si = new ServiceInfo();
+        final ApplicationInfo ai = new ApplicationInfo();
+        ai.packageName = packageName;
+        ai.enabled = true;
+        ai.flags |= ApplicationInfo.FLAG_SYSTEM;
+        si.applicationInfo = ai;
+        si.enabled = true;
+        si.packageName = packageName;
+        si.name = name;
+        si.exported = true;
+        si.nonLocalizedLabel = label;
+        ri.serviceInfo = si;
+        return new InputMethodInfo(ri, isAuxIme, "", subtypes, 1, isDefault);
+    }
+
+    private static InputMethodSubtype createDummyInputMethodSubtype(String locale, String mode,
+            boolean isAuxiliary, boolean overridesImplicitlyEnabledSubtype) {
+        return new InputMethodSubtype(0, 0, locale, mode, "", isAuxiliary,
+                overridesImplicitlyEnabledSubtype);
+    }
+
+    private static InputMethodInfo createDefaultAutoDummyVoiceIme() {
+        final ArrayList<InputMethodSubtype> subtypes = new ArrayList<InputMethodSubtype>();
+        subtypes.add(createDummyInputMethodSubtype("auto", "voice", IS_AUX, IS_AUTO));
+        subtypes.add(createDummyInputMethodSubtype("en_US", "voice", IS_AUX, !IS_AUTO));
+        return createDummyInputMethodInfo("DummyDefaultAutoVoiceIme", "dummy.voice0",
+                "DummyVoice0", IS_AUX, IS_DEFAULT, subtypes);
+    }
+
+    private static InputMethodInfo createNonDefaultAutoDummyVoiceIme0() {
+        final ArrayList<InputMethodSubtype> subtypes = new ArrayList<InputMethodSubtype>();
+        subtypes.add(createDummyInputMethodSubtype("auto", "voice", IS_AUX, IS_AUTO));
+        subtypes.add(createDummyInputMethodSubtype("en_US", "voice", IS_AUX, !IS_AUTO));
+        return createDummyInputMethodInfo("DummyNonDefaultAutoVoiceIme0", "dummy.voice1",
+                "DummyVoice1", IS_AUX, !IS_DEFAULT, subtypes);
+    }
+
+    private static InputMethodInfo createNonDefaultAutoDummyVoiceIme1() {
+        final ArrayList<InputMethodSubtype> subtypes = new ArrayList<InputMethodSubtype>();
+        subtypes.add(createDummyInputMethodSubtype("auto", "voice", IS_AUX, IS_AUTO));
+        subtypes.add(createDummyInputMethodSubtype("en_US", "voice", IS_AUX, !IS_AUTO));
+        return createDummyInputMethodInfo("DummyNonDefaultAutoVoiceIme1", "dummy.voice2",
+                "DummyVoice2", IS_AUX, !IS_DEFAULT, subtypes);
+    }
+
+    private static InputMethodInfo createNonDefaultDummyVoiceIme2() {
+        final ArrayList<InputMethodSubtype> subtypes = new ArrayList<InputMethodSubtype>();
+        subtypes.add(createDummyInputMethodSubtype("en_US", "voice", IS_AUX, !IS_AUTO));
+        return createDummyInputMethodInfo("DummyNonDefaultVoiceIme2", "dummy.voice3",
+                "DummyVoice3", IS_AUX, !IS_DEFAULT, subtypes);
+    }
+
+    private static InputMethodInfo createDefaultDummyEnUSKeyboardIme() {
+        final ArrayList<InputMethodSubtype> subtypes = new ArrayList<InputMethodSubtype>();
+        subtypes.add(createDummyInputMethodSubtype("en_US", "keyboard", !IS_AUX, !IS_AUTO));
+        return createDummyInputMethodInfo("DummyDefaultEnKeyboardIme", "dummy.keyboard0",
+                "DummyKeyboard0", !IS_AUX, IS_DEFAULT, subtypes);
+    }
+
+    private static InputMethodInfo createNonDefaultDummyJaJPKeyboardIme() {
+        final ArrayList<InputMethodSubtype> subtypes = new ArrayList<InputMethodSubtype>();
+        subtypes.add(createDummyInputMethodSubtype("ja_JP", "keyboard", !IS_AUX, !IS_AUTO));
+        return createDummyInputMethodInfo("DummyNonDefaultJaJPKeyboardIme", "dummy.keyboard1",
+                "DummyKeyboard1", !IS_AUX, !IS_DEFAULT, subtypes);
+    }
+}
diff --git a/data/etc/platform.xml b/data/etc/platform.xml
index 83ecdd9..cf04b5c 100644
--- a/data/etc/platform.xml
+++ b/data/etc/platform.xml
@@ -106,6 +106,10 @@
         <group gid="net_bw_acct" />
     </permission>
 
+    <permission name="android.permission.LOOP_RADIO" >
+        <group gid="loop_radio" />
+    </permission>
+
     <!-- ================================================================== -->
     <!-- ================================================================== -->
     <!-- ================================================================== -->
diff --git a/graphics/java/android/renderscript/Matrix3f.java b/graphics/java/android/renderscript/Matrix3f.java
index 0bad7e0..5e9a7ca 100644
--- a/graphics/java/android/renderscript/Matrix3f.java
+++ b/graphics/java/android/renderscript/Matrix3f.java
@@ -140,7 +140,7 @@
         mMat[4] = y*y*nc +  c;
         mMat[7] =  yz*nc - xs;
         mMat[2] =  zx*nc - ys;
-        mMat[6] =  yz*nc + xs;
+        mMat[5] =  yz*nc + xs;
         mMat[8] = z*z*nc +  c;
     }
 
diff --git a/libs/hwui/DisplayListLogBuffer.cpp b/libs/hwui/DisplayListLogBuffer.cpp
index f204644..f039fcd 100644
--- a/libs/hwui/DisplayListLogBuffer.cpp
+++ b/libs/hwui/DisplayListLogBuffer.cpp
@@ -18,9 +18,8 @@
 
 // BUFFER_SIZE size must be one more than a multiple of COMMAND_SIZE to ensure
 // that mStart always points at the next command, not just the next item
-#define COMMAND_SIZE 2
 #define NUM_COMMANDS 50
-#define BUFFER_SIZE ((NUM_COMMANDS * COMMAND_SIZE) + 1)
+#define BUFFER_SIZE ((NUM_COMMANDS) + 1)
 
 /**
  * DisplayListLogBuffer is a utility class which logs the most recent display
@@ -57,7 +56,7 @@
 
 
 DisplayListLogBuffer::DisplayListLogBuffer() {
-    mBufferFirst = (int*) malloc(BUFFER_SIZE * sizeof(int));
+    mBufferFirst = (OpLog*) malloc(BUFFER_SIZE * sizeof(OpLog));
     mStart = mBufferFirst;
     mBufferLast = mBufferFirst + BUFFER_SIZE - 1;
     mEnd = mStart;
@@ -71,42 +70,30 @@
  * Called from DisplayListRenderer to output the current buffer into the
  * specified FILE. This only happens in a dumpsys/bugreport operation.
  */
-void DisplayListLogBuffer::outputCommands(FILE *file, const char* opNames[])
+void DisplayListLogBuffer::outputCommands(FILE *file)
 {
-    int *tmpBufferPtr = mStart;
+    OpLog* tmpBufferPtr = mStart;
     while (true) {
         if (tmpBufferPtr == mEnd) {
             break;
         }
-        int level = *tmpBufferPtr++;
+        OpLog* nextOp = tmpBufferPtr++;
         if (tmpBufferPtr > mBufferLast) {
             tmpBufferPtr = mBufferFirst;
         }
-        int op = *tmpBufferPtr++;
-        if (tmpBufferPtr > mBufferLast) {
-            tmpBufferPtr = mBufferFirst;
-        }
-        uint32_t count = (level + 1) * 2;
-        char indent[count + 1];
-        for (uint32_t i = 0; i < count; i++) {
-            indent[i] = ' ';
-        }
-        indent[count] = '\0';
-        fprintf(file, "%s%s\n", indent, opNames[op]);
+
+        fprintf(file, "%*s%s\n", tmpBufferPtr->level*2, "", tmpBufferPtr->label);
     }
 }
 
-void DisplayListLogBuffer::writeCommand(int level, int op) {
-    writeInt(level);
-    writeInt(op);
-}
-
 /**
- * Store the given value in the buffer and increment/wrap the mEnd
- * and mStart values as appropriate.
+ * Store the given level and label in the buffer and increment/wrap the mEnd
+ * and mStart values as appropriate. Label should point to static memory.
  */
-void DisplayListLogBuffer::writeInt(int value) {
-    *((int*)mEnd) = value;
+void DisplayListLogBuffer::writeCommand(int level, const char* label) {
+    mEnd->level = level;
+    mEnd->label = label;
+
     if (mEnd == mBufferLast) {
         mEnd = mBufferFirst;
     } else {
diff --git a/libs/hwui/DisplayListLogBuffer.h b/libs/hwui/DisplayListLogBuffer.h
index 5d689bb..c884789 100644
--- a/libs/hwui/DisplayListLogBuffer.h
+++ b/libs/hwui/DisplayListLogBuffer.h
@@ -31,19 +31,23 @@
     friend class Singleton<DisplayListLogBuffer>;
 
 public:
-    void writeCommand(int level, int op);
-    void writeInt(int value);
-    void outputCommands(FILE *file, const char* opNames[]);
+    void writeCommand(int level, const char* label);
+    void outputCommands(FILE *file);
 
     bool isEmpty() {
         return (mStart == mEnd);
     }
 
+    struct OpLog {
+        int level;
+        const char* label;
+    };
+
 private:
-    int *mBufferFirst; // where the memory starts
-    int* mStart;       // where the current command stream starts
-    int* mEnd;         // where the current commands end
-    int* mBufferLast;  // where the buffer memory ends
+    OpLog* mBufferFirst; // where the memory starts
+    OpLog* mStart;       // where the current command stream starts
+    OpLog* mEnd;         // where the current commands end
+    OpLog* mBufferLast;  // where the buffer memory ends
 
 };
 
diff --git a/libs/hwui/DisplayListOp.h b/libs/hwui/DisplayListOp.h
new file mode 100644
index 0000000..a4de56d
--- /dev/null
+++ b/libs/hwui/DisplayListOp.h
@@ -0,0 +1,1138 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HWUI_DISPLAY_OPERATION_H
+#define ANDROID_HWUI_DISPLAY_OPERATION_H
+
+#include <SkXfermode.h>
+
+#include "OpenGLRenderer.h"
+#include "DisplayListRenderer.h"
+#include "utils/LinearAllocator.h"
+
+#define CRASH() do { \
+    *(int *)(uintptr_t)0xbbadbeef = 0; \
+    ((void(*)())0)(); /* More reliable, but doesn't say BBADBEEF */ \
+} while(false)
+
+#define MATRIX_STRING "[%.2f %.2f %.2f] [%.2f %.2f %.2f] [%.2f %.2f %.2f]"
+#define MATRIX_ARGS(m) \
+    m->get(0), m->get(1), m->get(2), \
+    m->get(3), m->get(4), m->get(5), \
+    m->get(6), m->get(7), m->get(8)
+#define RECT_STRING "%.2f %.2f %.2f %.2f"
+#define RECT_ARGS(r) \
+    r.left, r.top, r.right, r.bottom
+
+// Use OP_LOG for logging with arglist, OP_LOGS if just printing char*
+#define OP_LOGS(s) OP_LOG("%s", s)
+#define OP_LOG(s, ...) ALOGD( "%*s--%p " s, level * 2, "", this, __VA_ARGS__ )
+
+
+namespace android {
+namespace uirenderer {
+
+/**
+ * Structure for storing canvas operations when they are recorded into a DisplayList, so that they
+ * may be replayed to an OpenGLRenderer.
+ *
+ * To avoid individual memory allocations, DisplayListOps may only be allocated into a
+ * LinearAllocator's managed memory buffers.  Each pointer held by a DisplayListOp is either a
+ * pointer into memory also allocated in the LinearAllocator (mostly for text and float buffers) or
+ * references a externally refcounted object (Sk... and Skia... objects). ~DisplayListOp() is
+ * never called as LinearAllocators are simply discarded, so no memory management should be done in
+ * this class.
+ */
+class DisplayListOp {
+public:
+    // These objects should always be allocated with a LinearAllocator, and never destroyed/deleted.
+    // standard new() intentionally not implemented, and delete/deconstructor should never be used.
+    virtual ~DisplayListOp() { CRASH(); }
+    static void operator delete(void* ptr) { CRASH(); }
+    /** static void* operator new(size_t size); PURPOSELY OMITTED **/
+    static void* operator new(size_t size, LinearAllocator& allocator) {
+        return allocator.alloc(size);
+    }
+
+    enum OpLogFlag {
+        kOpLogFlag_Recurse = 0x1,
+        kOpLogFlag_JSON = 0x2 // TODO: add?
+    };
+
+    //TODO: for draw batching, DrawOps should override a virtual sub-method, with
+    // DrawOps::apply deferring operations to a different list if possible
+    virtual status_t replay(OpenGLRenderer& renderer, Rect& dirty, int32_t flags, int saveCount,
+            uint32_t level, bool caching, int multipliedAlpha) = 0;
+
+    virtual void output(int level, uint32_t flags = 0) = 0;
+
+    // NOTE: it would be nice to declare constants and overriding the implementation in each op to
+    // point at the constants, but that seems to require a .cpp file
+    virtual const char* name() = 0;
+};
+
+class StateOp : public DisplayListOp {
+public:
+    StateOp() {};
+
+    virtual ~StateOp() {}
+
+    virtual status_t replay(OpenGLRenderer& renderer, Rect& dirty, int32_t flags, int saveCount,
+            uint32_t level, bool caching, int multipliedAlpha) {
+        applyState(renderer, saveCount);
+        return DrawGlInfo::kStatusDone;
+    }
+
+    virtual void applyState(OpenGLRenderer& renderer, int saveCount) = 0;
+};
+
+class DrawOp : public DisplayListOp {
+public:
+    DrawOp(SkPaint* paint)
+            : mPaint(paint), mQuickRejected(false) {}
+
+    virtual status_t replay(OpenGLRenderer& renderer, Rect& dirty, int32_t flags, int saveCount,
+            uint32_t level, bool caching, int multipliedAlpha) {
+        if (mQuickRejected && CC_LIKELY(flags & DisplayList::kReplayFlag_ClipChildren)) {
+            return DrawGlInfo::kStatusDone;
+        }
+
+        return applyDraw(renderer, dirty, level, caching, multipliedAlpha);
+    }
+
+    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, uint32_t level,
+            bool caching, int multipliedAlpha) = 0;
+
+    // returns true if bounds exist
+    virtual bool getLocalBounds(Rect& localBounds) { return false; }
+
+    // TODO: better refine localbounds usage
+    void setQuickRejected(bool quickRejected) { mQuickRejected = quickRejected; }
+    bool getQuickRejected() { return mQuickRejected; }
+
+protected:
+    SkPaint* getPaint(OpenGLRenderer& renderer) {
+        return renderer.filterPaint(mPaint);
+    }
+
+    SkPaint* mPaint; // should be accessed via getPaint() when applying
+    bool mQuickRejected;
+};
+
+class DrawBoundedOp : public DrawOp {
+public:
+    DrawBoundedOp(float left, float top, float right, float bottom, SkPaint* paint)
+            : DrawOp(paint), mLocalBounds(left, top, right, bottom) {}
+
+    // default constructor for area, to be overridden in child constructor body
+    DrawBoundedOp(SkPaint* paint)
+            : DrawOp(paint) {}
+
+    bool getLocalBounds(Rect& localBounds) {
+        localBounds.set(mLocalBounds);
+        return true;
+    }
+
+protected:
+    Rect mLocalBounds; // displayed area in LOCAL coord. doesn't incorporate stroke, so check paint
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// STATE OPERATIONS - these may affect the state of the canvas/renderer, but do
+//         not directly draw or alter output
+///////////////////////////////////////////////////////////////////////////////
+
+class SaveOp : public StateOp {
+public:
+    SaveOp(int flags)
+            : mFlags(flags) {}
+
+    virtual void applyState(OpenGLRenderer& renderer, int saveCount) {
+        renderer.save(mFlags);
+    }
+
+    virtual void output(int level, uint32_t flags = 0) {
+        OP_LOG("Save flags %x", mFlags);
+    }
+
+    virtual const char* name() { return "Save"; }
+
+private:
+    int mFlags;
+};
+
+class RestoreToCountOp : public StateOp {
+public:
+    RestoreToCountOp(int count)
+            : mCount(count) {}
+
+    virtual void applyState(OpenGLRenderer& renderer, int saveCount) {
+        renderer.restoreToCount(saveCount + mCount);
+
+    }
+
+    virtual void output(int level, uint32_t flags = 0) {
+        OP_LOG("Restore to count %d", mCount);
+    }
+
+    virtual const char* name() { return "RestoreToCount"; }
+
+private:
+    int mCount;
+};
+
+class SaveLayerOp : public StateOp {
+public:
+    SaveLayerOp(float left, float top, float right, float bottom, SkPaint* paint, int flags)
+            : mArea(left, top, right, bottom), mPaint(paint), mFlags(flags) {}
+
+    virtual void applyState(OpenGLRenderer& renderer, int saveCount) {
+        SkPaint* paint = renderer.filterPaint(mPaint);
+        renderer.saveLayer(mArea.left, mArea.top, mArea.right, mArea.bottom, paint, mFlags);
+    }
+
+    virtual void output(int level, uint32_t flags = 0) {
+        OP_LOG("SaveLayer of area " RECT_STRING, RECT_ARGS(mArea));
+    }
+
+    virtual const char* name() { return "SaveLayer"; }
+
+private:
+    Rect mArea;
+    SkPaint* mPaint;
+    int mFlags;
+};
+
+class SaveLayerAlphaOp : public StateOp {
+public:
+    SaveLayerAlphaOp(float left, float top, float right, float bottom, int alpha, int flags)
+            : mArea(left, top, right, bottom), mAlpha(alpha), mFlags(flags) {}
+
+    virtual void applyState(OpenGLRenderer& renderer, int saveCount) {
+        renderer.saveLayerAlpha(mArea.left, mArea.top, mArea.right, mArea.bottom, mAlpha, mFlags);
+    }
+
+    virtual void output(int level, uint32_t flags = 0) {
+        OP_LOG("SaveLayerAlpha of area " RECT_STRING, RECT_ARGS(mArea));
+    }
+
+    virtual const char* name() { return "SaveLayerAlpha"; }
+private:
+    Rect mArea;
+    int mAlpha;
+    int mFlags;
+};
+
+class TranslateOp : public StateOp {
+public:
+    TranslateOp(float dx, float dy)
+            : mDx(dx), mDy(dy) {}
+
+    virtual void applyState(OpenGLRenderer& renderer, int saveCount) {
+        renderer.translate(mDx, mDy);
+    }
+
+    virtual void output(int level, uint32_t flags = 0) {
+        OP_LOG("Translate by %f %f", mDx, mDy);
+    }
+
+    virtual const char* name() { return "Translate"; }
+
+private:
+    float mDx;
+    float mDy;
+};
+
+class RotateOp : public StateOp {
+public:
+    RotateOp(float degrees)
+            : mDegrees(degrees) {}
+
+    virtual void applyState(OpenGLRenderer& renderer, int saveCount) {
+        renderer.rotate(mDegrees);
+    }
+
+    virtual void output(int level, uint32_t flags = 0) {
+        OP_LOG("Rotate by %f degrees", mDegrees);
+    }
+
+    virtual const char* name() { return "Rotate"; }
+
+private:
+    float mDegrees;
+};
+
+class ScaleOp : public StateOp {
+public:
+    ScaleOp(float sx, float sy)
+            : mSx(sx), mSy(sy) {}
+
+    virtual void applyState(OpenGLRenderer& renderer, int saveCount) {
+        renderer.scale(mSx, mSy);
+    }
+
+    virtual void output(int level, uint32_t flags = 0) {
+        OP_LOG("Scale by %f %f", mSx, mSy);
+    }
+
+    virtual const char* name() { return "Scale"; }
+
+private:
+    float mSx;
+    float mSy;
+};
+
+class SkewOp : public StateOp {
+public:
+    SkewOp(float sx, float sy)
+            : mSx(sx), mSy(sy) {}
+
+    virtual void applyState(OpenGLRenderer& renderer, int saveCount) {
+        renderer.skew(mSx, mSy);
+    }
+
+    virtual void output(int level, uint32_t flags = 0) {
+        OP_LOG("Skew by %f %f", mSx, mSy);
+    }
+
+    virtual const char* name() { return "Skew"; }
+
+private:
+    float mSx;
+    float mSy;
+};
+
+class SetMatrixOp : public StateOp {
+public:
+    SetMatrixOp(SkMatrix* matrix)
+            : mMatrix(matrix) {}
+
+    virtual void applyState(OpenGLRenderer& renderer, int saveCount) {
+        renderer.setMatrix(mMatrix);
+    }
+
+    virtual void output(int level, uint32_t flags = 0) {
+        OP_LOG("SetMatrix " MATRIX_STRING, MATRIX_ARGS(mMatrix));
+    }
+
+    virtual const char* name() { return "SetMatrix"; }
+
+private:
+    SkMatrix* mMatrix;
+};
+
+class ConcatMatrixOp : public StateOp {
+public:
+    ConcatMatrixOp(SkMatrix* matrix)
+            : mMatrix(matrix) {}
+
+    virtual void applyState(OpenGLRenderer& renderer, int saveCount) {
+        renderer.concatMatrix(mMatrix);
+    }
+
+    virtual void output(int level, uint32_t flags = 0) {
+        OP_LOG("ConcatMatrix " MATRIX_STRING, MATRIX_ARGS(mMatrix));
+    }
+
+    virtual const char* name() { return "ConcatMatrix"; }
+
+private:
+    SkMatrix* mMatrix;
+};
+
+class ClipRectOp : public StateOp {
+public:
+    ClipRectOp(float left, float top, float right, float bottom, SkRegion::Op op)
+            : mArea(left, top, right, bottom), mOp(op) {}
+
+    virtual void applyState(OpenGLRenderer& renderer, int saveCount) {
+        renderer.clipRect(mArea.left, mArea.top, mArea.right, mArea.bottom, mOp);
+    }
+
+    virtual void output(int level, uint32_t flags = 0) {
+        OP_LOG("ClipRect " RECT_STRING, RECT_ARGS(mArea));
+    }
+
+    virtual const char* name() { return "ClipRect"; }
+
+private:
+    Rect mArea;
+    SkRegion::Op mOp;
+};
+
+class ClipPathOp : public StateOp {
+public:
+    ClipPathOp(SkPath* path, SkRegion::Op op)
+            : mPath(path), mOp(op) {}
+
+    virtual void applyState(OpenGLRenderer& renderer, int saveCount) {
+        renderer.clipPath(mPath, mOp);
+    }
+
+    virtual void output(int level, uint32_t flags = 0) {
+        SkRect bounds = mPath->getBounds();
+        OP_LOG("ClipPath bounds " RECT_STRING,
+                bounds.left(), bounds.top(), bounds.right(), bounds.bottom());
+    }
+
+    virtual const char* name() { return "ClipPath"; }
+
+private:
+    SkPath* mPath;
+    SkRegion::Op mOp;
+};
+
+class ClipRegionOp : public StateOp {
+public:
+    ClipRegionOp(SkRegion* region, SkRegion::Op op)
+            : mRegion(region), mOp(op) {}
+
+    virtual void applyState(OpenGLRenderer& renderer, int saveCount) {
+        renderer.clipRegion(mRegion, mOp);
+    }
+
+    virtual void output(int level, uint32_t flags = 0) {
+        SkIRect bounds = mRegion->getBounds();
+        OP_LOG("ClipRegion bounds %d %d %d %d",
+                bounds.left(), bounds.top(), bounds.right(), bounds.bottom());
+    }
+
+    virtual const char* name() { return "ClipRegion"; }
+
+private:
+    SkRegion* mRegion;
+    SkRegion::Op mOp;
+};
+
+class ResetShaderOp : public StateOp {
+public:
+    virtual void applyState(OpenGLRenderer& renderer, int saveCount) {
+        renderer.resetShader();
+    }
+
+    virtual void output(int level, uint32_t flags = 0) {
+        OP_LOGS("ResetShader");
+    }
+
+    virtual const char* name() { return "ResetShader"; }
+};
+
+class SetupShaderOp : public StateOp {
+public:
+    SetupShaderOp(SkiaShader* shader)
+            : mShader(shader) {}
+    virtual void applyState(OpenGLRenderer& renderer, int saveCount) {
+        renderer.setupShader(mShader);
+    }
+
+    virtual void output(int level, uint32_t flags = 0) {
+        OP_LOG("SetupShader, shader %p", mShader);
+    }
+
+    virtual const char* name() { return "SetupShader"; }
+
+private:
+    SkiaShader* mShader;
+};
+
+class ResetColorFilterOp : public StateOp {
+public:
+    virtual void applyState(OpenGLRenderer& renderer, int saveCount) {
+        renderer.resetColorFilter();
+    }
+
+    virtual void output(int level, uint32_t flags = 0) {
+        OP_LOGS("ResetColorFilter");
+    }
+
+    virtual const char* name() { return "ResetColorFilter"; }
+};
+
+class SetupColorFilterOp : public StateOp {
+public:
+    SetupColorFilterOp(SkiaColorFilter* colorFilter)
+            : mColorFilter(colorFilter) {}
+
+    virtual void applyState(OpenGLRenderer& renderer, int saveCount) {
+        renderer.setupColorFilter(mColorFilter);
+    }
+
+    virtual void output(int level, uint32_t flags = 0) {
+        OP_LOG("SetupColorFilter, filter %p", mColorFilter);
+    }
+
+    virtual const char* name() { return "SetupColorFilter"; }
+
+private:
+    SkiaColorFilter* mColorFilter;
+};
+
+class ResetShadowOp : public StateOp {
+public:
+    virtual void applyState(OpenGLRenderer& renderer, int saveCount) {
+        renderer.resetShadow();
+    }
+
+    virtual void output(int level, uint32_t flags = 0) {
+        OP_LOGS("ResetShadow");
+    }
+
+    virtual const char* name() { return "ResetShadow"; }
+};
+
+class SetupShadowOp : public StateOp {
+public:
+    SetupShadowOp(float radius, float dx, float dy, int color)
+            : mRadius(radius), mDx(dx), mDy(dy), mColor(color) {}
+
+    virtual void applyState(OpenGLRenderer& renderer, int saveCount) {
+        renderer.setupShadow(mRadius, mDx, mDy, mColor);
+    }
+
+    virtual void output(int level, uint32_t flags = 0) {
+        OP_LOG("SetupShadow, radius %f, %f, %f, color %#x", mRadius, mDx, mDy, mColor);
+    }
+
+    virtual const char* name() { return "SetupShadow"; }
+
+private:
+    float mRadius;
+    float mDx;
+    float mDy;
+    int mColor;
+};
+
+class ResetPaintFilterOp : public StateOp {
+public:
+    virtual void applyState(OpenGLRenderer& renderer, int saveCount) {
+        renderer.resetPaintFilter();
+    }
+
+    virtual void output(int level, uint32_t flags = 0) {
+        OP_LOGS("ResetPaintFilter");
+    }
+
+    virtual const char* name() { return "ResetPaintFilter"; }
+};
+
+class SetupPaintFilterOp : public StateOp {
+public:
+    SetupPaintFilterOp(int clearBits, int setBits)
+            : mClearBits(clearBits), mSetBits(setBits) {}
+
+    virtual void applyState(OpenGLRenderer& renderer, int saveCount) {
+        renderer.setupPaintFilter(mClearBits, mSetBits);
+    }
+
+    virtual void output(int level, uint32_t flags = 0) {
+        OP_LOG("SetupPaintFilter, clear %#x, set %#x", mClearBits, mSetBits);
+    }
+
+    virtual const char* name() { return "SetupPaintFilter"; }
+
+private:
+    int mClearBits;
+    int mSetBits;
+};
+
+
+///////////////////////////////////////////////////////////////////////////////
+// DRAW OPERATIONS - these are operations that can draw to the canvas's device
+///////////////////////////////////////////////////////////////////////////////
+
+class DrawBitmapOp : public DrawBoundedOp {
+public:
+    DrawBitmapOp(SkBitmap* bitmap, float left, float top, SkPaint* paint)
+            : DrawBoundedOp(left, top, left + bitmap->width(), top + bitmap->height(),
+                    paint),
+            mBitmap(bitmap) {}
+
+    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, uint32_t level,
+            bool caching, int multipliedAlpha) {
+        SkPaint* paint = getPaint(renderer);
+        int oldAlpha = -1;
+        if (caching && multipliedAlpha < 255) {
+            oldAlpha = paint->getAlpha();
+            paint->setAlpha(multipliedAlpha);
+        }
+        status_t ret = renderer.drawBitmap(mBitmap, mLocalBounds.left, mLocalBounds.top, paint);
+        if (oldAlpha >= 0) {
+            paint->setAlpha(oldAlpha);
+        }
+        return ret;
+    }
+
+    virtual void output(int level, uint32_t flags) {
+        OP_LOG("Draw bitmap %p at %f %f", mBitmap, mLocalBounds.left, mLocalBounds.top);
+    }
+
+    virtual const char* name() { return "DrawBitmap"; }
+
+protected:
+    SkBitmap* mBitmap;
+};
+
+class DrawBitmapMatrixOp : public DrawBoundedOp {
+public:
+    DrawBitmapMatrixOp(SkBitmap* bitmap, SkMatrix* matrix, SkPaint* paint)
+            : DrawBoundedOp(paint), mBitmap(bitmap), mMatrix(matrix) {
+        mLocalBounds.set(0, 0, bitmap->width(), bitmap->height());
+        const mat4 transform(*matrix);
+        transform.mapRect(mLocalBounds);
+    }
+
+    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, uint32_t level,
+            bool caching, int multipliedAlpha) {
+        return renderer.drawBitmap(mBitmap, mMatrix, getPaint(renderer));
+    }
+
+    virtual void output(int level, uint32_t flags) {
+        OP_LOG("Draw bitmap %p matrix " MATRIX_STRING, mBitmap, MATRIX_ARGS(mMatrix));
+    }
+
+    virtual const char* name() { return "DrawBitmap"; }
+
+private:
+    SkBitmap* mBitmap;
+    SkMatrix* mMatrix;
+};
+
+class DrawBitmapRectOp : public DrawBoundedOp {
+public:
+    DrawBitmapRectOp(SkBitmap* bitmap, float srcLeft, float srcTop, float srcRight, float srcBottom,
+            float dstLeft, float dstTop, float dstRight, float dstBottom, SkPaint* paint)
+            : DrawBoundedOp(dstLeft, dstTop, dstRight, dstBottom, paint),
+            mBitmap(bitmap), mSrc(srcLeft, srcTop, srcRight, srcBottom) {}
+
+    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, uint32_t level,
+            bool caching, int multipliedAlpha) {
+        return renderer.drawBitmap(mBitmap, mSrc.left, mSrc.top, mSrc.right, mSrc.bottom,
+                mLocalBounds.left, mLocalBounds.top, mLocalBounds.right, mLocalBounds.bottom,
+                getPaint(renderer));
+    }
+
+    virtual void output(int level, uint32_t flags) {
+        OP_LOG("Draw bitmap %p src="RECT_STRING", dst="RECT_STRING,
+                mBitmap, RECT_ARGS(mSrc), RECT_ARGS(mLocalBounds));
+    }
+
+    virtual const char* name() { return "DrawBitmapRect"; }
+
+private:
+    SkBitmap* mBitmap;
+    Rect mSrc;
+};
+
+class DrawBitmapDataOp : public DrawBitmapOp {
+public:
+    DrawBitmapDataOp(SkBitmap* bitmap, float left, float top, SkPaint* paint)
+            : DrawBitmapOp(bitmap, left, top, paint) {}
+
+    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, uint32_t level,
+            bool caching, int multipliedAlpha) {
+        return renderer.drawBitmapData(mBitmap, mLocalBounds.left,
+                mLocalBounds.top, getPaint(renderer));
+    }
+
+    virtual void output(int level, uint32_t flags) {
+        OP_LOG("Draw bitmap %p", mBitmap);
+    }
+
+    virtual const char* name() { return "DrawBitmapData"; }
+};
+
+class DrawBitmapMeshOp : public DrawOp {
+public:
+    DrawBitmapMeshOp(SkBitmap* bitmap, int meshWidth, int meshHeight,
+            float* vertices, int* colors, SkPaint* paint)
+            : DrawOp(paint), mBitmap(bitmap), mMeshWidth(meshWidth), mMeshHeight(meshHeight),
+            mVertices(vertices), mColors(colors) {}
+
+    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, uint32_t level,
+            bool caching, int multipliedAlpha) {
+        return renderer.drawBitmapMesh(mBitmap, mMeshWidth, mMeshHeight,
+                mVertices, mColors, getPaint(renderer));
+    }
+
+    virtual void output(int level, uint32_t flags) {
+        OP_LOG("Draw bitmap %p mesh %d x %d", mBitmap, mMeshWidth, mMeshHeight);
+    }
+
+    virtual const char* name() { return "DrawBitmapMesh"; }
+
+private:
+    SkBitmap* mBitmap;
+    int mMeshWidth;
+    int mMeshHeight;
+    float* mVertices;
+    int* mColors;
+};
+
+class DrawPatchOp : public DrawBoundedOp {
+public:
+    DrawPatchOp(SkBitmap* bitmap, const int32_t* xDivs,
+            const int32_t* yDivs, const uint32_t* colors, uint32_t width, uint32_t height,
+            int8_t numColors, float left, float top, float right, float bottom,
+            int alpha, SkXfermode::Mode mode)
+            : DrawBoundedOp(left, top, right, bottom, 0),
+            mBitmap(bitmap), mxDivs(xDivs), myDivs(yDivs),
+            mColors(colors), mxDivsCount(width), myDivsCount(height),
+            mNumColors(numColors), mAlpha(alpha), mMode(mode) {};
+
+    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, uint32_t level,
+            bool caching, int multipliedAlpha) {
+        // NOTE: not calling the virtual method, which takes a paint
+        return renderer.drawPatch(mBitmap, mxDivs, myDivs, mColors,
+                mxDivsCount, myDivsCount, mNumColors,
+                mLocalBounds.left, mLocalBounds.top,
+                mLocalBounds.right, mLocalBounds.bottom, mAlpha, mMode);
+    }
+
+    virtual void output(int level, uint32_t flags) {
+        OP_LOG("Draw patch "RECT_STRING, RECT_ARGS(mLocalBounds));
+    }
+
+    virtual const char* name() { return "DrawPatch"; }
+
+private:
+    SkBitmap* mBitmap;
+    const int32_t* mxDivs;
+    const int32_t* myDivs;
+    const uint32_t* mColors;
+    uint32_t mxDivsCount;
+    uint32_t myDivsCount;
+    int8_t mNumColors;
+    int mAlpha;
+    SkXfermode::Mode mMode;
+};
+
+class DrawColorOp : public DrawOp {
+public:
+    DrawColorOp(int color, SkXfermode::Mode mode)
+            : DrawOp(0), mColor(color), mMode(mode) {};
+
+    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, uint32_t level,
+            bool caching, int multipliedAlpha) {
+        return renderer.drawColor(mColor, mMode);
+    }
+
+    virtual void output(int level, uint32_t flags) {
+        OP_LOG("Draw color %#x, mode %d", mColor, mMode);
+    }
+
+    virtual const char* name() { return "DrawColor"; }
+
+private:
+    int mColor;
+    SkXfermode::Mode mMode;
+};
+
+class DrawStrokableOp : public DrawBoundedOp {
+public:
+    DrawStrokableOp(float left, float top, float right, float bottom, SkPaint* paint)
+            : DrawBoundedOp(left, top, right, bottom, paint) {};
+
+    bool getLocalBounds(Rect& localBounds) {
+        if (mPaint && mPaint->getStyle() != SkPaint::kFill_Style) {
+            float outset = mPaint->getStrokeWidth() * 0.5f;
+            localBounds.set(mLocalBounds.left - outset, mLocalBounds.top - outset,
+                    mLocalBounds.right + outset, mLocalBounds.bottom + outset);
+        } else {
+            localBounds.set(mLocalBounds);
+        }
+        return true;
+    }
+};
+
+class DrawRectOp : public DrawStrokableOp {
+public:
+    DrawRectOp(float left, float top, float right, float bottom, SkPaint* paint)
+            : DrawStrokableOp(left, top, right, bottom, paint) {}
+
+    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, uint32_t level,
+            bool caching, int multipliedAlpha) {
+        return renderer.drawRect(mLocalBounds.left, mLocalBounds.top,
+                mLocalBounds.right, mLocalBounds.bottom, getPaint(renderer));
+    }
+
+    virtual void output(int level, uint32_t flags) {
+        OP_LOG("Draw Rect "RECT_STRING, RECT_ARGS(mLocalBounds));
+    }
+
+    virtual const char* name() { return "DrawRect"; }
+};
+
+class DrawRectsOp : public DrawOp {
+public:
+    DrawRectsOp(const float* rects, int count, SkPaint* paint)
+            : DrawOp(paint), mRects(rects), mCount(count) {}
+
+    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, uint32_t level,
+            bool caching, int multipliedAlpha) {
+        return renderer.drawRects(mRects, mCount, getPaint(renderer));
+    }
+
+    virtual void output(int level, uint32_t flags) {
+        OP_LOG("Draw Rects count %d", mCount);
+    }
+
+    virtual const char* name() { return "DrawRects"; }
+
+private:
+    const float* mRects;
+    int mCount;
+};
+
+class DrawRoundRectOp : public DrawStrokableOp {
+public:
+    DrawRoundRectOp(float left, float top, float right, float bottom,
+            float rx, float ry, SkPaint* paint)
+            : DrawStrokableOp(left, top, right, bottom, paint), mRx(rx), mRy(ry) {}
+
+    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, uint32_t level,
+            bool caching, int multipliedAlpha) {
+        return renderer.drawRoundRect(mLocalBounds.left, mLocalBounds.top,
+                mLocalBounds.right, mLocalBounds.bottom, mRx, mRy, getPaint(renderer));
+    }
+
+    virtual void output(int level, uint32_t flags) {
+        OP_LOG("Draw RoundRect "RECT_STRING", rx %f, ry %f", RECT_ARGS(mLocalBounds), mRx, mRy);
+    }
+
+    virtual const char* name() { return "DrawRoundRect"; }
+
+private:
+    float mRx;
+    float mRy;
+};
+
+class DrawCircleOp : public DrawStrokableOp {
+public:
+    DrawCircleOp(float x, float y, float radius, SkPaint* paint)
+            : DrawStrokableOp(x - radius, y - radius, x + radius, y + radius, paint),
+            mX(x), mY(y), mRadius(radius) {}
+
+    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, uint32_t level,
+            bool caching, int multipliedAlpha) {
+        return renderer.drawCircle(mX, mY, mRadius, getPaint(renderer));
+    }
+
+    virtual void output(int level, uint32_t flags) {
+        OP_LOG("Draw Circle x %f, y %f, r %f", mX, mY, mRadius);
+    }
+
+    virtual const char* name() { return "DrawCircle"; }
+
+private:
+    float mX;
+    float mY;
+    float mRadius;
+};
+
+class DrawOvalOp : public DrawStrokableOp {
+public:
+    DrawOvalOp(float left, float top, float right, float bottom, SkPaint* paint)
+            : DrawStrokableOp(left, top, right, bottom, paint) {}
+
+    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, uint32_t level,
+            bool caching, int multipliedAlpha) {
+        return renderer.drawOval(mLocalBounds.left, mLocalBounds.top,
+                mLocalBounds.right, mLocalBounds.bottom, getPaint(renderer));
+    }
+
+    virtual void output(int level, uint32_t flags) {
+        OP_LOG("Draw Oval "RECT_STRING, RECT_ARGS(mLocalBounds));
+    }
+
+    virtual const char* name() { return "DrawOval"; }
+};
+
+class DrawArcOp : public DrawStrokableOp {
+public:
+    DrawArcOp(float left, float top, float right, float bottom,
+            float startAngle, float sweepAngle, bool useCenter, SkPaint* paint)
+            : DrawStrokableOp(left, top, right, bottom, paint),
+            mStartAngle(startAngle), mSweepAngle(sweepAngle), mUseCenter(useCenter) {}
+
+    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, uint32_t level,
+            bool caching, int multipliedAlpha) {
+        return renderer.drawArc(mLocalBounds.left, mLocalBounds.top,
+                mLocalBounds.right, mLocalBounds.bottom,
+                mStartAngle, mSweepAngle, mUseCenter, getPaint(renderer));
+    }
+
+    virtual void output(int level, uint32_t flags) {
+        OP_LOG("Draw Arc "RECT_STRING", start %f, sweep %f, useCenter %d",
+                RECT_ARGS(mLocalBounds), mStartAngle, mSweepAngle, mUseCenter);
+    }
+
+    virtual const char* name() { return "DrawArc"; }
+
+private:
+    float mStartAngle;
+    float mSweepAngle;
+    bool mUseCenter;
+};
+
+class DrawPathOp : public DrawBoundedOp {
+public:
+    DrawPathOp(SkPath* path, SkPaint* paint)
+            : DrawBoundedOp(paint), mPath(path) {
+        float left, top, offset;
+        uint32_t width, height;
+        computePathBounds(path, paint, left, top, offset, width, height);
+        left -= offset;
+        top -= offset;
+        mLocalBounds.set(left, top, left + width, top + height);
+    }
+
+    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, uint32_t level,
+            bool caching, int multipliedAlpha) {
+        return renderer.drawPath(mPath, getPaint(renderer));
+    }
+
+    virtual void output(int level, uint32_t flags) {
+        OP_LOG("Draw Path %p in "RECT_STRING, mPath, RECT_ARGS(mLocalBounds));
+    }
+
+    virtual const char* name() { return "DrawPath"; }
+
+private:
+    SkPath* mPath;
+};
+
+class DrawLinesOp : public DrawOp {
+public:
+    DrawLinesOp(float* points, int count, SkPaint* paint)
+            : DrawOp(paint), mPoints(points), mCount(count) {
+        /* TODO: inherit from DrawBoundedOp and calculate localbounds something like:
+        for (int i = 0; i < count; i += 2) {
+            mLocalBounds.left = fminf(mLocalBounds.left, points[i]);
+            mLocalBounds.right = fmaxf(mLocalBounds.right, points[i]);
+            mLocalBounds.top = fminf(mLocalBounds.top, points[i+1]);
+            mLocalBounds.bottom = fmaxf(mLocalBounds.bottom, points[i+1]);
+        }
+        */
+    }
+
+    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, uint32_t level,
+            bool caching, int multipliedAlpha) {
+        return renderer.drawLines(mPoints, mCount, getPaint(renderer));
+    }
+
+    virtual void output(int level, uint32_t flags) {
+        OP_LOG("Draw Lines count %d", mCount);
+    }
+
+    virtual const char* name() { return "DrawLines"; }
+
+protected:
+    float* mPoints;
+    int mCount;
+};
+
+class DrawPointsOp : public DrawLinesOp {
+public:
+    DrawPointsOp(float* points, int count, SkPaint* paint)
+            : DrawLinesOp(points, count, paint) {}
+
+    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, uint32_t level,
+            bool caching, int multipliedAlpha) {
+        return renderer.drawPoints(mPoints, mCount, getPaint(renderer));
+    }
+
+    virtual void output(int level, uint32_t flags) {
+        OP_LOG("Draw Points count %d", mCount);
+    }
+
+    virtual const char* name() { return "DrawPoints"; }
+};
+
+class DrawSomeTextOp : public DrawOp {
+public:
+    DrawSomeTextOp(const char* text, int bytesCount, int count, SkPaint* paint)
+            : DrawOp(paint), mText(text), mBytesCount(bytesCount), mCount(count) {};
+
+    virtual void output(int level, uint32_t flags) {
+        OP_LOG("Draw some text, %d bytes", mBytesCount);
+    }
+protected:
+    const char* mText;
+    int mBytesCount;
+    int mCount;
+};
+
+class DrawTextOnPathOp : public DrawSomeTextOp {
+public:
+    DrawTextOnPathOp(const char* text, int bytesCount, int count,
+            SkPath* path, float hOffset, float vOffset, SkPaint* paint)
+            : DrawSomeTextOp(text, bytesCount, count, paint),
+            mPath(path), mHOffset(hOffset), mVOffset(vOffset) {
+        /* TODO: inherit from DrawBounded and init mLocalBounds */
+    }
+
+    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, uint32_t level,
+            bool caching, int multipliedAlpha) {
+        return renderer.drawTextOnPath(mText, mBytesCount, mCount, mPath,
+                mHOffset, mVOffset, getPaint(renderer));
+    }
+
+    virtual const char* name() { return "DrawTextOnPath"; }
+
+private:
+    SkPath* mPath;
+    float mHOffset;
+    float mVOffset;
+};
+
+class DrawPosTextOp : public DrawSomeTextOp {
+public:
+    DrawPosTextOp(const char* text, int bytesCount, int count,
+            const float* positions, SkPaint* paint)
+            : DrawSomeTextOp(text, bytesCount, count, paint), mPositions(positions) {
+        /* TODO: inherit from DrawBounded and init mLocalBounds */
+    }
+
+    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, uint32_t level,
+            bool caching, int multipliedAlpha) {
+        return renderer.drawPosText(mText, mBytesCount, mCount, mPositions, getPaint(renderer));
+    }
+
+    virtual const char* name() { return "DrawPosText"; }
+
+private:
+    const float* mPositions;
+};
+
+class DrawTextOp : public DrawBoundedOp {
+public:
+    DrawTextOp(const char* text, int bytesCount, int count, float x, float y,
+            const float* positions, SkPaint* paint, float length)
+            : DrawBoundedOp(paint), mText(text), mBytesCount(bytesCount), mCount(count),
+            mX(x), mY(y), mPositions(positions), mLength(length) {
+        SkPaint::FontMetrics metrics;
+        paint->getFontMetrics(&metrics, 0.0f);
+        mLocalBounds.set(mX, mY + metrics.fTop, mX + length, mY + metrics.fBottom);
+    }
+
+    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, uint32_t level,
+            bool caching, int multipliedAlpha) {
+        return renderer.drawText(mText, mBytesCount, mCount, mX, mY,
+                mPositions, getPaint(renderer), mLength);
+    }
+
+    virtual void output(int level, uint32_t flags) {
+        OP_LOG("Draw Text of count %d, bytes %d", mCount, mBytesCount);
+    }
+
+    virtual const char* name() { return "DrawText"; }
+
+private:
+    const char* mText;
+    int mBytesCount;
+    int mCount;
+    float mX;
+    float mY;
+    const float* mPositions;
+    float mLength;
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// SPECIAL DRAW OPERATIONS
+///////////////////////////////////////////////////////////////////////////////
+
+class DrawFunctorOp : public DrawOp {
+public:
+    DrawFunctorOp(Functor* functor)
+            : DrawOp(0), mFunctor(functor) {}
+
+    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, uint32_t level,
+            bool caching, int multipliedAlpha) {
+        renderer.startMark("GL functor");
+        status_t ret = renderer.callDrawGLFunction(mFunctor, dirty);
+        renderer.endMark();
+        return ret;
+    }
+
+    virtual void output(int level, uint32_t flags) {
+        OP_LOG("Draw Functor %p", mFunctor);
+    }
+
+    virtual const char* name() { return "DrawFunctor"; }
+
+private:
+    Functor* mFunctor;
+};
+
+class DrawDisplayListOp : public DrawOp {
+public:
+    DrawDisplayListOp(DisplayList* displayList, int flags)
+            : DrawOp(0), mDisplayList(displayList), mFlags(flags) {}
+    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, uint32_t level,
+            bool caching, int multipliedAlpha) {
+        return renderer.drawDisplayList(mDisplayList, dirty, mFlags, level + 1);
+    }
+
+    virtual void output(int level, uint32_t flags) {
+        OP_LOG("Draw Display List %p, flags %#x", mDisplayList, mFlags);
+        if (mDisplayList && (flags & kOpLogFlag_Recurse)) {
+            mDisplayList->output(level + 1);
+        }
+    }
+
+    virtual const char* name() { return "DrawDisplayList"; }
+
+private:
+    DisplayList* mDisplayList;
+    int mFlags;
+};
+
+class DrawLayerOp : public DrawOp {
+public:
+    DrawLayerOp(Layer* layer, float x, float y, SkPaint* paint)
+            : DrawOp(paint), mLayer(layer), mX(x), mY(y) {}
+
+    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, uint32_t level,
+            bool caching, int multipliedAlpha) {
+        int oldAlpha = -1;
+
+        if (caching && multipliedAlpha < 255) {
+            oldAlpha = mLayer->getAlpha();
+            mLayer->setAlpha(multipliedAlpha);
+        }
+        status_t ret = renderer.drawLayer(mLayer, mX, mY, getPaint(renderer));
+        if (oldAlpha >= 0) {
+            mLayer->setAlpha(oldAlpha);
+        }
+        return ret;
+    }
+
+    virtual void output(int level, uint32_t flags) {
+        OP_LOG("Draw Layer %p at %f %f", mLayer, mX, mY);
+    }
+
+    virtual const char* name() { return "DrawLayer"; }
+
+private:
+    Layer* mLayer;
+    float mX;
+    float mY;
+};
+
+}; // namespace uirenderer
+}; // namespace android
+
+#endif // ANDROID_HWUI_DISPLAY_OPERATION_H
diff --git a/libs/hwui/DisplayListRenderer.cpp b/libs/hwui/DisplayListRenderer.cpp
index f0c9ce4..5cb629e 100644
--- a/libs/hwui/DisplayListRenderer.cpp
+++ b/libs/hwui/DisplayListRenderer.cpp
@@ -21,6 +21,7 @@
 #include <private/hwui/DrawGlInfo.h>
 
 #include "DisplayListLogBuffer.h"
+#include "DisplayListOp.h"
 #include "DisplayListRenderer.h"
 #include "Caches.h"
 
@@ -31,53 +32,6 @@
 // Display list
 ///////////////////////////////////////////////////////////////////////////////
 
-const char* DisplayList::OP_NAMES[] = {
-    "Save",
-    "Restore",
-    "RestoreToCount",
-    "SaveLayer",
-    "SaveLayerAlpha",
-    "Translate",
-    "Rotate",
-    "Scale",
-    "Skew",
-    "SetMatrix",
-    "ConcatMatrix",
-    "ClipRect",
-    "ClipPath",
-    "ClipRegion",
-    "DrawDisplayList",
-    "DrawLayer",
-    "DrawBitmap",
-    "DrawBitmapMatrix",
-    "DrawBitmapRect",
-    "DrawBitmapData",
-    "DrawBitmapMesh",
-    "DrawPatch",
-    "DrawColor",
-    "DrawRect",
-    "DrawRoundRect",
-    "DrawCircle",
-    "DrawOval",
-    "DrawArc",
-    "DrawPath",
-    "DrawLines",
-    "DrawPoints",
-    "DrawTextOnPath",
-    "DrawPosText",
-    "DrawText",
-    "DrawRects",
-    "ResetShader",
-    "SetupShader",
-    "ResetColorFilter",
-    "SetupColorFilter",
-    "ResetShadow",
-    "SetupShadow",
-    "ResetPaintFilter",
-    "SetupPaintFilter",
-    "DrawGLFunction"
-};
-
 void DisplayList::outputLogBuffer(int fd) {
     DisplayListLogBuffer& logBuffer = DisplayListLogBuffer::getInstance();
     if (logBuffer.isEmpty()) {
@@ -87,7 +41,7 @@
     FILE *file = fdopen(fd, "a");
 
     fprintf(file, "\nRecent DisplayList operations\n");
-    logBuffer.outputCommands(file, OP_NAMES);
+    logBuffer.outputCommands(file);
 
     String8 cachesLog;
     Caches::getInstance().dumpMemoryUsage(cachesLog);
@@ -116,9 +70,7 @@
 }
 
 void DisplayList::clearResources() {
-    sk_free((void*) mReader.base());
-    mReader.setMemory(NULL, 0);
-
+    mDisplayListData = NULL;
     delete mTransformMatrix;
     delete mTransformCamera;
     delete mTransformMatrix3D;
@@ -200,7 +152,6 @@
 }
 
 void DisplayList::initFromDisplayListRenderer(const DisplayListRenderer& recorder, bool reusing) {
-
     if (reusing) {
         // re-using display list - clear out previous allocations
         clearResources();
@@ -208,16 +159,13 @@
 
     init();
 
-    const SkWriter32& writer = recorder.writeStream();
-    if (writer.size() == 0) {
+    mDisplayListData = recorder.getDisplayListData();
+    mSize = mDisplayListData->allocator.usedSize();
+
+    if (mSize == 0) {
         return;
     }
 
-    mSize = writer.size();
-    void* buffer = sk_malloc_throw(mSize);
-    writer.flatten(buffer);
-    mReader.setMemory(buffer, mSize);
-
     mFunctorCount = recorder.getFunctorCount();
 
     Caches& caches = Caches::getInstance();
@@ -312,392 +260,17 @@
  * This function is a simplified version of replay(), where we simply retrieve and log the
  * display list. This function should remain in sync with the replay() function.
  */
-void DisplayList::output(OpenGLRenderer& renderer, uint32_t level) {
-    TextContainer text;
-
-    uint32_t count = (level + 1) * 2;
-    char indent[count + 1];
-    for (uint32_t i = 0; i < count; i++) {
-        indent[i] = ' ';
-    }
-    indent[count] = '\0';
-    ALOGD("%sStart display list (%p, %s, render=%d)", (char*) indent + 2, this,
+void DisplayList::output(uint32_t level) {
+    ALOGD("%*sStart display list (%p, %s, render=%d)", level * 2, "", this,
             mName.string(), isRenderable());
 
-    ALOGD("%s%s %d", indent, "Save", SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag);
-    int saveCount = renderer.getSaveCount() - 1;
-
-    outputViewProperties(renderer, (char*) indent);
-    mReader.rewind();
-
-    while (!mReader.eof()) {
-        int op = mReader.readInt();
-        if (op & OP_MAY_BE_SKIPPED_MASK) {
-            int skip = mReader.readInt();
-            ALOGD("%sSkip %d", (char*) indent, skip);
-            op &= ~OP_MAY_BE_SKIPPED_MASK;
-        }
-
-        switch (op) {
-            case DrawGLFunction: {
-                Functor *functor = (Functor *) getInt();
-                ALOGD("%s%s %p", (char*) indent, OP_NAMES[op], functor);
-            }
-            break;
-            case Save: {
-                int rendererNum = getInt();
-                ALOGD("%s%s %d", (char*) indent, OP_NAMES[op], rendererNum);
-            }
-            break;
-            case Restore: {
-                ALOGD("%s%s", (char*) indent, OP_NAMES[op]);
-            }
-            break;
-            case RestoreToCount: {
-                int restoreCount = saveCount + getInt();
-                ALOGD("%s%s %d", (char*) indent, OP_NAMES[op], restoreCount);
-            }
-            break;
-            case SaveLayer: {
-                float f1 = getFloat();
-                float f2 = getFloat();
-                float f3 = getFloat();
-                float f4 = getFloat();
-                SkPaint* paint = getPaint(renderer);
-                int flags = getInt();
-                ALOGD("%s%s %.2f, %.2f, %.2f, %.2f, %p, 0x%x", (char*) indent,
-                        OP_NAMES[op], f1, f2, f3, f4, paint, flags);
-            }
-            break;
-            case SaveLayerAlpha: {
-                float f1 = getFloat();
-                float f2 = getFloat();
-                float f3 = getFloat();
-                float f4 = getFloat();
-                int alpha = getInt();
-                int flags = getInt();
-                ALOGD("%s%s %.2f, %.2f, %.2f, %.2f, %d, 0x%x", (char*) indent,
-                        OP_NAMES[op], f1, f2, f3, f4, alpha, flags);
-            }
-            break;
-            case Translate: {
-                float f1 = getFloat();
-                float f2 = getFloat();
-                ALOGD("%s%s %.2f, %.2f", (char*) indent, OP_NAMES[op], f1, f2);
-            }
-            break;
-            case Rotate: {
-                float rotation = getFloat();
-                ALOGD("%s%s %.2f", (char*) indent, OP_NAMES[op], rotation);
-            }
-            break;
-            case Scale: {
-                float sx = getFloat();
-                float sy = getFloat();
-                ALOGD("%s%s %.2f, %.2f", (char*) indent, OP_NAMES[op], sx, sy);
-            }
-            break;
-            case Skew: {
-                float sx = getFloat();
-                float sy = getFloat();
-                ALOGD("%s%s %.2f, %.2f", (char*) indent, OP_NAMES[op], sx, sy);
-            }
-            break;
-            case SetMatrix: {
-                SkMatrix* matrix = getMatrix();
-                ALOGD("%s%s %p", (char*) indent, OP_NAMES[op], matrix);
-            }
-            break;
-            case ConcatMatrix: {
-                SkMatrix* matrix = getMatrix();
-                ALOGD("%s%s new concat %p: [%f, %f, %f]   [%f, %f, %f]   [%f, %f, %f]",
-                        (char*) indent, OP_NAMES[op], matrix, matrix->get(0), matrix->get(1),
-                        matrix->get(2), matrix->get(3), matrix->get(4), matrix->get(5),
-                        matrix->get(6), matrix->get(7), matrix->get(8));
-            }
-            break;
-            case ClipRect: {
-                float f1 = getFloat();
-                float f2 = getFloat();
-                float f3 = getFloat();
-                float f4 = getFloat();
-                int regionOp = getInt();
-                ALOGD("%s%s %.2f, %.2f, %.2f, %.2f, %d", (char*) indent, OP_NAMES[op],
-                        f1, f2, f3, f4, regionOp);
-            }
-            break;
-            case ClipPath: {
-                SkPath* path = getPath();
-                int regionOp = getInt();
-                ALOGD("%s%s %d", (char*) indent, OP_NAMES[op], regionOp);
-            }
-            break;
-            case ClipRegion: {
-                SkRegion* region = getRegion();
-                int regionOp = getInt();
-                ALOGD("%s%s %d", (char*) indent, OP_NAMES[op], regionOp);
-            }
-            break;
-            case DrawDisplayList: {
-                DisplayList* displayList = getDisplayList();
-                int32_t flags = getInt();
-                ALOGD("%s%s %p, %dx%d, 0x%x %d", (char*) indent, OP_NAMES[op],
-                        displayList, mWidth, mHeight, flags, level + 1);
-                renderer.outputDisplayList(displayList, level + 1);
-            }
-            break;
-            case DrawLayer: {
-                Layer* layer = (Layer*) getInt();
-                float x = getFloat();
-                float y = getFloat();
-                SkPaint* paint = getPaint(renderer);
-                ALOGD("%s%s %p, %.2f, %.2f, %p", (char*) indent, OP_NAMES[op],
-                        layer, x, y, paint);
-            }
-            break;
-            case DrawBitmap: {
-                SkBitmap* bitmap = getBitmap();
-                float x = getFloat();
-                float y = getFloat();
-                SkPaint* paint = getPaint(renderer);
-                ALOGD("%s%s %p, %.2f, %.2f, %p", (char*) indent, OP_NAMES[op],
-                        bitmap, x, y, paint);
-            }
-            break;
-            case DrawBitmapMatrix: {
-                SkBitmap* bitmap = getBitmap();
-                SkMatrix* matrix = getMatrix();
-                SkPaint* paint = getPaint(renderer);
-                ALOGD("%s%s %p, %p, %p", (char*) indent, OP_NAMES[op],
-                        bitmap, matrix, paint);
-            }
-            break;
-            case DrawBitmapRect: {
-                SkBitmap* bitmap = getBitmap();
-                float f1 = getFloat();
-                float f2 = getFloat();
-                float f3 = getFloat();
-                float f4 = getFloat();
-                float f5 = getFloat();
-                float f6 = getFloat();
-                float f7 = getFloat();
-                float f8 = getFloat();
-                SkPaint* paint = getPaint(renderer);
-                ALOGD("%s%s %p, %.2f, %.2f, %.2f, %.2f, %.2f, %.2f, %.2f, %.2f, %p",
-                        (char*) indent, OP_NAMES[op], bitmap, f1, f2, f3, f4, f5, f6, f7, f8, paint);
-            }
-            break;
-            case DrawBitmapData: {
-                SkBitmap* bitmap = getBitmapData();
-                float x = getFloat();
-                float y = getFloat();
-                SkPaint* paint = getPaint(renderer);
-                ALOGD("%s%s %.2f, %.2f, %p", (char*) indent, OP_NAMES[op], x, y, paint);
-            }
-            break;
-            case DrawBitmapMesh: {
-                int verticesCount = 0;
-                uint32_t colorsCount = 0;
-                SkBitmap* bitmap = getBitmap();
-                uint32_t meshWidth = getInt();
-                uint32_t meshHeight = getInt();
-                float* vertices = getFloats(verticesCount);
-                bool hasColors = getInt();
-                int* colors = hasColors ? getInts(colorsCount) : NULL;
-                SkPaint* paint = getPaint(renderer);
-                ALOGD("%s%s", (char*) indent, OP_NAMES[op]);
-            }
-            break;
-            case DrawPatch: {
-                int32_t* xDivs = NULL;
-                int32_t* yDivs = NULL;
-                uint32_t* colors = NULL;
-                uint32_t xDivsCount = 0;
-                uint32_t yDivsCount = 0;
-                int8_t numColors = 0;
-                SkBitmap* bitmap = getBitmap();
-                xDivs = getInts(xDivsCount);
-                yDivs = getInts(yDivsCount);
-                colors = getUInts(numColors);
-                float left = getFloat();
-                float top = getFloat();
-                float right = getFloat();
-                float bottom = getFloat();
-                int alpha = getInt();
-                SkXfermode::Mode mode = (SkXfermode::Mode) getInt();
-                ALOGD("%s%s %.2f, %.2f, %.2f, %.2f", (char*) indent, OP_NAMES[op],
-                        left, top, right, bottom);
-            }
-            break;
-            case DrawColor: {
-                int color = getInt();
-                int xferMode = getInt();
-                ALOGD("%s%s 0x%x %d", (char*) indent, OP_NAMES[op], color, xferMode);
-            }
-            break;
-            case DrawRect: {
-                float f1 = getFloat();
-                float f2 = getFloat();
-                float f3 = getFloat();
-                float f4 = getFloat();
-                SkPaint* paint = getPaint(renderer);
-                ALOGD("%s%s %.2f, %.2f, %.2f, %.2f, %p", (char*) indent, OP_NAMES[op],
-                        f1, f2, f3, f4, paint);
-            }
-            break;
-            case DrawRoundRect: {
-                float f1 = getFloat();
-                float f2 = getFloat();
-                float f3 = getFloat();
-                float f4 = getFloat();
-                float f5 = getFloat();
-                float f6 = getFloat();
-                SkPaint* paint = getPaint(renderer);
-                ALOGD("%s%s %.2f, %.2f, %.2f, %.2f, %.2f, %.2f, %p",
-                        (char*) indent, OP_NAMES[op], f1, f2, f3, f4, f5, f6, paint);
-            }
-            break;
-            case DrawCircle: {
-                float f1 = getFloat();
-                float f2 = getFloat();
-                float f3 = getFloat();
-                SkPaint* paint = getPaint(renderer);
-                ALOGD("%s%s %.2f, %.2f, %.2f, %p",
-                        (char*) indent, OP_NAMES[op], f1, f2, f3, paint);
-            }
-            break;
-            case DrawOval: {
-                float f1 = getFloat();
-                float f2 = getFloat();
-                float f3 = getFloat();
-                float f4 = getFloat();
-                SkPaint* paint = getPaint(renderer);
-                ALOGD("%s%s %.2f, %.2f, %.2f, %.2f, %p",
-                        (char*) indent, OP_NAMES[op], f1, f2, f3, f4, paint);
-            }
-            break;
-            case DrawArc: {
-                float f1 = getFloat();
-                float f2 = getFloat();
-                float f3 = getFloat();
-                float f4 = getFloat();
-                float f5 = getFloat();
-                float f6 = getFloat();
-                int i1 = getInt();
-                SkPaint* paint = getPaint(renderer);
-                ALOGD("%s%s %.2f, %.2f, %.2f, %.2f, %.2f, %.2f, %d, %p",
-                        (char*) indent, OP_NAMES[op], f1, f2, f3, f4, f5, f6, i1, paint);
-            }
-            break;
-            case DrawPath: {
-                SkPath* path = getPath();
-                SkPaint* paint = getPaint(renderer);
-                ALOGD("%s%s %p, %p", (char*) indent, OP_NAMES[op], path, paint);
-            }
-            break;
-            case DrawLines: {
-                int count = 0;
-                float* points = getFloats(count);
-                SkPaint* paint = getPaint(renderer);
-                ALOGD("%s%s", (char*) indent, OP_NAMES[op]);
-            }
-            break;
-            case DrawPoints: {
-                int count = 0;
-                float* points = getFloats(count);
-                SkPaint* paint = getPaint(renderer);
-                ALOGD("%s%s", (char*) indent, OP_NAMES[op]);
-            }
-            break;
-            case DrawTextOnPath: {
-                getText(&text);
-                int32_t count = getInt();
-                SkPath* path = getPath();
-                float hOffset = getFloat();
-                float vOffset = getFloat();
-                SkPaint* paint = getPaint(renderer);
-                ALOGD("%s%s %s, %d, %d, %p", (char*) indent, OP_NAMES[op],
-                    text.text(), text.length(), count, paint);
-            }
-            break;
-            case DrawPosText: {
-                getText(&text);
-                int count = getInt();
-                int positionsCount = 0;
-                float* positions = getFloats(positionsCount);
-                SkPaint* paint = getPaint(renderer);
-                ALOGD("%s%s %s, %d, %d, %p", (char*) indent, OP_NAMES[op],
-                        text.text(), text.length(), count, paint);
-            }
-            break;
-            case DrawText: {
-                getText(&text);
-                int32_t count = getInt();
-                float x = getFloat();
-                float y = getFloat();
-                int32_t positionsCount = 0;
-                float* positions = getFloats(positionsCount);
-                SkPaint* paint = getPaint(renderer);
-                float length = getFloat();
-                ALOGD("%s%s %s, %d, %d, %p", (char*) indent, OP_NAMES[op],
-                        text.text(), text.length(), count, paint);
-            }
-            break;
-            case DrawRects: {
-                int32_t count = 0;
-                float* rects = getFloats(count);
-                SkPaint* paint = getPaint(renderer);
-                ALOGD("%s%s %d, %p", (char*) indent, OP_NAMES[op], count / 4, paint);
-            }
-            break;
-            case ResetShader: {
-                ALOGD("%s%s", (char*) indent, OP_NAMES[op]);
-            }
-            break;
-            case SetupShader: {
-                SkiaShader* shader = getShader();
-                ALOGD("%s%s %p", (char*) indent, OP_NAMES[op], shader);
-            }
-            break;
-            case ResetColorFilter: {
-                ALOGD("%s%s", (char*) indent, OP_NAMES[op]);
-            }
-            break;
-            case SetupColorFilter: {
-                SkiaColorFilter *colorFilter = getColorFilter();
-                ALOGD("%s%s %p", (char*) indent, OP_NAMES[op], colorFilter);
-            }
-            break;
-            case ResetShadow: {
-                ALOGD("%s%s", (char*) indent, OP_NAMES[op]);
-            }
-            break;
-            case SetupShadow: {
-                float radius = getFloat();
-                float dx = getFloat();
-                float dy = getFloat();
-                int color = getInt();
-                ALOGD("%s%s %.2f, %.2f, %.2f, 0x%x", (char*) indent, OP_NAMES[op],
-                        radius, dx, dy, color);
-            }
-            break;
-            case ResetPaintFilter: {
-                ALOGD("%s%s", (char*) indent, OP_NAMES[op]);
-            }
-            break;
-            case SetupPaintFilter: {
-                int clearBits = getInt();
-                int setBits = getInt();
-                ALOGD("%s%s 0x%x, 0x%x", (char*) indent, OP_NAMES[op], clearBits, setBits);
-            }
-            break;
-            default:
-                ALOGD("Display List error: op not handled: %s%s",
-                        (char*) indent, OP_NAMES[op]);
-                break;
-        }
+    ALOGD("%*s%s %d", level * 4, "", "Save", SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag);
+    outputViewProperties(level);
+    int flags = DisplayListOp::kOpLogFlag_Recurse;
+    for (unsigned int i = 0; i < mDisplayListData->displayListOps.size(); i++) {
+        mDisplayListData->displayListOps[i]->output(level, flags);
     }
-    ALOGD("%sDone (%p, %s)", (char*) indent + 2, this, mName.string());
+    ALOGD("%*sDone (%p, %s)", level * 2, "", this, mName.string());
 }
 
 void DisplayList::updateMatrix() {
@@ -743,115 +316,68 @@
     }
 }
 
-void DisplayList::outputViewProperties(OpenGLRenderer& renderer, char* indent) {
+void DisplayList::outputViewProperties(uint32_t level) {
     updateMatrix();
     if (mLeft != 0 || mTop != 0) {
-        ALOGD("%s%s %d, %d", indent, "Translate (left, top)", mLeft, mTop);
+        ALOGD("%*sTranslate (left, top) %d, %d", level * 2, "", mLeft, mTop);
     }
     if (mStaticMatrix) {
-        ALOGD("%s%s %p: [%.2f, %.2f, %.2f] [%.2f, %.2f, %.2f] [%.2f, %.2f, %.2f]",
-                indent, "ConcatMatrix (static)", mStaticMatrix,
-                mStaticMatrix->get(0), mStaticMatrix->get(1),
-                mStaticMatrix->get(2), mStaticMatrix->get(3),
-                mStaticMatrix->get(4), mStaticMatrix->get(5),
-                mStaticMatrix->get(6), mStaticMatrix->get(7),
-                mStaticMatrix->get(8));
+        ALOGD("%*sConcatMatrix (static) %p: " MATRIX_STRING,
+                level * 2, "", mStaticMatrix, MATRIX_ARGS(mStaticMatrix));
     }
     if (mAnimationMatrix) {
-        ALOGD("%s%s %p: [%.2f, %.2f, %.2f] [%.2f, %.2f, %.2f] [%.2f, %.2f, %.2f]",
-                indent, "ConcatMatrix (animation)", mAnimationMatrix,
-                mAnimationMatrix->get(0), mAnimationMatrix->get(1),
-                mAnimationMatrix->get(2), mAnimationMatrix->get(3),
-                mAnimationMatrix->get(4), mAnimationMatrix->get(5),
-                mAnimationMatrix->get(6), mAnimationMatrix->get(7),
-                mAnimationMatrix->get(8));
+        ALOGD("%*sConcatMatrix (animation) %p: " MATRIX_STRING,
+                level * 2, "", mAnimationMatrix, MATRIX_ARGS(mStaticMatrix));
     }
     if (mMatrixFlags != 0) {
         if (mMatrixFlags == TRANSLATION) {
-            ALOGD("%s%s %f, %f", indent, "Translate", mTranslationX, mTranslationY);
+            ALOGD("%*sTranslate %f, %f", level * 2, "", mTranslationX, mTranslationY);
         } else {
-            ALOGD("%s%s %p: [%.2f, %.2f, %.2f] [%.2f, %.2f, %.2f] [%.2f, %.2f, %.2f]",
-                    indent, "ConcatMatrix", mTransformMatrix,
-                    mTransformMatrix->get(0), mTransformMatrix->get(1),
-                    mTransformMatrix->get(2), mTransformMatrix->get(3),
-                    mTransformMatrix->get(4), mTransformMatrix->get(5),
-                    mTransformMatrix->get(6), mTransformMatrix->get(7),
-                    mTransformMatrix->get(8));
+            ALOGD("%*sConcatMatrix %p: " MATRIX_STRING,
+                    level * 2, "", mTransformMatrix, MATRIX_ARGS(mTransformMatrix));
         }
     }
     if (mAlpha < 1 && !mCaching) {
         if (!mHasOverlappingRendering) {
-            ALOGD("%s%s %.2f", indent, "SetAlpha", mAlpha);
+            ALOGD("%*sSetAlpha %.2f", level * 2, "", mAlpha);
         } else {
             int flags = SkCanvas::kHasAlphaLayer_SaveFlag;
             if (mClipChildren) {
                 flags |= SkCanvas::kClipToLayer_SaveFlag;
             }
-            ALOGD("%s%s %.2f, %.2f, %.2f, %.2f, %d, 0x%x", indent, "SaveLayerAlpha",
+            ALOGD("%*sSaveLayerAlpha %.2f, %.2f, %.2f, %.2f, %d, 0x%x", level * 2, "",
                     (float) 0, (float) 0, (float) mRight - mLeft, (float) mBottom - mTop,
                     mMultipliedAlpha, flags);
         }
     }
     if (mClipChildren) {
-        ALOGD("%s%s %.2f, %.2f, %.2f, %.2f", indent, "ClipRect", 0.0f, 0.0f,
+        ALOGD("%*sClipRect %.2f, %.2f, %.2f, %.2f", level * 2, "", 0.0f, 0.0f,
                 (float) mRight - mLeft, (float) mBottom - mTop);
     }
 }
 
 void DisplayList::setViewProperties(OpenGLRenderer& renderer, uint32_t level) {
-#if DEBUG_DISPLAY_LIST
-        uint32_t count = (level + 1) * 2;
-        char indent[count + 1];
-        for (uint32_t i = 0; i < count; i++) {
-            indent[i] = ' ';
-        }
-        indent[count] = '\0';
+#if DEBUG_DISPLAYLIST
+    outputViewProperties(level);
 #endif
     updateMatrix();
     if (mLeft != 0 || mTop != 0) {
-        DISPLAY_LIST_LOGD("%s%s %d, %d", indent, "Translate (left, top)", mLeft, mTop);
         renderer.translate(mLeft, mTop);
     }
     if (mStaticMatrix) {
-        DISPLAY_LIST_LOGD(
-                "%s%s %p: [%.2f, %.2f, %.2f] [%.2f, %.2f, %.2f] [%.2f, %.2f, %.2f]",
-                indent, "ConcatMatrix (static)", mStaticMatrix,
-                mStaticMatrix->get(0), mStaticMatrix->get(1),
-                mStaticMatrix->get(2), mStaticMatrix->get(3),
-                mStaticMatrix->get(4), mStaticMatrix->get(5),
-                mStaticMatrix->get(6), mStaticMatrix->get(7),
-                mStaticMatrix->get(8));
         renderer.concatMatrix(mStaticMatrix);
     } else if (mAnimationMatrix) {
-        DISPLAY_LIST_LOGD(
-                "%s%s %p: [%.2f, %.2f, %.2f] [%.2f, %.2f, %.2f] [%.2f, %.2f, %.2f]",
-                indent, "ConcatMatrix (animation)", mAnimationMatrix,
-                mAnimationMatrix->get(0), mAnimationMatrix->get(1),
-                mAnimationMatrix->get(2), mAnimationMatrix->get(3),
-                mAnimationMatrix->get(4), mAnimationMatrix->get(5),
-                mAnimationMatrix->get(6), mAnimationMatrix->get(7),
-                mAnimationMatrix->get(8));
         renderer.concatMatrix(mAnimationMatrix);
     }
     if (mMatrixFlags != 0) {
         if (mMatrixFlags == TRANSLATION) {
-            DISPLAY_LIST_LOGD("%s%s %f, %f", indent, "Translate", mTranslationX, mTranslationY);
             renderer.translate(mTranslationX, mTranslationY);
         } else {
-            DISPLAY_LIST_LOGD(
-                    "%s%s %p: [%.2f, %.2f, %.2f] [%.2f, %.2f, %.2f] [%.2f, %.2f, %.2f]",
-                    indent, "ConcatMatrix", mTransformMatrix,
-                    mTransformMatrix->get(0), mTransformMatrix->get(1),
-                    mTransformMatrix->get(2), mTransformMatrix->get(3),
-                    mTransformMatrix->get(4), mTransformMatrix->get(5),
-                    mTransformMatrix->get(6), mTransformMatrix->get(7),
-                    mTransformMatrix->get(8));
             renderer.concatMatrix(mTransformMatrix);
         }
     }
     if (mAlpha < 1 && !mCaching) {
         if (!mHasOverlappingRendering) {
-            DISPLAY_LIST_LOGD("%s%s %.2f", indent, "SetAlpha", mAlpha);
             renderer.setAlpha(mAlpha);
         } else {
             // TODO: should be able to store the size of a DL at record time and not
@@ -861,53 +387,35 @@
             if (mClipChildren) {
                 flags |= SkCanvas::kClipToLayer_SaveFlag;
             }
-            DISPLAY_LIST_LOGD("%s%s %.2f, %.2f, %.2f, %.2f, %d, 0x%x", indent, "SaveLayerAlpha",
-                    (float) 0, (float) 0, (float) mRight - mLeft, (float) mBottom - mTop,
-                    mMultipliedAlpha, flags);
             renderer.saveLayerAlpha(0, 0, mRight - mLeft, mBottom - mTop,
                     mMultipliedAlpha, flags);
         }
     }
     if (mClipChildren) {
-        DISPLAY_LIST_LOGD("%s%s %.2f, %.2f, %.2f, %.2f", indent, "ClipRect", 0.0f, 0.0f,
-                (float) mRight - mLeft, (float) mBottom - mTop);
         renderer.clipRect(0, 0, mRight - mLeft, mBottom - mTop,
                 SkRegion::kIntersect_Op);
     }
 }
 
-/**
- * Changes to replay(), specifically those involving opcode or parameter changes, should be mimicked
- * in the output() function, since that function processes the same list of opcodes for the
- * purposes of logging display list info for a given view.
- */
 status_t DisplayList::replay(OpenGLRenderer& renderer, Rect& dirty, int32_t flags, uint32_t level) {
     status_t drawGlStatus = DrawGlInfo::kStatusDone;
-    TextContainer text;
-    mReader.rewind();
 
 #if DEBUG_DISPLAY_LIST
-    uint32_t count = (level + 1) * 2;
-    char indent[count + 1];
-    for (uint32_t i = 0; i < count; i++) {
-        indent[i] = ' ';
-    }
-    indent[count] = '\0';
     Rect* clipRect = renderer.getClipRect();
-    DISPLAY_LIST_LOGD("%sStart display list (%p, %s), clipRect: %.0f, %.f, %.0f, %.0f",
-            (char*) indent + 2, this, mName.string(), clipRect->left, clipRect->top,
+    DISPLAY_LIST_LOGD("%*sStart display list (%p, %s), clipRect: %.0f, %.f, %.0f, %.0f",
+            (level+1)*2, "", this, mName.string(), clipRect->left, clipRect->top,
             clipRect->right, clipRect->bottom);
 #endif
 
     renderer.startMark(mName.string());
 
     int restoreTo = renderer.save(SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag);
-    DISPLAY_LIST_LOGD("%s%s %d %d", indent, "Save",
+    DISPLAY_LIST_LOGD("%*sSave %d %d", level * 2, "",
             SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag, restoreTo);
     setViewProperties(renderer, level);
 
     if (renderer.quickRejectNoScissor(0, 0, mWidth, mHeight)) {
-        DISPLAY_LIST_LOGD("%s%s %d", (char*) indent, "RestoreToCount", restoreTo);
+        DISPLAY_LIST_LOGD("%*sRestoreToCount %d", level * 2, "", restoreTo);
         renderer.restoreToCount(restoreTo);
         renderer.endMark();
         return drawGlStatus;
@@ -915,469 +423,22 @@
 
     DisplayListLogBuffer& logBuffer = DisplayListLogBuffer::getInstance();
     int saveCount = renderer.getSaveCount() - 1;
-
-    while (!mReader.eof()) {
-        int op = mReader.readInt();
-        if (op & OP_MAY_BE_SKIPPED_MASK) {
-            int32_t skip = mReader.readInt();
-            if (CC_LIKELY(flags & kReplayFlag_ClipChildren)) {
-                mReader.skip(skip);
-                DISPLAY_LIST_LOGD("%s%s skipping %d bytes", (char*) indent,
-                        OP_NAMES[op & ~OP_MAY_BE_SKIPPED_MASK], skip);
-                continue;
-            } else {
-                op &= ~OP_MAY_BE_SKIPPED_MASK;
-            }
-        }
-        logBuffer.writeCommand(level, op);
-
+    for (unsigned int i = 0; i < mDisplayListData->displayListOps.size(); i++) {
+        DisplayListOp *op = mDisplayListData->displayListOps[i];
 #if DEBUG_DISPLAY_LIST_OPS_AS_EVENTS
-        Caches::getInstance().eventMark(strlen(OP_NAMES[op]), OP_NAMES[op]);
+        Caches::getInstance().eventMark(strlen(op->name()), op->name());
 #endif
 
-        switch (op) {
-            case DrawGLFunction: {
-                Functor *functor = (Functor *) getInt();
-                DISPLAY_LIST_LOGD("%s%s %p", (char*) indent, OP_NAMES[op], functor);
-                renderer.startMark("GL functor");
-                drawGlStatus |= renderer.callDrawGLFunction(functor, dirty);
-                renderer.endMark();
-            }
-            break;
-            case Save: {
-                int32_t rendererNum = getInt();
-                DISPLAY_LIST_LOGD("%s%s %d", (char*) indent, OP_NAMES[op], rendererNum);
-                renderer.save(rendererNum);
-            }
-            break;
-            case Restore: {
-                DISPLAY_LIST_LOGD("%s%s", (char*) indent, OP_NAMES[op]);
-                renderer.restore();
-            }
-            break;
-            case RestoreToCount: {
-                int32_t restoreCount = saveCount + getInt();
-                DISPLAY_LIST_LOGD("%s%s %d", (char*) indent, OP_NAMES[op], restoreCount);
-                renderer.restoreToCount(restoreCount);
-            }
-            break;
-            case SaveLayer: {
-                float f1 = getFloat();
-                float f2 = getFloat();
-                float f3 = getFloat();
-                float f4 = getFloat();
-                SkPaint* paint = getPaint(renderer);
-                int32_t flags = getInt();
-                DISPLAY_LIST_LOGD("%s%s %.2f, %.2f, %.2f, %.2f, %p, 0x%x", (char*) indent,
-                        OP_NAMES[op], f1, f2, f3, f4, paint, flags);
-                renderer.saveLayer(f1, f2, f3, f4, paint, flags);
-            }
-            break;
-            case SaveLayerAlpha: {
-                float f1 = getFloat();
-                float f2 = getFloat();
-                float f3 = getFloat();
-                float f4 = getFloat();
-                int32_t alpha = getInt();
-                int32_t flags = getInt();
-                DISPLAY_LIST_LOGD("%s%s %.2f, %.2f, %.2f, %.2f, %d, 0x%x", (char*) indent,
-                        OP_NAMES[op], f1, f2, f3, f4, alpha, flags);
-                renderer.saveLayerAlpha(f1, f2, f3, f4, alpha, flags);
-            }
-            break;
-            case Translate: {
-                float f1 = getFloat();
-                float f2 = getFloat();
-                DISPLAY_LIST_LOGD("%s%s %.2f, %.2f", (char*) indent, OP_NAMES[op], f1, f2);
-                renderer.translate(f1, f2);
-            }
-            break;
-            case Rotate: {
-                float rotation = getFloat();
-                DISPLAY_LIST_LOGD("%s%s %.2f", (char*) indent, OP_NAMES[op], rotation);
-                renderer.rotate(rotation);
-            }
-            break;
-            case Scale: {
-                float sx = getFloat();
-                float sy = getFloat();
-                DISPLAY_LIST_LOGD("%s%s %.2f, %.2f", (char*) indent, OP_NAMES[op], sx, sy);
-                renderer.scale(sx, sy);
-            }
-            break;
-            case Skew: {
-                float sx = getFloat();
-                float sy = getFloat();
-                DISPLAY_LIST_LOGD("%s%s %.2f, %.2f", (char*) indent, OP_NAMES[op], sx, sy);
-                renderer.skew(sx, sy);
-            }
-            break;
-            case SetMatrix: {
-                SkMatrix* matrix = getMatrix();
-                DISPLAY_LIST_LOGD("%s%s %p", (char*) indent, OP_NAMES[op], matrix);
-                renderer.setMatrix(matrix);
-            }
-            break;
-            case ConcatMatrix: {
-                SkMatrix* matrix = getMatrix();
-                DISPLAY_LIST_LOGD(
-                        "%s%s %p: [%.2f, %.2f, %.2f] [%.2f, %.2f, %.2f] [%.2f, %.2f, %.2f]",
-                        (char*) indent, OP_NAMES[op], matrix,
-                        matrix->get(0), matrix->get(1), matrix->get(2),
-                        matrix->get(3), matrix->get(4), matrix->get(5),
-                        matrix->get(6), matrix->get(7), matrix->get(8));
-                renderer.concatMatrix(matrix);
-            }
-            break;
-            case ClipRect: {
-                float f1 = getFloat();
-                float f2 = getFloat();
-                float f3 = getFloat();
-                float f4 = getFloat();
-                int32_t regionOp = getInt();
-                DISPLAY_LIST_LOGD("%s%s %.2f, %.2f, %.2f, %.2f, %d", (char*) indent, OP_NAMES[op],
-                        f1, f2, f3, f4, regionOp);
-                renderer.clipRect(f1, f2, f3, f4, (SkRegion::Op) regionOp);
-            }
-            break;
-            case ClipPath: {
-                SkPath* path = getPath();
-                int32_t regionOp = getInt();
-                DISPLAY_LIST_LOGD("%s%s %d", (char*) indent, OP_NAMES[op], regionOp);
-                renderer.clipPath(path, (SkRegion::Op) regionOp);
-            }
-            break;
-            case ClipRegion: {
-                SkRegion* region = getRegion();
-                int32_t regionOp = getInt();
-                DISPLAY_LIST_LOGD("%s%s %d", (char*) indent, OP_NAMES[op], regionOp);
-                renderer.clipRegion(region, (SkRegion::Op) regionOp);
-            }
-            break;
-            case DrawDisplayList: {
-                DisplayList* displayList = getDisplayList();
-                int32_t flags = getInt();
-                DISPLAY_LIST_LOGD("%s%s %p, %dx%d, 0x%x %d", (char*) indent, OP_NAMES[op],
-                        displayList, mWidth, mHeight, flags, level + 1);
-                drawGlStatus |= renderer.drawDisplayList(displayList, dirty, flags, level + 1);
-            }
-            break;
-            case DrawLayer: {
-                int oldAlpha = -1;
-                Layer* layer = (Layer*) getInt();
-                float x = getFloat();
-                float y = getFloat();
-                SkPaint* paint = getPaint(renderer);
-                if (mCaching && mMultipliedAlpha < 255) {
-                    oldAlpha = layer->getAlpha();
-                    layer->setAlpha(mMultipliedAlpha);
-                }
-                DISPLAY_LIST_LOGD("%s%s %p, %.2f, %.2f, %p", (char*) indent, OP_NAMES[op],
-                        layer, x, y, paint);
-                drawGlStatus |= renderer.drawLayer(layer, x, y, paint);
-                if (oldAlpha >= 0) {
-                    layer->setAlpha(oldAlpha);
-                }
-            }
-            break;
-            case DrawBitmap: {
-                int oldAlpha = -1;
-                SkBitmap* bitmap = getBitmap();
-                float x = getFloat();
-                float y = getFloat();
-                SkPaint* paint = getPaint(renderer);
-                if (mCaching && mMultipliedAlpha < 255) {
-                    oldAlpha = paint->getAlpha();
-                    paint->setAlpha(mMultipliedAlpha);
-                }
-                DISPLAY_LIST_LOGD("%s%s %p, %.2f, %.2f, %p", (char*) indent, OP_NAMES[op],
-                        bitmap, x, y, paint);
-                drawGlStatus |= renderer.drawBitmap(bitmap, x, y, paint);
-                if (oldAlpha >= 0) {
-                    paint->setAlpha(oldAlpha);
-                }
-            }
-            break;
-            case DrawBitmapMatrix: {
-                SkBitmap* bitmap = getBitmap();
-                SkMatrix* matrix = getMatrix();
-                SkPaint* paint = getPaint(renderer);
-                DISPLAY_LIST_LOGD("%s%s %p, %p, %p", (char*) indent, OP_NAMES[op],
-                        bitmap, matrix, paint);
-                drawGlStatus |= renderer.drawBitmap(bitmap, matrix, paint);
-            }
-            break;
-            case DrawBitmapRect: {
-                SkBitmap* bitmap = getBitmap();
-                float f1 = getFloat();
-                float f2 = getFloat();
-                float f3 = getFloat();
-                float f4 = getFloat();
-                float f5 = getFloat();
-                float f6 = getFloat();
-                float f7 = getFloat();
-                float f8 = getFloat();
-                SkPaint* paint = getPaint(renderer);
-                DISPLAY_LIST_LOGD("%s%s %p, %.2f, %.2f, %.2f, %.2f, %.2f, %.2f, %.2f, %.2f, %p",
-                        (char*) indent, OP_NAMES[op], bitmap,
-                        f1, f2, f3, f4, f5, f6, f7, f8,paint);
-                drawGlStatus |= renderer.drawBitmap(bitmap, f1, f2, f3, f4, f5, f6, f7, f8, paint);
-            }
-            break;
-            case DrawBitmapData: {
-                SkBitmap* bitmap = getBitmapData();
-                float x = getFloat();
-                float y = getFloat();
-                SkPaint* paint = getPaint(renderer);
-                DISPLAY_LIST_LOGD("%s%s %p, %.2f, %.2f, %p", (char*) indent, OP_NAMES[op],
-                        bitmap, x, y, paint);
-                drawGlStatus |= renderer.drawBitmap(bitmap, x, y, paint);
-            }
-            break;
-            case DrawBitmapMesh: {
-                int32_t verticesCount = 0;
-                uint32_t colorsCount = 0;
-
-                SkBitmap* bitmap = getBitmap();
-                uint32_t meshWidth = getInt();
-                uint32_t meshHeight = getInt();
-                float* vertices = getFloats(verticesCount);
-                bool hasColors = getInt();
-                int32_t* colors = hasColors ? getInts(colorsCount) : NULL;
-                SkPaint* paint = getPaint(renderer);
-
-                DISPLAY_LIST_LOGD("%s%s", (char*) indent, OP_NAMES[op]);
-                drawGlStatus |= renderer.drawBitmapMesh(bitmap, meshWidth, meshHeight, vertices,
-                        colors, paint);
-            }
-            break;
-            case DrawPatch: {
-                int32_t* xDivs = NULL;
-                int32_t* yDivs = NULL;
-                uint32_t* colors = NULL;
-                uint32_t xDivsCount = 0;
-                uint32_t yDivsCount = 0;
-                int8_t numColors = 0;
-
-                SkBitmap* bitmap = getBitmap();
-
-                xDivs = getInts(xDivsCount);
-                yDivs = getInts(yDivsCount);
-                colors = getUInts(numColors);
-
-                float left = getFloat();
-                float top = getFloat();
-                float right = getFloat();
-                float bottom = getFloat();
-
-                int alpha = getInt();
-                SkXfermode::Mode mode = (SkXfermode::Mode) getInt();
-
-                DISPLAY_LIST_LOGD("%s%s", (char*) indent, OP_NAMES[op]);
-                drawGlStatus |= renderer.drawPatch(bitmap, xDivs, yDivs, colors,
-                        xDivsCount, yDivsCount, numColors, left, top, right, bottom,
-                        alpha, mode);
-            }
-            break;
-            case DrawColor: {
-                int32_t color = getInt();
-                int32_t xferMode = getInt();
-                DISPLAY_LIST_LOGD("%s%s 0x%x %d", (char*) indent, OP_NAMES[op], color, xferMode);
-                drawGlStatus |= renderer.drawColor(color, (SkXfermode::Mode) xferMode);
-            }
-            break;
-            case DrawRect: {
-                float f1 = getFloat();
-                float f2 = getFloat();
-                float f3 = getFloat();
-                float f4 = getFloat();
-                SkPaint* paint = getPaint(renderer);
-                DISPLAY_LIST_LOGD("%s%s %.2f, %.2f, %.2f, %.2f, %p", (char*) indent, OP_NAMES[op],
-                        f1, f2, f3, f4, paint);
-                drawGlStatus |= renderer.drawRect(f1, f2, f3, f4, paint);
-            }
-            break;
-            case DrawRoundRect: {
-                float f1 = getFloat();
-                float f2 = getFloat();
-                float f3 = getFloat();
-                float f4 = getFloat();
-                float f5 = getFloat();
-                float f6 = getFloat();
-                SkPaint* paint = getPaint(renderer);
-                DISPLAY_LIST_LOGD("%s%s %.2f, %.2f, %.2f, %.2f, %.2f, %.2f, %p",
-                        (char*) indent, OP_NAMES[op], f1, f2, f3, f4, f5, f6, paint);
-                drawGlStatus |= renderer.drawRoundRect(f1, f2, f3, f4, f5, f6, paint);
-            }
-            break;
-            case DrawCircle: {
-                float f1 = getFloat();
-                float f2 = getFloat();
-                float f3 = getFloat();
-                SkPaint* paint = getPaint(renderer);
-                DISPLAY_LIST_LOGD("%s%s %.2f, %.2f, %.2f, %p",
-                        (char*) indent, OP_NAMES[op], f1, f2, f3, paint);
-                drawGlStatus |= renderer.drawCircle(f1, f2, f3, paint);
-            }
-            break;
-            case DrawOval: {
-                float f1 = getFloat();
-                float f2 = getFloat();
-                float f3 = getFloat();
-                float f4 = getFloat();
-                SkPaint* paint = getPaint(renderer);
-                DISPLAY_LIST_LOGD("%s%s %.2f, %.2f, %.2f, %.2f, %p",
-                        (char*) indent, OP_NAMES[op], f1, f2, f3, f4, paint);
-                drawGlStatus |= renderer.drawOval(f1, f2, f3, f4, paint);
-            }
-            break;
-            case DrawArc: {
-                float f1 = getFloat();
-                float f2 = getFloat();
-                float f3 = getFloat();
-                float f4 = getFloat();
-                float f5 = getFloat();
-                float f6 = getFloat();
-                int32_t i1 = getInt();
-                SkPaint* paint = getPaint(renderer);
-                DISPLAY_LIST_LOGD("%s%s %.2f, %.2f, %.2f, %.2f, %.2f, %.2f, %d, %p",
-                        (char*) indent, OP_NAMES[op], f1, f2, f3, f4, f5, f6, i1, paint);
-                drawGlStatus |= renderer.drawArc(f1, f2, f3, f4, f5, f6, i1 == 1, paint);
-            }
-            break;
-            case DrawPath: {
-                SkPath* path = getPath();
-                SkPaint* paint = getPaint(renderer);
-                DISPLAY_LIST_LOGD("%s%s %p, %p", (char*) indent, OP_NAMES[op], path, paint);
-                drawGlStatus |= renderer.drawPath(path, paint);
-            }
-            break;
-            case DrawLines: {
-                int32_t count = 0;
-                float* points = getFloats(count);
-                SkPaint* paint = getPaint(renderer);
-                DISPLAY_LIST_LOGD("%s%s", (char*) indent, OP_NAMES[op]);
-                drawGlStatus |= renderer.drawLines(points, count, paint);
-            }
-            break;
-            case DrawPoints: {
-                int32_t count = 0;
-                float* points = getFloats(count);
-                SkPaint* paint = getPaint(renderer);
-                DISPLAY_LIST_LOGD("%s%s", (char*) indent, OP_NAMES[op]);
-                drawGlStatus |= renderer.drawPoints(points, count, paint);
-            }
-            break;
-            case DrawTextOnPath: {
-                getText(&text);
-                int32_t count = getInt();
-                SkPath* path = getPath();
-                float hOffset = getFloat();
-                float vOffset = getFloat();
-                SkPaint* paint = getPaint(renderer);
-                DISPLAY_LIST_LOGD("%s%s %s, %d, %d, %p", (char*) indent, OP_NAMES[op],
-                    text.text(), text.length(), count, paint);
-                drawGlStatus |= renderer.drawTextOnPath(text.text(), text.length(), count, path,
-                        hOffset, vOffset, paint);
-            }
-            break;
-            case DrawPosText: {
-                getText(&text);
-                int32_t count = getInt();
-                int32_t positionsCount = 0;
-                float* positions = getFloats(positionsCount);
-                SkPaint* paint = getPaint(renderer);
-                DISPLAY_LIST_LOGD("%s%s %s, %d, %d, %p", (char*) indent,
-                        OP_NAMES[op], text.text(), text.length(), count, paint);
-                drawGlStatus |= renderer.drawPosText(text.text(), text.length(), count,
-                        positions, paint);
-            }
-            break;
-            case DrawText: {
-                getText(&text);
-                int32_t count = getInt();
-                float x = getFloat();
-                float y = getFloat();
-                int32_t positionsCount = 0;
-                float* positions = getFloats(positionsCount);
-                SkPaint* paint = getPaint(renderer);
-                float length = getFloat();
-                DISPLAY_LIST_LOGD("%s%s %s, %d, %d, %.2f, %.2f, %p, %.2f", (char*) indent,
-                        OP_NAMES[op], text.text(), text.length(), count, x, y, paint, length);
-                drawGlStatus |= renderer.drawText(text.text(), text.length(), count,
-                        x, y, positions, paint, length);
-            }
-            break;
-            case DrawRects: {
-                int32_t count = 0;
-                float* rects = getFloats(count);
-                SkPaint* paint = getPaint(renderer);
-                DISPLAY_LIST_LOGD("%s%s %d, %p", (char*) indent, OP_NAMES[op], count, paint);
-                drawGlStatus |= renderer.drawRects(rects, count / 4, paint);
-            }
-            break;
-            case ResetShader: {
-                DISPLAY_LIST_LOGD("%s%s", (char*) indent, OP_NAMES[op]);
-                renderer.resetShader();
-            }
-            break;
-            case SetupShader: {
-                SkiaShader* shader = getShader();
-                DISPLAY_LIST_LOGD("%s%s %p", (char*) indent, OP_NAMES[op], shader);
-                renderer.setupShader(shader);
-            }
-            break;
-            case ResetColorFilter: {
-                DISPLAY_LIST_LOGD("%s%s", (char*) indent, OP_NAMES[op]);
-                renderer.resetColorFilter();
-            }
-            break;
-            case SetupColorFilter: {
-                SkiaColorFilter *colorFilter = getColorFilter();
-                DISPLAY_LIST_LOGD("%s%s %p", (char*) indent, OP_NAMES[op], colorFilter);
-                renderer.setupColorFilter(colorFilter);
-            }
-            break;
-            case ResetShadow: {
-                DISPLAY_LIST_LOGD("%s%s", (char*) indent, OP_NAMES[op]);
-                renderer.resetShadow();
-            }
-            break;
-            case SetupShadow: {
-                float radius = getFloat();
-                float dx = getFloat();
-                float dy = getFloat();
-                int32_t color = getInt();
-                DISPLAY_LIST_LOGD("%s%s %.2f, %.2f, %.2f, 0x%x", (char*) indent, OP_NAMES[op],
-                        radius, dx, dy, color);
-                renderer.setupShadow(radius, dx, dy, color);
-            }
-            break;
-            case ResetPaintFilter: {
-                DISPLAY_LIST_LOGD("%s%s", (char*) indent, OP_NAMES[op]);
-                renderer.resetPaintFilter();
-            }
-            break;
-            case SetupPaintFilter: {
-                int32_t clearBits = getInt();
-                int32_t setBits = getInt();
-                DISPLAY_LIST_LOGD("%s%s 0x%x, 0x%x", (char*) indent, OP_NAMES[op],
-                        clearBits, setBits);
-                renderer.setupPaintFilter(clearBits, setBits);
-            }
-            break;
-            default:
-                DISPLAY_LIST_LOGD("Display List error: op not handled: %s%s",
-                        (char*) indent, OP_NAMES[op]);
-                break;
-        }
+        drawGlStatus |= op->replay(renderer, dirty, flags,
+                saveCount, level, mCaching, mMultipliedAlpha);
+        logBuffer.writeCommand(level, op->name());
     }
 
-    DISPLAY_LIST_LOGD("%s%s %d", (char*) indent, "RestoreToCount", restoreTo);
+    DISPLAY_LIST_LOGD("%*sRestoreToCount %d", level * 2, "", restoreTo);
     renderer.restoreToCount(restoreTo);
     renderer.endMark();
 
-    DISPLAY_LIST_LOGD("%sDone (%p, %s), returning %d", (char*) indent + 2, this, mName.string(),
+    DISPLAY_LIST_LOGD("%*sDone (%p, %s), returning %d", (level + 1) * 2, "", this, mName.string(),
             drawGlStatus);
     return drawGlStatus;
 }
@@ -1387,7 +448,7 @@
 ///////////////////////////////////////////////////////////////////////////////
 
 DisplayListRenderer::DisplayListRenderer():
-        mCaches(Caches::getInstance()), mWriter(MIN_WRITER_SIZE),
+        mCaches(Caches::getInstance()), mDisplayListData(new DisplayListData),
         mTranslateX(0.0f), mTranslateY(0.0f), mHasTranslate(false),
         mHasDrawOps(false), mFunctorCount(0) {
 }
@@ -1397,8 +458,7 @@
 }
 
 void DisplayListRenderer::reset() {
-    mWriter.reset();
-
+    mDisplayListData = new DisplayListData();
     mCaches.resourceCache.lock();
 
     for (size_t i = 0; i < mBitmapResources.size(); i++) {
@@ -1493,7 +553,7 @@
 
 void DisplayListRenderer::finish() {
     insertRestoreToCount();
-    insertTranlate();
+    insertTranslate();
 }
 
 void DisplayListRenderer::interrupt() {
@@ -1504,15 +564,13 @@
 
 status_t DisplayListRenderer::callDrawGLFunction(Functor *functor, Rect& dirty) {
     // Ignore dirty during recording, it matters only when we replay
-    addOp(DisplayList::DrawGLFunction);
-    addInt((int) functor);
+    addDrawOp(new (alloc()) DrawFunctorOp(functor));
     mFunctorCount++;
     return DrawGlInfo::kStatusDone; // No invalidate needed at record-time
 }
 
 int DisplayListRenderer::save(int flags) {
-    addOp(DisplayList::Save);
-    addInt(flags);
+    addStateOp(new (alloc()) SaveOp(flags));
     return OpenGLRenderer::save(flags);
 }
 
@@ -1523,31 +581,25 @@
     }
 
     mRestoreSaveCount--;
-    insertTranlate();
+    insertTranslate();
     OpenGLRenderer::restore();
 }
 
 void DisplayListRenderer::restoreToCount(int saveCount) {
     mRestoreSaveCount = saveCount;
-    insertTranlate();
+    insertTranslate();
     OpenGLRenderer::restoreToCount(saveCount);
 }
 
 int DisplayListRenderer::saveLayer(float left, float top, float right, float bottom,
         SkPaint* p, int flags) {
-    addOp(DisplayList::SaveLayer);
-    addBounds(left, top, right, bottom);
-    addPaint(p);
-    addInt(flags);
+    addStateOp(new (alloc()) SaveLayerOp(left, top, right, bottom, p, flags));
     return OpenGLRenderer::save(flags);
 }
 
 int DisplayListRenderer::saveLayerAlpha(float left, float top, float right, float bottom,
         int alpha, int flags) {
-    addOp(DisplayList::SaveLayerAlpha);
-    addBounds(left, top, right, bottom);
-    addInt(alpha);
-    addInt(flags);
+    addStateOp(new (alloc()) SaveLayerAlphaOp(left, top, right, bottom, alpha, flags));
     return OpenGLRenderer::save(flags);
 }
 
@@ -1560,54 +612,47 @@
 }
 
 void DisplayListRenderer::rotate(float degrees) {
-    addOp(DisplayList::Rotate);
-    addFloat(degrees);
+    addStateOp(new (alloc()) RotateOp(degrees));
     OpenGLRenderer::rotate(degrees);
 }
 
 void DisplayListRenderer::scale(float sx, float sy) {
-    addOp(DisplayList::Scale);
-    addPoint(sx, sy);
+    addStateOp(new (alloc()) ScaleOp(sx, sy));
     OpenGLRenderer::scale(sx, sy);
 }
 
 void DisplayListRenderer::skew(float sx, float sy) {
-    addOp(DisplayList::Skew);
-    addPoint(sx, sy);
+    addStateOp(new (alloc()) SkewOp(sx, sy));
     OpenGLRenderer::skew(sx, sy);
 }
 
 void DisplayListRenderer::setMatrix(SkMatrix* matrix) {
-    addOp(DisplayList::SetMatrix);
-    addMatrix(matrix);
+    matrix = refMatrix(matrix);
+    addStateOp(new (alloc()) SetMatrixOp(matrix));
     OpenGLRenderer::setMatrix(matrix);
 }
 
 void DisplayListRenderer::concatMatrix(SkMatrix* matrix) {
-    addOp(DisplayList::ConcatMatrix);
-    addMatrix(matrix);
+    matrix = refMatrix(matrix);
+    addStateOp(new (alloc()) ConcatMatrixOp(matrix));
     OpenGLRenderer::concatMatrix(matrix);
 }
 
 bool DisplayListRenderer::clipRect(float left, float top, float right, float bottom,
         SkRegion::Op op) {
-    addOp(DisplayList::ClipRect);
-    addBounds(left, top, right, bottom);
-    addInt(op);
+    addStateOp(new (alloc()) ClipRectOp(left, top, right, bottom, op));
     return OpenGLRenderer::clipRect(left, top, right, bottom, op);
 }
 
 bool DisplayListRenderer::clipPath(SkPath* path, SkRegion::Op op) {
-    addOp(DisplayList::ClipPath);
-    addPath(path);
-    addInt(op);
+    path = refPath(path);
+    addStateOp(new (alloc()) ClipPathOp(path, op));
     return OpenGLRenderer::clipPath(path, op);
 }
 
 bool DisplayListRenderer::clipRegion(SkRegion* region, SkRegion::Op op) {
-    addOp(DisplayList::ClipRegion);
-    addRegion(region);
-    addInt(op);
+    region = refRegion(region);
+    addStateOp(new (alloc()) ClipRegionOp(region, op));
     return OpenGLRenderer::clipRegion(region, op);
 }
 
@@ -1616,84 +661,71 @@
     // dirty is an out parameter and should not be recorded,
     // it matters only when replaying the display list
 
-    addOp(DisplayList::DrawDisplayList);
-    addDisplayList(displayList);
-    addInt(flags);
+    // TODO: To be safe, the display list should be ref-counted in the
+    //       resources cache, but we rely on the caller (UI toolkit) to
+    //       do the right thing for now
+
+    addDrawOp(new (alloc()) DrawDisplayListOp(displayList, flags));
     return DrawGlInfo::kStatusDone;
 }
 
 status_t DisplayListRenderer::drawLayer(Layer* layer, float x, float y, SkPaint* paint) {
-    addOp(DisplayList::DrawLayer);
-    addLayer(layer);
-    addPoint(x, y);
-    addPaint(paint);
+    mLayers.add(layer);
+    mCaches.resourceCache.incrementRefcount(layer);
+    paint = refPaint(paint);
+
+    addDrawOp(new (alloc()) DrawLayerOp(layer, x, y, paint));
     return DrawGlInfo::kStatusDone;
 }
 
 status_t DisplayListRenderer::drawBitmap(SkBitmap* bitmap, float left, float top, SkPaint* paint) {
-    const bool reject = quickRejectNoScissor(left, top,
-            left + bitmap->width(), top + bitmap->height());
-    uint32_t* location = addOp(DisplayList::DrawBitmap, reject);
-    addBitmap(bitmap);
-    addPoint(left, top);
-    addPaint(paint);
-    addSkip(location);
+    bitmap = refBitmap(bitmap);
+    paint = refPaint(paint);
+
+    addDrawOp(new (alloc()) DrawBitmapOp(bitmap, left, top, paint));
     return DrawGlInfo::kStatusDone;
 }
 
 status_t DisplayListRenderer::drawBitmap(SkBitmap* bitmap, SkMatrix* matrix, SkPaint* paint) {
-    Rect r(0.0f, 0.0f, bitmap->width(), bitmap->height());
-    const mat4 transform(*matrix);
-    transform.mapRect(r);
+    bitmap = refBitmap(bitmap);
+    matrix = refMatrix(matrix);
+    paint = refPaint(paint);
 
-    const bool reject = quickRejectNoScissor(r.left, r.top, r.right, r.bottom);
-    uint32_t* location = addOp(DisplayList::DrawBitmapMatrix, reject);
-    addBitmap(bitmap);
-    addMatrix(matrix);
-    addPaint(paint);
-    addSkip(location);
+    addDrawOp(new (alloc()) DrawBitmapMatrixOp(bitmap, matrix, paint));
     return DrawGlInfo::kStatusDone;
 }
 
 status_t DisplayListRenderer::drawBitmap(SkBitmap* bitmap, float srcLeft, float srcTop,
         float srcRight, float srcBottom, float dstLeft, float dstTop,
         float dstRight, float dstBottom, SkPaint* paint) {
-    const bool reject = quickRejectNoScissor(dstLeft, dstTop, dstRight, dstBottom);
-    uint32_t* location = addOp(DisplayList::DrawBitmapRect, reject);
-    addBitmap(bitmap);
-    addBounds(srcLeft, srcTop, srcRight, srcBottom);
-    addBounds(dstLeft, dstTop, dstRight, dstBottom);
-    addPaint(paint);
-    addSkip(location);
+    bitmap = refBitmap(bitmap);
+    paint = refPaint(paint);
+
+    addDrawOp(new (alloc()) DrawBitmapRectOp(bitmap,
+                    srcLeft, srcTop, srcRight, srcBottom,
+                    dstLeft, dstTop, dstRight, dstBottom, paint));
     return DrawGlInfo::kStatusDone;
 }
 
 status_t DisplayListRenderer::drawBitmapData(SkBitmap* bitmap, float left, float top,
         SkPaint* paint) {
-    const bool reject = quickRejectNoScissor(left, top,
-            left + bitmap->width(), top + bitmap->height());
-    uint32_t* location = addOp(DisplayList::DrawBitmapData, reject);
-    addBitmapData(bitmap);
-    addPoint(left, top);
-    addPaint(paint);
-    addSkip(location);
+    bitmap = refBitmapData(bitmap);
+    paint = refPaint(paint);
+
+    addDrawOp(new (alloc()) DrawBitmapDataOp(bitmap, left, top, paint));
     return DrawGlInfo::kStatusDone;
 }
 
 status_t DisplayListRenderer::drawBitmapMesh(SkBitmap* bitmap, int meshWidth, int meshHeight,
         float* vertices, int* colors, SkPaint* paint) {
-    addOp(DisplayList::DrawBitmapMesh);
-    addBitmap(bitmap);
-    addInt(meshWidth);
-    addInt(meshHeight);
-    addFloats(vertices, (meshWidth + 1) * (meshHeight + 1) * 2);
-    if (colors) {
-        addInt(1);
-        addInts(colors, (meshWidth + 1) * (meshHeight + 1));
-    } else {
-        addInt(0);
-    }
-    addPaint(paint);
+    int count = (meshWidth + 1) * (meshHeight + 1) * 2;
+    bitmap = refBitmap(bitmap);
+    vertices = refBuffer<float>(vertices, count);
+    paint = refPaint(paint);
+    colors = refBuffer<int>(colors, count);
+
+    addDrawOp(new (alloc()) DrawBitmapMeshOp(bitmap, meshWidth, meshHeight,
+                    vertices, colors, paint));
     return DrawGlInfo::kStatusDone;
 }
 
@@ -1704,132 +736,114 @@
     SkXfermode::Mode mode;
     OpenGLRenderer::getAlphaAndModeDirect(paint, &alpha, &mode);
 
-    const bool reject = quickRejectNoScissor(left, top, right, bottom);
-    uint32_t* location = addOp(DisplayList::DrawPatch, reject);
-    addBitmap(bitmap);
-    addInts(xDivs, width);
-    addInts(yDivs, height);
-    addUInts(colors, numColors);
-    addBounds(left, top, right, bottom);
-    addInt(alpha);
-    addInt(mode);
-    addSkip(location);
+    bitmap = refBitmap(bitmap);
+    xDivs = refBuffer<int>(xDivs, width);
+    yDivs = refBuffer<int>(yDivs, height);
+    colors = refBuffer<uint32_t>(colors, numColors);
+
+    addDrawOp(new (alloc()) DrawPatchOp(bitmap, xDivs, yDivs, colors, width, height, numColors,
+                    left, top, right, bottom, alpha, mode));
     return DrawGlInfo::kStatusDone;
 }
 
 status_t DisplayListRenderer::drawColor(int color, SkXfermode::Mode mode) {
-    addOp(DisplayList::DrawColor);
-    addInt(color);
-    addInt(mode);
+    addDrawOp(new (alloc()) DrawColorOp(color, mode));
     return DrawGlInfo::kStatusDone;
 }
 
 status_t DisplayListRenderer::drawRect(float left, float top, float right, float bottom,
         SkPaint* paint) {
-    const bool reject = paint->getStyle() == SkPaint::kFill_Style &&
-            quickRejectNoScissor(left, top, right, bottom);
-    uint32_t* location = addOp(DisplayList::DrawRect, reject);
-    addBounds(left, top, right, bottom);
-    addPaint(paint);
-    addSkip(location);
+    paint = refPaint(paint);
+    addDrawOp(new (alloc()) DrawRectOp(left, top, right, bottom, paint));
     return DrawGlInfo::kStatusDone;
 }
 
 status_t DisplayListRenderer::drawRoundRect(float left, float top, float right, float bottom,
         float rx, float ry, SkPaint* paint) {
-    const bool reject = paint->getStyle() == SkPaint::kFill_Style &&
-            quickRejectNoScissor(left, top, right, bottom);
-    uint32_t* location = addOp(DisplayList::DrawRoundRect, reject);
-    addBounds(left, top, right, bottom);
-    addPoint(rx, ry);
-    addPaint(paint);
-    addSkip(location);
+    paint = refPaint(paint);
+    addDrawOp(new (alloc()) DrawRoundRectOp(left, top, right, bottom, rx, ry, paint));
     return DrawGlInfo::kStatusDone;
 }
 
 status_t DisplayListRenderer::drawCircle(float x, float y, float radius, SkPaint* paint) {
-    addOp(DisplayList::DrawCircle);
-    addPoint(x, y);
-    addFloat(radius);
-    addPaint(paint);
+    paint = refPaint(paint);
+    addDrawOp(new (alloc()) DrawCircleOp(x, y, radius, paint));
     return DrawGlInfo::kStatusDone;
 }
 
 status_t DisplayListRenderer::drawOval(float left, float top, float right, float bottom,
         SkPaint* paint) {
-    addOp(DisplayList::DrawOval);
-    addBounds(left, top, right, bottom);
-    addPaint(paint);
+    paint = refPaint(paint);
+    addDrawOp(new (alloc()) DrawOvalOp(left, top, right, bottom, paint));
     return DrawGlInfo::kStatusDone;
 }
 
 status_t DisplayListRenderer::drawArc(float left, float top, float right, float bottom,
         float startAngle, float sweepAngle, bool useCenter, SkPaint* paint) {
-    addOp(DisplayList::DrawArc);
-    addBounds(left, top, right, bottom);
-    addPoint(startAngle, sweepAngle);
-    addInt(useCenter ? 1 : 0);
-    addPaint(paint);
+    paint = refPaint(paint);
+    addDrawOp(new (alloc()) DrawArcOp(left, top, right, bottom,
+                    startAngle, sweepAngle, useCenter, paint));
     return DrawGlInfo::kStatusDone;
 }
 
 status_t DisplayListRenderer::drawPath(SkPath* path, SkPaint* paint) {
-    float left, top, offset;
-    uint32_t width, height;
-    computePathBounds(path, paint, left, top, offset, width, height);
+    path = refPath(path);
+    paint = refPaint(paint);
 
-    left -= offset;
-    top -= offset;
-
-    const bool reject = quickRejectNoScissor(left, top, left + width, top + height);
-    uint32_t* location = addOp(DisplayList::DrawPath, reject);
-    addPath(path);
-    addPaint(paint);
-    addSkip(location);
+    addDrawOp(new (alloc()) DrawPathOp(path, paint));
     return DrawGlInfo::kStatusDone;
 }
 
 status_t DisplayListRenderer::drawLines(float* points, int count, SkPaint* paint) {
-    addOp(DisplayList::DrawLines);
-    addFloats(points, count);
-    addPaint(paint);
+    points = refBuffer<float>(points, count);
+    paint = refPaint(paint);
+
+    addDrawOp(new (alloc()) DrawLinesOp(points, count, paint));
     return DrawGlInfo::kStatusDone;
 }
 
 status_t DisplayListRenderer::drawPoints(float* points, int count, SkPaint* paint) {
-    addOp(DisplayList::DrawPoints);
-    addFloats(points, count);
-    addPaint(paint);
+    points = refBuffer<float>(points, count);
+    paint = refPaint(paint);
+
+    addDrawOp(new (alloc()) DrawPointsOp(points, count, paint));
     return DrawGlInfo::kStatusDone;
 }
 
 status_t DisplayListRenderer::drawTextOnPath(const char* text, int bytesCount, int count,
         SkPath* path, float hOffset, float vOffset, SkPaint* paint) {
     if (!text || count <= 0) return DrawGlInfo::kStatusDone;
-    addOp(DisplayList::DrawTextOnPath);
-    addText(text, bytesCount);
-    addInt(count);
-    addPath(path);
-    addFloat(hOffset);
-    addFloat(vOffset);
+
     paint->setAntiAlias(true);
-    SkPaint* addedPaint = addPaint(paint);
-    FontRenderer& fontRenderer = mCaches.fontRenderer->getFontRenderer(addedPaint);
-    fontRenderer.precache(addedPaint, text, count, *mSnapshot->transform);
+    text = refText(text, bytesCount);
+    path = refPath(path);
+    paint = refPaint(paint);
+
+    DrawOp* op = new (alloc()) DrawTextOnPathOp(text, bytesCount, count, path,
+            hOffset, vOffset, paint);
+    if (addDrawOp(op)) {
+        // precache if draw operation is visible
+        FontRenderer& fontRenderer = mCaches.fontRenderer->getFontRenderer(paint);
+        fontRenderer.precache(paint, text, count, *mSnapshot->transform);
+    }
     return DrawGlInfo::kStatusDone;
 }
 
 status_t DisplayListRenderer::drawPosText(const char* text, int bytesCount, int count,
         const float* positions, SkPaint* paint) {
     if (!text || count <= 0) return DrawGlInfo::kStatusDone;
-    addOp(DisplayList::DrawPosText);
-    addText(text, bytesCount);
-    addInt(count);
-    addFloats(positions, count * 2);
+
     paint->setAntiAlias(true);
-    SkPaint* addedPaint = addPaint(paint);
-    FontRenderer& fontRenderer = mCaches.fontRenderer->getFontRenderer(addedPaint);
-    fontRenderer.precache(addedPaint, text, count, *mSnapshot->transform);
+    text = refText(text, bytesCount);
+    positions = refBuffer<float>(positions, count * 2);
+    paint = refPaint(paint);
+
+    DrawOp* op = new (alloc()) DrawPosTextOp(text, bytesCount, count, positions, paint);
+    if (addDrawOp(op)) {
+        // precache if draw operation is visible
+        FontRenderer& fontRenderer = mCaches.fontRenderer->getFontRenderer(paint);
+        fontRenderer.precache(paint, text, count, *mSnapshot->transform);
+    }
     return DrawGlInfo::kStatusDone;
 }
 
@@ -1847,75 +861,96 @@
     paint->setAntiAlias(true);
     if (length < 0.0f) length = paint->measureText(text, bytesCount);
 
-    bool reject = false;
-    if (CC_LIKELY(paint->getTextAlign() == SkPaint::kLeft_Align)) {
-        SkPaint::FontMetrics metrics;
-        paint->getFontMetrics(&metrics, 0.0f);
-        reject = quickRejectNoScissor(x, y + metrics.fTop, x + length, y + metrics.fBottom);
-    }
+    text = refText(text, bytesCount);
+    positions = refBuffer<float>(positions, count * 2);
+    paint = refPaint(paint);
 
-    uint32_t* location = addOp(DisplayList::DrawText, reject);
-    addText(text, bytesCount);
-    addInt(count);
-    addFloat(x);
-    addFloat(y);
-    addFloats(positions, count * 2);
-    SkPaint* addedPaint = addPaint(paint);
-    if (!reject) {
-        FontRenderer& fontRenderer = mCaches.fontRenderer->getFontRenderer(addedPaint);
-        fontRenderer.precache(addedPaint, text, count, *mSnapshot->transform);
+    DrawOp* op = new (alloc()) DrawTextOp(text, bytesCount, count, x, y, positions, paint, length);
+    if (addDrawOp(op)) {
+        // precache if draw operation is visible
+        FontRenderer& fontRenderer = mCaches.fontRenderer->getFontRenderer(paint);
+        fontRenderer.precache(paint, text, count, *mSnapshot->transform);
     }
-    addFloat(length);
-    addSkip(location);
     return DrawGlInfo::kStatusDone;
 }
 
 status_t DisplayListRenderer::drawRects(const float* rects, int count, SkPaint* paint) {
     if (count <= 0) return DrawGlInfo::kStatusDone;
 
-    addOp(DisplayList::DrawRects);
-    addFloats(rects, count * 4);
-    addPaint(paint);
+    rects = refBuffer<float>(rects, count);
+    paint = refPaint(paint);
+    addDrawOp(new (alloc()) DrawRectsOp(rects, count, paint));
     return DrawGlInfo::kStatusDone;
 }
 
 void DisplayListRenderer::resetShader() {
-    addOp(DisplayList::ResetShader);
+    addStateOp(new (alloc()) ResetShaderOp());
 }
 
 void DisplayListRenderer::setupShader(SkiaShader* shader) {
-    addOp(DisplayList::SetupShader);
-    addShader(shader);
+    shader = refShader(shader);
+    addStateOp(new (alloc()) SetupShaderOp(shader));
 }
 
 void DisplayListRenderer::resetColorFilter() {
-    addOp(DisplayList::ResetColorFilter);
+    addStateOp(new (alloc()) ResetColorFilterOp());
 }
 
 void DisplayListRenderer::setupColorFilter(SkiaColorFilter* filter) {
-    addOp(DisplayList::SetupColorFilter);
-    addColorFilter(filter);
+    filter = refColorFilter(filter);
+    addStateOp(new (alloc()) SetupColorFilterOp(filter));
 }
 
 void DisplayListRenderer::resetShadow() {
-    addOp(DisplayList::ResetShadow);
+    addStateOp(new (alloc()) ResetShadowOp());
 }
 
 void DisplayListRenderer::setupShadow(float radius, float dx, float dy, int color) {
-    addOp(DisplayList::SetupShadow);
-    addFloat(radius);
-    addPoint(dx, dy);
-    addInt(color);
+    addStateOp(new (alloc()) SetupShadowOp(radius, dx, dy, color));
 }
 
 void DisplayListRenderer::resetPaintFilter() {
-    addOp(DisplayList::ResetPaintFilter);
+    addStateOp(new (alloc()) ResetPaintFilterOp());
 }
 
 void DisplayListRenderer::setupPaintFilter(int clearBits, int setBits) {
-    addOp(DisplayList::SetupPaintFilter);
-    addInt(clearBits);
-    addInt(setBits);
+    addStateOp(new (alloc()) SetupPaintFilterOp(clearBits, setBits));
+}
+
+void DisplayListRenderer::insertRestoreToCount() {
+    if (mRestoreSaveCount >= 0) {
+        DisplayListOp* op = new (alloc()) RestoreToCountOp(mRestoreSaveCount);
+        mDisplayListData->displayListOps.add(op);
+        mRestoreSaveCount = -1;
+    }
+}
+
+void DisplayListRenderer::insertTranslate() {
+    if (mHasTranslate) {
+        if (mTranslateX != 0.0f || mTranslateY != 0.0f) {
+            DisplayListOp* op = new (alloc()) TranslateOp(mTranslateX, mTranslateY);
+            mDisplayListData->displayListOps.add(op);
+            mTranslateX = mTranslateY = 0.0f;
+        }
+        mHasTranslate = false;
+    }
+}
+
+void DisplayListRenderer::addStateOp(StateOp* op) {
+    addOpInternal(op);
+}
+
+bool DisplayListRenderer::addDrawOp(DrawOp* op) {
+    bool rejected = false;
+    Rect localBounds;
+    if (op->getLocalBounds(localBounds)) {
+        rejected = quickRejectNoScissor(localBounds.left, localBounds.top,
+                localBounds.right, localBounds.bottom);
+        op->setQuickRejected(rejected);
+    }
+    mHasDrawOps = true;
+    addOpInternal(op);
+    return !rejected;
 }
 
 }; // namespace uirenderer
diff --git a/libs/hwui/DisplayListRenderer.h b/libs/hwui/DisplayListRenderer.h
index f55f1f2..b25288b 100644
--- a/libs/hwui/DisplayListRenderer.h
+++ b/libs/hwui/DisplayListRenderer.h
@@ -31,6 +31,7 @@
 
 #include "DisplayListLogBuffer.h"
 #include "OpenGLRenderer.h"
+#include "utils/LinearAllocator.h"
 
 namespace android {
 namespace uirenderer {
@@ -60,6 +61,18 @@
 ///////////////////////////////////////////////////////////////////////////////
 
 class DisplayListRenderer;
+class DisplayListOp;
+class DrawOp;
+class StateOp;
+
+/**
+ * Refcounted structure that holds data used in display list stream
+ */
+class DisplayListData: public LightRefBase<DisplayListData> {
+public:
+    LinearAllocator allocator;
+    Vector<DisplayListOp*> displayListOps;
+};
 
 /**
  * Replays recorded drawing commands.
@@ -69,66 +82,13 @@
     DisplayList(const DisplayListRenderer& recorder);
     ANDROID_API ~DisplayList();
 
-    // IMPORTANT: Update the intialization of OP_NAMES in the .cpp file
-    //            when modifying this file
-    enum Op {
-        // Non-drawing operations
-        Save = 0,
-        Restore,
-        RestoreToCount,
-        SaveLayer,
-        SaveLayerAlpha,
-        Translate,
-        Rotate,
-        Scale,
-        Skew,
-        SetMatrix,
-        ConcatMatrix,
-        ClipRect,
-        ClipPath,
-        ClipRegion,
-        // Drawing operations
-        DrawDisplayList,
-        DrawLayer,
-        DrawBitmap,
-        DrawBitmapMatrix,
-        DrawBitmapRect,
-        DrawBitmapData,
-        DrawBitmapMesh,
-        DrawPatch,
-        DrawColor,
-        DrawRect,
-        DrawRoundRect,
-        DrawCircle,
-        DrawOval,
-        DrawArc,
-        DrawPath,
-        DrawLines,
-        DrawPoints,
-        DrawTextOnPath,
-        DrawPosText,
-        DrawText,
-        DrawRects,
-        ResetShader,
-        SetupShader,
-        ResetColorFilter,
-        SetupColorFilter,
-        ResetShadow,
-        SetupShadow,
-        ResetPaintFilter,
-        SetupPaintFilter,
-        DrawGLFunction,
-    };
-
     // See flags defined in DisplayList.java
     enum ReplayFlag {
         kReplayFlag_ClipChildren = 0x1
     };
 
-    static const char* OP_NAMES[];
-
     void setViewProperties(OpenGLRenderer& renderer, uint32_t level);
-    void outputViewProperties(OpenGLRenderer& renderer, char* indent);
+    void outputViewProperties(uint32_t level);
 
     ANDROID_API size_t getSize();
     ANDROID_API static void destroyDisplayListDeferred(DisplayList* displayList);
@@ -138,7 +98,7 @@
 
     status_t replay(OpenGLRenderer& renderer, Rect& dirty, int32_t flags, uint32_t level = 0);
 
-    void output(OpenGLRenderer& renderer, uint32_t level = 0);
+    void output(uint32_t level = 0);
 
     ANDROID_API void reset();
 
@@ -423,78 +383,6 @@
         const char* mText;
     };
 
-    SkBitmap* getBitmap() {
-        return (SkBitmap*) getInt();
-    }
-
-    SkBitmap* getBitmapData() {
-        return (SkBitmap*) getInt();
-    }
-
-    SkiaShader* getShader() {
-        return (SkiaShader*) getInt();
-    }
-
-    SkiaColorFilter* getColorFilter() {
-        return (SkiaColorFilter*) getInt();
-    }
-
-    inline int32_t getIndex() {
-        return mReader.readInt();
-    }
-
-    inline int32_t getInt() {
-        return mReader.readInt();
-    }
-
-    inline uint32_t getUInt() {
-        return mReader.readU32();
-    }
-
-    SkMatrix* getMatrix() {
-        return (SkMatrix*) getInt();
-    }
-
-    SkPath* getPath() {
-        return (SkPath*) getInt();
-    }
-
-    SkRegion* getRegion() {
-        return (SkRegion*) getInt();
-    }
-
-    SkPaint* getPaint(OpenGLRenderer& renderer) {
-        return renderer.filterPaint((SkPaint*) getInt());
-    }
-
-    DisplayList* getDisplayList() {
-        return (DisplayList*) getInt();
-    }
-
-    inline float getFloat() {
-        return mReader.readScalar();
-    }
-
-    int32_t* getInts(uint32_t& count) {
-        count = getInt();
-        return (int32_t*) mReader.skip(count * sizeof(int32_t));
-    }
-
-    uint32_t* getUInts(int8_t& count) {
-        count = getInt();
-        return (uint32_t*) mReader.skip(count * sizeof(uint32_t));
-    }
-
-    float* getFloats(int32_t& count) {
-        count = getInt();
-        return (float*) mReader.skip(count * sizeof(float));
-    }
-
-    void getText(TextContainer* text) {
-        size_t length = text->mByteLength = getInt();
-        text->mText = (const char*) mReader.skip(length);
-    }
-
     Vector<SkBitmap*> mBitmapResources;
     Vector<SkBitmap*> mOwnedBitmapResources;
     Vector<SkiaColorFilter*> mFilterResources;
@@ -507,7 +395,7 @@
     Vector<SkiaShader*> mShaders;
     Vector<Layer*> mLayers;
 
-    mutable SkFlattenableReadBuffer mReader;
+    sp<DisplayListData> mDisplayListData;
 
     size_t mSize;
 
@@ -634,8 +522,8 @@
 
     ANDROID_API void reset();
 
-    const SkWriter32& writeStream() const {
-        return mWriter;
+    sp<DisplayListData> getDisplayListData() const {
+        return mDisplayListData;
     }
 
     const Vector<SkBitmap*>& getBitmapResources() const {
@@ -683,102 +571,32 @@
     }
 
 private:
-    void insertRestoreToCount() {
-        if (mRestoreSaveCount >= 0) {
-            mWriter.writeInt(DisplayList::RestoreToCount);
-            addInt(mRestoreSaveCount);
-            mRestoreSaveCount = -1;
-        }
-    }
+    void insertRestoreToCount();
+    void insertTranslate();
 
-    void insertTranlate() {
-        if (mHasTranslate) {
-            if (mTranslateX != 0.0f || mTranslateY != 0.0f) {
-                mWriter.writeInt(DisplayList::Translate);
-                addPoint(mTranslateX, mTranslateY);
-                mTranslateX = mTranslateY = 0.0f;
-            }
-            mHasTranslate = false;
-        }
-    }
-
-    inline void addOp(const DisplayList::Op drawOp) {
+    LinearAllocator& alloc() { return mDisplayListData->allocator; }
+    void addStateOp(StateOp* op);
+    bool addDrawOp(DrawOp* op); // returns true if op not rejected
+    void addOpInternal(DisplayListOp* op) {
         insertRestoreToCount();
-        insertTranlate();
-        mWriter.writeInt(drawOp);
-        mHasDrawOps = mHasDrawOps || drawOp >= DisplayList::DrawDisplayList;
+        insertTranslate();
+        mDisplayListData->displayListOps.add(op);
     }
 
-    uint32_t* addOp(const DisplayList::Op drawOp, const bool reject) {
-        insertRestoreToCount();
-        insertTranlate();
-        mHasDrawOps = mHasDrawOps || drawOp >= DisplayList::DrawDisplayList;
-        if (reject) {
-            mWriter.writeInt(OP_MAY_BE_SKIPPED_MASK | drawOp);
-            mWriter.writeInt(0xdeaddead);
-            mBufferSize = mWriter.size();
-            return mWriter.peek32(mBufferSize - sizeof(int32_t));
-        }
-        mWriter.writeInt(drawOp);
-        return NULL;
+    template<class T>
+    inline T* refBuffer(const T* srcBuffer, int32_t count) {
+        if (srcBuffer == NULL) return NULL;
+        T* dstBuffer = (T*) mDisplayListData->allocator.alloc(count * sizeof(T));
+        memcpy(dstBuffer, srcBuffer, count * sizeof(T));
+        return dstBuffer;
     }
 
-    inline void addSkip(uint32_t* location) {
-        if (location) {
-            *location = (int32_t) (mWriter.size() - mBufferSize);
-        }
+    inline char* refText(const char* text, size_t byteLength) {
+        return (char*) refBuffer<uint8_t>((uint8_t*)text, byteLength);
     }
 
-    inline void addInt(int32_t value) {
-        mWriter.writeInt(value);
-    }
-
-    inline void addSize(uint32_t w, uint32_t h) {
-        mWriter.writeInt(w);
-        mWriter.writeInt(h);
-    }
-
-    void addInts(const int32_t* values, uint32_t count) {
-        mWriter.writeInt(count);
-        mWriter.write(values, count * sizeof(int32_t));
-    }
-
-    void addUInts(const uint32_t* values, int8_t count) {
-        mWriter.writeInt(count);
-        mWriter.write(values, count * sizeof(uint32_t));
-    }
-
-    inline void addFloat(float value) {
-        mWriter.writeScalar(value);
-    }
-
-    void addFloats(const float* values, int32_t count) {
-        mWriter.writeInt(count);
-        mWriter.write(values, count * sizeof(float));
-    }
-
-    inline void addPoint(float x, float y) {
-        mWriter.writeScalar(x);
-        mWriter.writeScalar(y);
-    }
-
-    inline void addBounds(float left, float top, float right, float bottom) {
-        mWriter.writeScalar(left);
-        mWriter.writeScalar(top);
-        mWriter.writeScalar(right);
-        mWriter.writeScalar(bottom);
-    }
-
-    inline void addText(const void* text, size_t byteLength) {
-        mWriter.writeInt(byteLength);
-        mWriter.writePad(text, byteLength);
-    }
-
-    inline void addPath(SkPath* path) {
-        if (!path) {
-            addInt((int) NULL);
-            return;
-        }
+    inline SkPath* refPath(SkPath* path) {
+        if (!path) return NULL;
 
         SkPath* pathCopy = mPathMap.valueFor(path);
         if (pathCopy == NULL || pathCopy->getGenerationID() != path->getGenerationID()) {
@@ -792,13 +610,11 @@
             mCaches.resourceCache.incrementRefcount(path);
             mSourcePaths.add(path);
         }
-
-        addInt((int) pathCopy);
+        return pathCopy;
     }
 
-    inline SkPaint* addPaint(SkPaint* paint) {
+    inline SkPaint* refPaint(SkPaint* paint) {
         if (!paint) {
-            addInt((int) NULL);
             return paint;
         }
 
@@ -810,14 +626,11 @@
             mPaints.add(paintCopy);
         }
 
-        addInt((int) paintCopy);
-
         return paintCopy;
     }
 
-    inline SkRegion* addRegion(SkRegion* region) {
+    inline SkRegion* refRegion(SkRegion* region) {
         if (!region) {
-            addInt((int) NULL);
             return region;
         }
 
@@ -830,53 +643,35 @@
             mRegions.add(regionCopy);
         }
 
-        addInt((int) regionCopy);
-
         return regionCopy;
     }
 
-    inline void addDisplayList(DisplayList* displayList) {
-        // TODO: To be safe, the display list should be ref-counted in the
-        //       resources cache, but we rely on the caller (UI toolkit) to
-        //       do the right thing for now
-        addInt((int) displayList);
-    }
-
-    inline void addMatrix(SkMatrix* matrix) {
+    inline SkMatrix* refMatrix(SkMatrix* matrix) {
         // Copying the matrix is cheap and prevents against the user changing the original
         // matrix before the operation that uses it
         SkMatrix* copy = new SkMatrix(*matrix);
-        addInt((int) copy);
         mMatrices.add(copy);
+        return copy;
     }
 
-    inline void addLayer(Layer* layer) {
-        addInt((int) layer);
-        mLayers.add(layer);
-        mCaches.resourceCache.incrementRefcount(layer);
-    }
-
-    inline void addBitmap(SkBitmap* bitmap) {
+    inline SkBitmap* refBitmap(SkBitmap* bitmap) {
         // Note that this assumes the bitmap is immutable. There are cases this won't handle
         // correctly, such as creating the bitmap from scratch, drawing with it, changing its
         // contents, and drawing again. The only fix would be to always copy it the first time,
         // which doesn't seem worth the extra cycles for this unlikely case.
-        addInt((int) bitmap);
         mBitmapResources.add(bitmap);
         mCaches.resourceCache.incrementRefcount(bitmap);
+        return bitmap;
     }
 
-    void addBitmapData(SkBitmap* bitmap) {
-        addInt((int) bitmap);
+    inline SkBitmap* refBitmapData(SkBitmap* bitmap) {
         mOwnedBitmapResources.add(bitmap);
         mCaches.resourceCache.incrementRefcount(bitmap);
+        return bitmap;
     }
 
-    inline void addShader(SkiaShader* shader) {
-        if (!shader) {
-            addInt((int) NULL);
-            return;
-        }
+    inline SkiaShader* refShader(SkiaShader* shader) {
+        if (!shader) return NULL;
 
         SkiaShader* shaderCopy = mShaderMap.valueFor(shader);
         // TODO: We also need to handle generation ID changes in compose shaders
@@ -887,14 +682,13 @@
             mShaders.add(shaderCopy);
             mCaches.resourceCache.incrementRefcount(shaderCopy);
         }
-
-        addInt((int) shaderCopy);
+        return shaderCopy;
     }
 
-    inline void addColorFilter(SkiaColorFilter* colorFilter) {
-        addInt((int) colorFilter);
+    inline SkiaColorFilter* refColorFilter(SkiaColorFilter* colorFilter) {
         mFilterResources.add(colorFilter);
         mCaches.resourceCache.incrementRefcount(colorFilter);
+        return colorFilter;
     }
 
     Vector<SkBitmap*> mBitmapResources;
@@ -919,12 +713,10 @@
 
     Vector<Layer*> mLayers;
 
-    uint32_t mBufferSize;
-
     int mRestoreSaveCount;
 
     Caches& mCaches;
-    SkWriter32 mWriter;
+    sp<DisplayListData> mDisplayListData;
 
     float mTranslateX;
     float mTranslateY;
diff --git a/libs/hwui/Layer.h b/libs/hwui/Layer.h
index a551b3f..e8a85fd 100644
--- a/libs/hwui/Layer.h
+++ b/libs/hwui/Layer.h
@@ -277,6 +277,10 @@
      * Texture coordinates of the layer.
      */
     Rect texCoords;
+    /**
+     * Clipping rectangle.
+     */
+    Rect clipRect;
 
     /**
      * Dirty region indicating what parts of the layer
diff --git a/libs/hwui/LayerRenderer.cpp b/libs/hwui/LayerRenderer.cpp
index 61bedbb..c8a8ed4 100644
--- a/libs/hwui/LayerRenderer.cpp
+++ b/libs/hwui/LayerRenderer.cpp
@@ -62,6 +62,7 @@
         android::Rect r(dirty.left, dirty.top, dirty.right, dirty.bottom);
         mLayer->region.subtractSelf(r);
     }
+    mLayer->clipRect.set(dirty);
 
     return OpenGLRenderer::prepareDirty(dirty.left, dirty.top, dirty.right, dirty.bottom, opaque);
 }
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index f55bc9d..7772f3a 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -169,8 +169,8 @@
     return prepareDirty(0.0f, 0.0f, mWidth, mHeight, opaque);
 }
 
-status_t OpenGLRenderer::prepareDirty(float left, float top, float right, float bottom,
-        bool opaque) {
+status_t OpenGLRenderer::prepareDirty(float left, float top,
+        float right, float bottom, bool opaque) {
     mCaches.clearGarbage();
 
     mSnapshot = new Snapshot(mFirstSnapshot,
@@ -207,7 +207,7 @@
     if (mCaches.extensions.hasDiscardFramebuffer() &&
             left <= 0.0f && top <= 0.0f && right >= mWidth && bottom >= mHeight) {
         const GLenum attachments[] = { getTargetFbo() == 0 ? (const GLenum) GL_COLOR_EXT :
-                (const GLenum) GL_COLOR_ATTACHMENT0 };
+                (const GLenum) GL_COLOR_ATTACHMENT0, GL_STENCIL_EXT };
         glDiscardFramebufferEXT(GL_FRAMEBUFFER, 1, attachments);
     }
 }
@@ -237,12 +237,18 @@
 void OpenGLRenderer::startTiling(const sp<Snapshot>& s, bool opaque) {
     if (!mSuppressTiling) {
         Rect* clip = mTilingSnapshot->clipRect;
-        if (s->flags & Snapshot::kFlagIsFboLayer) {
-            clip = s->clipRect;
+        if (s->flags & Snapshot::kFlagFboTarget) {
+            clip = &s->layer->clipRect;
         }
 
-        mCaches.startTiling(clip->left, s->height - clip->bottom,
-                clip->right - clip->left, clip->bottom - clip->top, opaque);
+        startTiling(*clip, s->height, opaque);
+    }
+}
+
+void OpenGLRenderer::startTiling(const Rect& clip, int windowHeight, bool opaque) {
+    if (!mSuppressTiling) {
+        mCaches.startTiling(clip.left, windowHeight - clip.bottom,
+                    clip.right - clip.left, clip.bottom - clip.top, opaque);
     }
 }
 
@@ -782,18 +788,17 @@
 }
 
 bool OpenGLRenderer::createFboLayer(Layer* layer, Rect& bounds, Rect& clip, GLuint previousFbo) {
+    layer->clipRect.set(clip);
     layer->setFbo(mCaches.fboCache.get());
 
     mSnapshot->region = &mSnapshot->layer->region;
-    mSnapshot->flags |= Snapshot::kFlagFboTarget;
-
-    mSnapshot->flags |= Snapshot::kFlagIsFboLayer;
+    mSnapshot->flags |= Snapshot::kFlagFboTarget | Snapshot::kFlagIsFboLayer |
+            Snapshot::kFlagDirtyOrtho;
     mSnapshot->fbo = layer->getFbo();
     mSnapshot->resetTransform(-bounds.left, -bounds.top, 0.0f);
     mSnapshot->resetClip(clip.left, clip.top, clip.right, clip.bottom);
     mSnapshot->viewport.set(0.0f, 0.0f, bounds.getWidth(), bounds.getHeight());
     mSnapshot->height = bounds.getHeight();
-    mSnapshot->flags |= Snapshot::kFlagDirtyOrtho;
     mSnapshot->orthoMatrix.load(mOrthoMatrix);
 
     endTiling();
@@ -811,7 +816,7 @@
     glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
             layer->getTexture(), 0);
 
-    startTiling(mSnapshot);
+    startTiling(mSnapshot, !layer->isBlend());
 
     // Clear the FBO, expand the clear region by 1 to get nice bilinear filtering
     mCaches.enableScissor();
@@ -1096,7 +1101,7 @@
         rects.push(r.fTop);
         rects.push(r.fRight);
         rects.push(r.fBottom);
-        count++;
+        count += 4;
         it.next();
     }
 
@@ -1245,6 +1250,11 @@
 void OpenGLRenderer::attachStencilBufferToLayer(Layer* layer) {
     // The layer's FBO is already bound when we reach this stage
     if (!layer->getStencilRenderBuffer()) {
+        // GL_QCOM_tiled_rendering doesn't like it if a renderbuffer
+        // is attached after we initiated tiling. We must turn it off,
+        // attach the new render buffer then turn tiling back on
+        endTiling();
+
         // TODO: See Layer::removeFbo(). The stencil renderbuffer should be cached
         GLuint buffer;
         glGenRenderbuffers(1, &buffer);
@@ -1254,6 +1264,8 @@
         layer->allocateStencilRenderBuffer();
 
         glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, buffer);
+
+        startTiling(layer->clipRect, layer->layer.getHeight(), !layer->isBlend());
     }
 }
 
@@ -1732,7 +1744,7 @@
 
 void OpenGLRenderer::outputDisplayList(DisplayList* displayList, uint32_t level) {
     if (displayList) {
-        displayList->output(*this, level);
+        displayList->output(level);
     }
 }
 
@@ -2082,7 +2094,6 @@
  */
 void OpenGLRenderer::drawConvexPath(const SkPath& path, SkPaint* paint) {
     int color = paint->getColor();
-    SkPaint::Style style = paint->getStyle();
     SkXfermode::Mode mode = getXfermode(paint->getXfermode());
     bool isAA = paint->isAntiAlias();
 
@@ -3193,8 +3204,7 @@
     Vertex mesh[count * 6];
     Vertex* vertex = mesh;
 
-    for (int i = 0; i < count; i++) {
-        int index = i * 4;
+    for (int index = 0; index < count; index += 4) {
         float l = rects[index + 0];
         float t = rects[index + 1];
         float r = rects[index + 2];
diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h
index d4e1eb5..594580e 100644
--- a/libs/hwui/OpenGLRenderer.h
+++ b/libs/hwui/OpenGLRenderer.h
@@ -400,12 +400,21 @@
 
     /**
      * Tells the GPU what part of the screen is about to be redrawn.
+     * This method will use the clip rect that we started drawing the
+     * frame with.
      * This method needs to be invoked every time getTargetFbo() is
      * bound again.
      */
     void startTiling(const sp<Snapshot>& snapshot, bool opaque = false);
 
     /**
+     * Tells the GPU what part of the screen is about to be redrawn.
+     * This method needs to be invoked every time getTargetFbo() is
+     * bound again.
+     */
+    void startTiling(const Rect& clip, int windowHeight, bool opaque = false);
+
+    /**
      * Tells the GPU that we are done drawing the frame or that we
      * are switching to another render target.
      */
diff --git a/libs/hwui/Patch.cpp b/libs/hwui/Patch.cpp
index e490151..45c619e 100644
--- a/libs/hwui/Patch.cpp
+++ b/libs/hwui/Patch.cpp
@@ -122,8 +122,6 @@
     float rescaleX = 1.0f;
     float rescaleY = 1.0f;
 
-    const float meshWidth = right - left;
-
     if (xStretchCount > 0) {
         uint32_t stretchSize = 0;
         for (uint32_t i = 1; i < mXCount; i += 2) {
diff --git a/libs/hwui/PathRenderer.cpp b/libs/hwui/PathRenderer.cpp
index dd13d79..d59e36f 100644
--- a/libs/hwui/PathRenderer.cpp
+++ b/libs/hwui/PathRenderer.cpp
@@ -596,7 +596,6 @@
     SkPath::Iter iter(path, forceClose);
     SkPoint pts[4];
     SkPath::Verb v;
-    Vertex* newVertex = 0;
     while (SkPath::kDone_Verb != (v = iter.next(pts))) {
             switch (v) {
                 case SkPath::kMove_Verb:
diff --git a/libs/hwui/Rect.h b/libs/hwui/Rect.h
index 80f39ff..5f4bb5a 100644
--- a/libs/hwui/Rect.h
+++ b/libs/hwui/Rect.h
@@ -171,22 +171,19 @@
     }
 
 private:
-    static inline float min(float a, float b) { return (a < b) ? a : b; }
-    static inline float max(float a, float b) { return (a > b) ? a : b; }
-
     void intersectWith(Rect& tmp) const {
-        tmp.left = max(left, tmp.left);
-        tmp.top = max(top, tmp.top);
-        tmp.right = min(right, tmp.right);
-        tmp.bottom = min(bottom, tmp.bottom);
+        tmp.left = fmaxf(left, tmp.left);
+        tmp.top = fmaxf(top, tmp.top);
+        tmp.right = fminf(right, tmp.right);
+        tmp.bottom = fminf(bottom, tmp.bottom);
     }
 
     Rect intersectWith(float l, float t, float r, float b) const {
         Rect tmp;
-        tmp.left = max(left, l);
-        tmp.top = max(top, t);
-        tmp.right = min(right, r);
-        tmp.bottom = min(bottom, b);
+        tmp.left = fmaxf(left, l);
+        tmp.top = fmaxf(top, t);
+        tmp.right = fminf(right, r);
+        tmp.bottom = fminf(bottom, b);
         return tmp;
     }
 
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
index fc0ff55..695c2aa 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
@@ -71,7 +71,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 = 96;
+    private static final int DATABASE_VERSION = 97;
 
     private Context mContext;
     private int mUserHandle;
@@ -1536,6 +1536,22 @@
             upgradeVersion = 96;
         }
 
+        if (upgradeVersion == 96) {
+            // Remove Settings.Secure.TOUCH_EXPLORATION_GRANTED_ACCESSIBILITY_SERVICES
+            if (mUserHandle == UserHandle.USER_OWNER) {
+                db.beginTransaction();
+                try {
+                    db.execSQL("DELETE FROM system WHERE name='"
+                            + Settings.Secure.TOUCH_EXPLORATION_GRANTED_ACCESSIBILITY_SERVICES
+                            + "'");
+                    db.setTransactionSuccessful();
+                } finally {
+                    db.endTransaction();
+                }
+            }
+            upgradeVersion = 97;
+        }
+
         // *** Remember to update DATABASE_VERSION above!
 
         if (upgradeVersion != currentVersion) {
diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml
index c40e26d..48edc73 100644
--- a/packages/SystemUI/res/values-ar/strings.xml
+++ b/packages/SystemUI/res/values-ar/strings.xml
@@ -189,7 +189,7 @@
     <string name="quick_settings_location_label" msgid="3292451598267467545">"الموقع المستخدم"</string>
     <string name="quick_settings_media_device_label" msgid="1302906836372603762">"جهاز الوسائط"</string>
     <string name="quick_settings_rssi_label" msgid="7725671335550695589">"RSSI"</string>
-    <string name="quick_settings_rssi_emergency_only" msgid="2713774041672886750">"مكالمات الطوارئ فقط"</string>
+    <string name="quick_settings_rssi_emergency_only" msgid="2713774041672886750">"مكالمات طوارئ فقط"</string>
     <string name="quick_settings_settings_label" msgid="5326556592578065401">"الإعدادات"</string>
     <string name="quick_settings_time_label" msgid="4635969182239736408">"الوقت"</string>
     <string name="quick_settings_user_label" msgid="5238995632130897840">"أنا"</string>
diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml
index 91214d1..7666f7d 100644
--- a/packages/SystemUI/res/values-sv/strings.xml
+++ b/packages/SystemUI/res/values-sv/strings.xml
@@ -197,8 +197,8 @@
     <string name="quick_settings_wifi_not_connected" msgid="7171904845345573431">"Ej ansluten"</string>
     <string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"Inget nätverk"</string>
     <string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi är inaktiverat"</string>
-    <string name="quick_settings_wifi_display_label" msgid="6893592964463624333">"Wi-Fi visas"</string>
-    <string name="quick_settings_wifi_display_no_connection_label" msgid="2355298740765736918">"Trådlös visning"</string>
+    <string name="quick_settings_wifi_display_label" msgid="6893592964463624333">"Trådlös skärm"</string>
+    <string name="quick_settings_wifi_display_no_connection_label" msgid="2355298740765736918">"Trådlös skärm"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Ljusstyrka"</string>
     <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTO"</string>
     <string name="status_bar_help_title" msgid="1199237744086469217">"Meddelanden visas här"</string>
diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml
index 7750e77..f43eabe 100644
--- a/packages/SystemUI/res/values-uk/strings.xml
+++ b/packages/SystemUI/res/values-uk/strings.xml
@@ -35,10 +35,10 @@
     <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Поточні"</string>
     <string name="status_bar_latest_events_title" msgid="6594767438577593172">"Сповіщення"</string>
     <string name="battery_low_title" msgid="2783104807551211639">"Підключіть зарядний пристрій"</string>
-    <string name="battery_low_subtitle" msgid="1752040062087829196">"Батарея виснажується."</string>
+    <string name="battery_low_subtitle" msgid="1752040062087829196">"Акумулятор розряджається."</string>
     <string name="battery_low_percent_format" msgid="1077244949318261761">"Залишилося <xliff:g id="NUMBER">%d%%</xliff:g>"</string>
     <string name="invalid_charger" msgid="4549105996740522523">"Заряджання USB не підтримується."\n"Використовуйте лише наданий у комплекті зарядний пристрій."</string>
-    <string name="battery_low_why" msgid="7279169609518386372">"Викор. батареї"</string>
+    <string name="battery_low_why" msgid="7279169609518386372">"Використання акумулятора"</string>
     <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Налаштування"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
     <string name="status_bar_settings_airplane" msgid="4879879698500955300">"Режим польоту"</string>
@@ -85,11 +85,11 @@
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Збільшення екрана."</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth під’єднано."</string>
     <string name="accessibility_bluetooth_disconnected" msgid="7416648669976870175">"Bluetooth від’єднано."</string>
-    <string name="accessibility_no_battery" msgid="358343022352820946">"Немає заряду батареї."</string>
-    <string name="accessibility_battery_one_bar" msgid="7774887721891057523">"Одна смужка заряду батареї."</string>
-    <string name="accessibility_battery_two_bars" msgid="8500650438735009973">"Дві смужки заряду батареї."</string>
-    <string name="accessibility_battery_three_bars" msgid="2302983330865040446">"Три смужки заряду батареї."</string>
-    <string name="accessibility_battery_full" msgid="8909122401720158582">"Повний заряд батареї"</string>
+    <string name="accessibility_no_battery" msgid="358343022352820946">"Акумулятор розряджений."</string>
+    <string name="accessibility_battery_one_bar" msgid="7774887721891057523">"Заряд акумулятора: одна смужка."</string>
+    <string name="accessibility_battery_two_bars" msgid="8500650438735009973">"Заряд акумулятора: дві смужки."</string>
+    <string name="accessibility_battery_three_bars" msgid="2302983330865040446">"Заряд акумулятора: три смужки."</string>
+    <string name="accessibility_battery_full" msgid="8909122401720158582">"Акумулятор заряджений."</string>
     <string name="accessibility_no_phone" msgid="4894708937052611281">"Немає сигналу телефону."</string>
     <string name="accessibility_phone_one_bar" msgid="687699278132664115">"Одна смужка сигналу телефону."</string>
     <string name="accessibility_phone_two_bars" msgid="8384905382804815201">"Дві смужки сигналу телефону."</string>
@@ -134,7 +134,7 @@
     <string name="accessibility_no_sim" msgid="8274017118472455155">"Немає SIM-карти."</string>
     <string name="accessibility_bluetooth_tether" msgid="4102784498140271969">"Прив’язка Bluetooth."</string>
     <string name="accessibility_airplane_mode" msgid="834748999790763092">"Режим польоту."</string>
-    <string name="accessibility_battery_level" msgid="7451474187113371965">"Відсотків батареї: <xliff:g id="NUMBER">%d</xliff:g>."</string>
+    <string name="accessibility_battery_level" msgid="7451474187113371965">"Заряд акумулятора: <xliff:g id="NUMBER">%d</xliff:g>."</string>
     <string name="accessibility_settings_button" msgid="799583911231893380">"Налаштування системи."</string>
     <string name="accessibility_notifications_button" msgid="4498000369779421892">"Сповіщення."</string>
     <string name="accessibility_remove_notification" msgid="3603099514902182350">"Очистити сповіщення."</string>
diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java
index 7cfa8c2..4cfe5d5 100644
--- a/services/java/com/android/server/ConnectivityService.java
+++ b/services/java/com/android/server/ConnectivityService.java
@@ -194,6 +194,7 @@
     private int mNetworkPreference;
     private int mActiveDefaultNetwork = -1;
     // 0 is full bad, 100 is full good
+    private int mDefaultInetCondition = 0;
     private int mDefaultInetConditionPublished = 0;
     private boolean mInetConditionChangeInFlight = false;
     private int mDefaultConnectionSequence = 0;
@@ -1729,10 +1730,6 @@
                 intent.putExtra(ConnectivityManager.EXTRA_OTHER_NETWORK_INFO, switchTo);
             } else {
                 mDefaultInetConditionPublished = 0; // we're not connected anymore
-                if (DBG) {
-                    log("handleDisconnect: net=" + mActiveDefaultNetwork +
-                            ", published condition=" + mDefaultInetConditionPublished);
-                }
                 intent.putExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, true);
             }
         }
@@ -1923,10 +1920,6 @@
                 intent.putExtra(ConnectivityManager.EXTRA_OTHER_NETWORK_INFO, switchTo);
             } else {
                 mDefaultInetConditionPublished = 0;
-                if (DBG) {
-                    log("handleConnectionFailure: net=" + mActiveDefaultNetwork +
-                            ", published condition=" + mDefaultInetConditionPublished);
-                }
                 intent.putExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, true);
             }
         }
@@ -2071,10 +2064,6 @@
             mDefaultInetConditionPublished = 0;
             mDefaultConnectionSequence++;
             mInetConditionChangeInFlight = false;
-            if (DBG) {
-                log("handleConnect: net=" + newNetType +
-                        ", published condition=" + mDefaultInetConditionPublished);
-            }
             // Don't do this - if we never sign in stay, grey
             //reportNetworkCondition(mActiveDefaultNetwork, 100);
         }
@@ -2790,8 +2779,7 @@
                 {
                     int netType = msg.arg1;
                     int sequence = msg.arg2;
-                    int condition = (Integer)msg.obj;
-                    handleInetConditionHoldEnd(netType, sequence, condition);
+                    handleInetConditionHoldEnd(netType, sequence);
                     break;
                 }
                 case EVENT_SET_NETWORK_PREFERENCE:
@@ -3004,13 +2992,14 @@
         if (VDBG) {
             log("handleInetConditionChange: net=" +
                     netType + ", condition=" + condition +
-                    " mActiveDefaultNetwork=" + mActiveDefaultNetwork);
+                    ",mActiveDefaultNetwork=" + mActiveDefaultNetwork);
         }
+        mDefaultInetCondition = condition;
         int delay;
         if (mInetConditionChangeInFlight == false) {
             if (VDBG) log("handleInetConditionChange: starting a change hold");
             // setup a new hold to debounce this
-            if (condition > 50) {
+            if (mDefaultInetCondition > 50) {
                 delay = Settings.Global.getInt(mContext.getContentResolver(),
                         Settings.Global.INET_CONDITION_DEBOUNCE_UP_DELAY, 500);
             } else {
@@ -3019,16 +3008,18 @@
             }
             mInetConditionChangeInFlight = true;
             mHandler.sendMessageDelayed(mHandler.obtainMessage(EVENT_INET_CONDITION_HOLD_END,
-                    mActiveDefaultNetwork, mDefaultConnectionSequence, new Integer(condition)), delay);
+                    mActiveDefaultNetwork, mDefaultConnectionSequence), delay);
         } else {
             // we've set the new condition, when this hold ends that will get picked up
             if (VDBG) log("handleInetConditionChange: currently in hold - not setting new end evt");
         }
     }
 
-    private void handleInetConditionHoldEnd(int netType, int sequence, int condition) {
+    private void handleInetConditionHoldEnd(int netType, int sequence) {
         if (DBG) {
-            log("handleInetConditionHoldEnd: net=" + netType + ", condition=" + condition);
+            log("handleInetConditionHoldEnd: net=" + netType +
+                    ", condition=" + mDefaultInetCondition +
+                    ", published condition=" + mDefaultInetConditionPublished);
         }
         mInetConditionChangeInFlight = false;
 
@@ -3040,13 +3031,19 @@
             if (DBG) log("handleInetConditionHoldEnd: event hold for obsolete network - ignoring");
             return;
         }
-
+        // TODO: Figure out why this optimization sometimes causes a
+        //       change in mDefaultInetCondition to be missed and the
+        //       UI to not be updated.
+        //if (mDefaultInetConditionPublished == mDefaultInetCondition) {
+        //    if (DBG) log("no change in condition - aborting");
+        //    return;
+        //}
         NetworkInfo networkInfo = mNetTrackers[mActiveDefaultNetwork].getNetworkInfo();
         if (networkInfo.isConnected() == false) {
             if (DBG) log("handleInetConditionHoldEnd: default network not connected - ignoring");
             return;
         }
-        mDefaultInetConditionPublished = condition;
+        mDefaultInetConditionPublished = mDefaultInetCondition;
         sendInetConditionBroadcast(networkInfo);
         return;
     }
diff --git a/services/java/com/android/server/InputMethodManagerService.java b/services/java/com/android/server/InputMethodManagerService.java
index 0f14265..1a8641b 100644
--- a/services/java/com/android/server/InputMethodManagerService.java
+++ b/services/java/com/android/server/InputMethodManagerService.java
@@ -511,7 +511,8 @@
                     }
                 }
 
-                buildInputMethodListLocked(mMethodList, mMethodMap);
+                buildInputMethodListLocked(
+                        mMethodList, mMethodMap, false /* resetDefaultEnabledIme */);
 
                 boolean changed = false;
 
@@ -671,9 +672,13 @@
 
         // Just checking if defaultImiId is empty or not
         final String defaultImiId = mSettings.getSelectedInputMethod();
+        if (DEBUG) {
+            Slog.d(TAG, "Initial default ime = " + defaultImiId);
+        }
         mImeSelectedOnBoot = !TextUtils.isEmpty(defaultImiId);
 
-        buildInputMethodListLocked(mMethodList, mMethodMap);
+        buildInputMethodListLocked(mMethodList, mMethodMap,
+                !mImeSelectedOnBoot /* resetDefaultEnabledIme */);
         mSettings.enableAllIMEsIfThereIsNoEnabledIME();
 
         if (!mImeSelectedOnBoot) {
@@ -726,7 +731,7 @@
         }
     }
 
-    private void resetAllInternalStateLocked(boolean updateOnlyWhenLocaleChanged) {
+    private void resetAllInternalStateLocked(final boolean updateOnlyWhenLocaleChanged) {
         if (!mSystemReady) {
             // not system ready
             return;
@@ -744,7 +749,8 @@
             }
             // InputMethodAndSubtypeListManager should be reset when the locale is changed.
             mImListManager = new InputMethodAndSubtypeListManager(mContext, this);
-            buildInputMethodListLocked(mMethodList, mMethodMap);
+            buildInputMethodListLocked(mMethodList, mMethodMap,
+                    updateOnlyWhenLocaleChanged /* resetDefaultEnabledIme */);
             if (!updateOnlyWhenLocaleChanged) {
                 final String selectedImiId = mSettings.getSelectedInputMethod();
                 if (TextUtils.isEmpty(selectedImiId)) {
@@ -814,7 +820,8 @@
                     mWindowManagerService.setOnHardKeyboardStatusChangeListener(
                             mHardKeyboardListener);
                 }
-                buildInputMethodListLocked(mMethodList, mMethodMap);
+                buildInputMethodListLocked(mMethodList, mMethodMap,
+                        !mImeSelectedOnBoot /* resetDefaultEnabledIme */);
                 if (!mImeSelectedOnBoot) {
                     Slog.w(TAG, "Reset the default IME as \"Resource\" is ready here.");
                     checkCurrentLocaleChangedLocked();
@@ -2147,7 +2154,8 @@
                         mFileManager.addInputMethodSubtypes(imi, subtypes);
                         final long ident = Binder.clearCallingIdentity();
                         try {
-                            buildInputMethodListLocked(mMethodList, mMethodMap);
+                            buildInputMethodListLocked(mMethodList, mMethodMap,
+                                    false /* resetDefaultEnabledIme */);
                         } finally {
                             Binder.restoreCallingIdentity(ident);
                         }
@@ -2397,9 +2405,10 @@
     }
 
     void buildInputMethodListLocked(ArrayList<InputMethodInfo> list,
-            HashMap<String, InputMethodInfo> map) {
+            HashMap<String, InputMethodInfo> map, boolean resetDefaultEnabledIme) {
         if (DEBUG) {
-            Slog.d(TAG, "--- re-buildInputMethodList " + ", \n ------ \n" + getStackTrace());
+            Slog.d(TAG, "--- re-buildInputMethodList reset = " + resetDefaultEnabledIme
+                    + " \n ------ \n" + getStackTrace());
         }
         list.clear();
         map.clear();
@@ -2436,14 +2445,8 @@
                 final String id = p.getId();
                 map.put(id, p);
 
-                // Valid system default IMEs and IMEs that have English subtypes are enabled
-                // by default
-                if (InputMethodUtils.isDefaultEnabledIme(mSystemReady, p, mContext)) {
-                    setInputMethodEnabledLocked(id, true);
-                }
-
                 if (DEBUG) {
-                    Slog.d(TAG, "Found a third-party input method " + p);
+                    Slog.d(TAG, "Found an input method " + p);
                 }
 
             } catch (XmlPullParserException e) {
@@ -2453,6 +2456,18 @@
             }
         }
 
+        if (resetDefaultEnabledIme) {
+            final ArrayList<InputMethodInfo> defaultEnabledIme =
+                    InputMethodUtils.getDefaultEnabledImes(mContext, mSystemReady, list);
+            for (int i = 0; i < defaultEnabledIme.size(); ++i) {
+                final InputMethodInfo imi =  defaultEnabledIme.get(i);
+                if (DEBUG) {
+                    Slog.d(TAG, "--- enable ime = " + imi);
+                }
+                setInputMethodEnabledLocked(imi.getId(), true);
+            }
+        }
+
         final String defaultImiId = mSettings.getSelectedInputMethod();
         if (!TextUtils.isEmpty(defaultImiId)) {
             if (!map.containsKey(defaultImiId)) {
diff --git a/services/java/com/android/server/PreferredComponent.java b/services/java/com/android/server/PreferredComponent.java
index 718b05d..bb22545 100644
--- a/services/java/com/android/server/PreferredComponent.java
+++ b/services/java/com/android/server/PreferredComponent.java
@@ -164,17 +164,19 @@
         return mParseError;
     }
 
-    public void writeToXml(XmlSerializer serializer) throws IOException {
+    public void writeToXml(XmlSerializer serializer, boolean full) throws IOException {
         final int NS = mSetClasses != null ? mSetClasses.length : 0;
         serializer.attribute(null, "name", mShortComponent);
-        if (mMatch != 0) {
-            serializer.attribute(null, "match", Integer.toHexString(mMatch));
-        }
-        serializer.attribute(null, "set", Integer.toString(NS));
-        for (int s=0; s<NS; s++) {
-            serializer.startTag(null, "set");
-            serializer.attribute(null, "name", mSetComponents[s]);
-            serializer.endTag(null, "set");
+        if (full) {
+            if (mMatch != 0) {
+                serializer.attribute(null, "match", Integer.toHexString(mMatch));
+            }
+            serializer.attribute(null, "set", Integer.toString(NS));
+            for (int s=0; s<NS; s++) {
+                serializer.startTag(null, "set");
+                serializer.attribute(null, "name", mSetComponents[s]);
+                serializer.endTag(null, "set");
+            }
         }
     }
 
diff --git a/services/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/java/com/android/server/accessibility/AccessibilityManagerService.java
index ded42ee..f4592f7 100644
--- a/services/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -23,15 +23,12 @@
 import android.accessibilityservice.AccessibilityServiceInfo;
 import android.accessibilityservice.IAccessibilityServiceClient;
 import android.accessibilityservice.IAccessibilityServiceConnection;
-import android.app.AlertDialog;
 import android.app.PendingIntent;
 import android.app.StatusBarManager;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
 import android.content.ContentResolver;
 import android.content.Context;
-import android.content.DialogInterface;
-import android.content.DialogInterface.OnClickListener;
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.ServiceConnection;
@@ -70,7 +67,6 @@
 import android.view.KeyCharacterMap;
 import android.view.KeyEvent;
 import android.view.MagnificationSpec;
-import android.view.WindowManager;
 import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.AccessibilityInteractionClient;
 import android.view.accessibility.AccessibilityManager;
@@ -161,8 +157,6 @@
 
     private Service mQueryBridge;
 
-    private AlertDialog mEnableTouchExplorationDialog;
-
     private AccessibilityInputFilter mInputFilter;
 
     private boolean mHasInputFilter;
@@ -250,12 +244,6 @@
                             persistComponentNamesToSettingLocked(
                                     Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES,
                                     state.mEnabledServices, userId);
-                            // Update the touch exploration granted services setting.
-                            state.mTouchExplorationGrantedServices.remove(comp);
-                            persistComponentNamesToSettingLocked(
-                                    Settings.Secure.
-                                            TOUCH_EXPLORATION_GRANTED_ACCESSIBILITY_SERVICES,
-                                    state.mEnabledServices, userId);
                             return;
                         }
                     }
@@ -534,6 +522,9 @@
             // No touch exploration.
             userState.mIsTouchExplorationEnabled = false;
 
+            // No touch enhanced web accessibility.
+            userState.mIsEnhancedWebAccessibilityEnabled = false;
+
             // Hook the automation service up.
             mUiAutomationService = new Service(mCurrentUserId, componentName,
                     accessibilityServiceInfo, true);
@@ -559,16 +550,14 @@
         synchronized (mLock) {
             UserState userState = getCurrentUserStateLocked();
             // Stash the old state so we can restore it when the keyguard is gone.
-            mTempStateChangeForCurrentUserMemento.initialize(mCurrentUserId,
-                    getCurrentUserStateLocked());
+            mTempStateChangeForCurrentUserMemento.initialize(getCurrentUserStateLocked());
             // Set the temporary state.
             userState.mIsAccessibilityEnabled = true;
-            userState.mIsTouchExplorationEnabled= touchExplorationEnabled;
+            userState.mIsTouchExplorationEnabled = touchExplorationEnabled;
+            userState.mIsEnhancedWebAccessibilityEnabled = false;
             userState.mIsDisplayMagnificationEnabled = false;
             userState.mEnabledServices.clear();
             userState.mEnabledServices.add(service);
-            userState.mTouchExplorationGrantedServices.clear();
-            userState.mTouchExplorationGrantedServices.add(service);
             // Update the internal state.
             performServiceManagementLocked(userState);
             scheduleUpdateInputFilter(userState);
@@ -842,14 +831,6 @@
                 userState.mEnabledServices);
     }
 
-    private void populateTouchExplorationGrantedAccessibilityServicesLocked(
-            UserState userState) {
-        populateComponentNamesFromSettingLocked(
-                Settings.Secure.TOUCH_EXPLORATION_GRANTED_ACCESSIBILITY_SERVICES,
-                userState.mUserId,
-                userState.mTouchExplorationGrantedServices);
-    }
-
     /**
      * Performs {@link AccessibilityService}s delayed notification. The delay is configurable
      * and denotes the period after the last event before notifying the service.
@@ -896,6 +877,7 @@
             userState.mComponentNameToServiceMap.put(service.mComponentName, service);
             scheduleUpdateInputFilter(userState);
             tryEnableTouchExplorationLocked(service);
+            tryEnableEnhancedWebAccessibilityLocked(service);
         } catch (RemoteException e) {
             /* do nothing */
         }
@@ -918,6 +900,7 @@
         service.dispose();
         scheduleUpdateInputFilter(userState);
         tryDisableTouchExplorationLocked(service);
+        tryDisableEnhancedWebAccessibilityLocked(service);
         return removed;
     }
 
@@ -937,7 +920,7 @@
     private boolean canDispathEventLocked(Service service, AccessibilityEvent event,
             int handledFeedbackTypes) {
 
-        if (!service.canReceiveEvents()) {
+        if (!service.canReceiveEventsLocked()) {
             return false;
         }
 
@@ -1140,53 +1123,6 @@
         }
     }
 
-    private void showEnableTouchExplorationDialog(final Service service) {
-        String label = service.mResolveInfo.loadLabel(
-                mContext.getPackageManager()).toString();
-        synchronized (mLock) {
-            final UserState state = getCurrentUserStateLocked();
-            if (state.mIsTouchExplorationEnabled) {
-                return;
-            }
-            if (mEnableTouchExplorationDialog != null
-                    && mEnableTouchExplorationDialog.isShowing()) {
-                return;
-            }
-            mEnableTouchExplorationDialog = new AlertDialog.Builder(mContext)
-                .setIconAttribute(android.R.attr.alertDialogIcon)
-                .setPositiveButton(android.R.string.ok, new OnClickListener() {
-                    @Override
-                    public void onClick(DialogInterface dialog, int which) {
-                        // The user allowed the service to toggle touch exploration.
-                        state.mTouchExplorationGrantedServices.add(service.mComponentName);
-                        persistComponentNamesToSettingLocked(
-                                Settings.Secure.TOUCH_EXPLORATION_GRANTED_ACCESSIBILITY_SERVICES,
-                                       state.mTouchExplorationGrantedServices, state.mUserId);
-                        // Enable touch exploration.
-                        Settings.Secure.putIntForUser(mContext.getContentResolver(),
-                                Settings.Secure.TOUCH_EXPLORATION_ENABLED, 1,
-                                service.mUserId);
-                    }
-                })
-                .setNegativeButton(android.R.string.cancel, new OnClickListener() {
-                    @Override
-                    public void onClick(DialogInterface dialog, int which) {
-                        dialog.dismiss();
-                    }
-                })
-                .setTitle(R.string.enable_explore_by_touch_warning_title)
-                .setMessage(mContext.getString(
-                        R.string.enable_explore_by_touch_warning_message, label))
-                .create();
-            mEnableTouchExplorationDialog.getWindow().setType(
-                    WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
-            mEnableTouchExplorationDialog.getWindow().getAttributes().privateFlags
-                    |= WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS;
-            mEnableTouchExplorationDialog.setCanceledOnTouchOutside(true);
-            mEnableTouchExplorationDialog.show();
-        }
-    }
-
     private int getClientState(UserState userState) {
         int clientState = 0;
         if (userState.mIsAccessibilityEnabled) {
@@ -1202,7 +1138,6 @@
     private void recreateInternalStateLocked(UserState userState) {
         populateInstalledAccessibilityServiceLocked(userState);
         populateEnabledAccessibilityServicesLocked(userState);
-        populateTouchExplorationGrantedAccessibilityServicesLocked(userState);
 
         handleTouchExplorationEnabledSettingChangedLocked(userState);
         handleDisplayMagnificationEnabledSettingChangedLocked(userState);
@@ -1240,40 +1175,21 @@
                 0, userState.mUserId) == 1;
     }
 
-    private void handleTouchExplorationGrantedAccessibilityServicesChangedLocked(
-            UserState userState) {
-        final int serviceCount = userState.mServices.size();
-        for (int i = 0; i < serviceCount; i++) {
-            Service service = userState.mServices.get(i);
-            if (service.mRequestTouchExplorationMode
-                    && userState.mTouchExplorationGrantedServices.contains(
-                            service.mComponentName)) {
-                tryEnableTouchExplorationLocked(service);
-                return;
-            }
+    private void tryEnableTouchExplorationLocked(Service service) {
+        if (!service.mRequestTouchExplorationMode || !service.canReceiveEventsLocked()) {
+            return;
         }
-        if (userState.mIsTouchExplorationEnabled) {
-            Settings.Secure.putIntForUser(mContext.getContentResolver(),
-                    Settings.Secure.TOUCH_EXPLORATION_ENABLED, 0, userState.mUserId);
-        }
-    }
-
-    private void tryEnableTouchExplorationLocked(final Service service) {
         UserState userState = getUserStateLocked(service.mUserId);
-        if (!userState.mIsTouchExplorationEnabled && service.mRequestTouchExplorationMode
-                && service.canReceiveEvents()) {
-            final boolean canToggleTouchExploration =
-                    userState.mTouchExplorationGrantedServices.contains(service.mComponentName);
-            if (!service.mIsAutomation && !canToggleTouchExploration) {
-                showEnableTouchExplorationDialog(service);
-            } else {
-                Settings.Secure.putIntForUser(mContext.getContentResolver(),
-                        Settings.Secure.TOUCH_EXPLORATION_ENABLED, 1, userState.mUserId);
-            }
+        if (!userState.mIsTouchExplorationEnabled) {
+            Settings.Secure.putIntForUser(mContext.getContentResolver(),
+                    Settings.Secure.TOUCH_EXPLORATION_ENABLED, 1, userState.mUserId);
         }
     }
 
     private void tryDisableTouchExplorationLocked(Service service) {
+        if (!service.mRequestTouchExplorationMode) {
+            return;
+        }
         UserState userState = getUserStateLocked(service.mUserId);
         if (userState.mIsTouchExplorationEnabled) {
             final int serviceCount = userState.mServices.size();
@@ -1288,6 +1204,35 @@
         }
     }
 
+    private void tryEnableEnhancedWebAccessibilityLocked(Service service) {
+        if (!service.mRequestEnhancedWebAccessibility || !service.canReceiveEventsLocked()) {
+            return;
+        }
+        UserState userState = getUserStateLocked(service.mUserId);
+        if (!userState.mIsEnhancedWebAccessibilityEnabled) {
+            Settings.Secure.putIntForUser(mContext.getContentResolver(),
+                    Settings.Secure.ACCESSIBILITY_SCRIPT_INJECTION, 1, userState.mUserId);
+        }
+    }
+
+    private void tryDisableEnhancedWebAccessibilityLocked(Service service) {
+        if (!service.mRequestEnhancedWebAccessibility) {
+            return;
+        }
+        UserState userState = getUserStateLocked(service.mUserId);
+        if (userState.mIsEnhancedWebAccessibilityEnabled) {
+            final int serviceCount = userState.mServices.size();
+            for (int i = 0; i < serviceCount; i++) {
+                Service other = userState.mServices.get(i);
+                if (other != service && other.mRequestEnhancedWebAccessibility) {
+                    return;
+                }
+            }
+            Settings.Secure.putIntForUser(mContext.getContentResolver(),
+                    Settings.Secure.ACCESSIBILITY_SCRIPT_INJECTION, 0, userState.mUserId);
+        }
+    }
+
     @Override
     public void dump(FileDescriptor fd, final PrintWriter pw, String[] args) {
         mSecurityPolicy.enforceCallingPermission(Manifest.permission.DUMP, FUNCTION_DUMP);
@@ -1494,6 +1439,8 @@
 
         boolean mRequestTouchExplorationMode;
 
+        boolean mRequestEnhancedWebAccessibility;
+
         int mFetchFlags;
 
         long mNotificationTimeout;
@@ -1547,9 +1494,6 @@
             mIsAutomation = isAutomation;
             if (!isAutomation) {
                 mCanRetrieveScreenContent = accessibilityServiceInfo.getCanRetrieveWindowContent();
-                mRequestTouchExplorationMode =
-                    (accessibilityServiceInfo.flags
-                            & AccessibilityServiceInfo.FLAG_REQUEST_TOUCH_EXPLORATION_MODE) != 0;
                 mIntent = new Intent().setComponent(mComponentName);
                 mIntent.putExtra(Intent.EXTRA_CLIENT_LABEL,
                         com.android.internal.R.string.accessibility_binding_label);
@@ -1582,18 +1526,39 @@
                     & AccessibilityServiceInfo.FLAG_REPORT_VIEW_IDS) != 0 ?
                             AccessibilityNodeInfo.FLAG_REPORT_VIEW_IDS : 0;
 
-            mRequestTouchExplorationMode = (info.flags
-                    & AccessibilityServiceInfo.FLAG_REQUEST_TOUCH_EXPLORATION_MODE) != 0;
+            if (mResolveInfo != null) {
+                String packageName = mResolveInfo.serviceInfo.packageName;
+
+                if (mContext.getPackageManager().checkPermission(
+                        android.Manifest.permission.CAN_REQUEST_TOUCH_EXPLORATION_MODE,
+                        packageName) == PackageManager.PERMISSION_GRANTED) {
+                    mRequestTouchExplorationMode = (info.flags
+                            & AccessibilityServiceInfo.FLAG_REQUEST_TOUCH_EXPLORATION_MODE) != 0;
+                }
+
+                if (mContext.getPackageManager().checkPermission(
+                        android.Manifest.permission.CAN_REQUEST_ENHANCED_WEB_ACCESSIBILITY,
+                        packageName) == PackageManager.PERMISSION_GRANTED) {
+                    mRequestEnhancedWebAccessibility = (info.flags
+                           & AccessibilityServiceInfo.FLAG_REQUEST_ENHANCED_WEB_ACCESSIBILITY) != 0;
+                }
+            }
 
             // If this service is up and running we may have to enable touch
-            // exploration, otherwise this will happen when the service connects.
+            // exploration or enhanced web accessibility, otherwise this will
+            // happen when the service connects.
             synchronized (mLock) {
-                if (canReceiveEvents()) {
+                if (canReceiveEventsLocked()) {
                     if (mRequestTouchExplorationMode) {
                         tryEnableTouchExplorationLocked(this);
                     } else {
                         tryDisableTouchExplorationLocked(this);
                     }
+                    if (mRequestEnhancedWebAccessibility) {
+                        tryEnableEnhancedWebAccessibilityLocked(this);
+                    } else {
+                        tryDisableEnhancedWebAccessibilityLocked(this);
+                    }
                 }
             }
         }
@@ -1630,7 +1595,7 @@
             return false;
         }
 
-        public boolean canReceiveEvents() {
+        public boolean canReceiveEventsLocked() {
             return (mEventTypes != 0 && mFeedbackType != 0 && mService != null);
         }
 
@@ -2488,9 +2453,6 @@
 
         public final Set<ComponentName> mEnabledServices = new HashSet<ComponentName>();
 
-        public final Set<ComponentName> mTouchExplorationGrantedServices =
-                new HashSet<ComponentName>();
-
         public final SparseArray<AccessibilityConnectionWrapper>
                 mInteractionConnections =
                 new SparseArray<AccessibilityConnectionWrapper>();
@@ -2501,6 +2463,7 @@
 
         public boolean mIsAccessibilityEnabled;
         public boolean mIsTouchExplorationEnabled;
+        public boolean mIsEnhancedWebAccessibilityEnabled;
         public boolean mIsDisplayMagnificationEnabled;
 
         public UserState(int userId) {
@@ -2512,36 +2475,37 @@
         public int mUserId = UserHandle.USER_NULL;
         public boolean mIsAccessibilityEnabled;
         public boolean mIsTouchExplorationEnabled;
+        public boolean mIsEnhancedWebAccessibilityEnabled;
         public boolean mIsDisplayMagnificationEnabled;
         public final Set<ComponentName> mEnabledServices = new HashSet<ComponentName>();
         public final Set<ComponentName> mTouchExplorationGrantedServices =
                 new HashSet<ComponentName>();
 
-        public void initialize(int userId, UserState userState) {
-            mUserId = userId;
+        public void initialize(UserState userState) {
+            mUserId = userState.mUserId;
             mIsAccessibilityEnabled = userState.mIsAccessibilityEnabled;
             mIsTouchExplorationEnabled = userState.mIsTouchExplorationEnabled;
+            mIsEnhancedWebAccessibilityEnabled = userState.mIsEnhancedWebAccessibilityEnabled;
             mIsDisplayMagnificationEnabled = userState.mIsDisplayMagnificationEnabled;
             mEnabledServices.clear();
             mEnabledServices.addAll(userState.mEnabledServices);
             mTouchExplorationGrantedServices.clear();
-            mTouchExplorationGrantedServices.addAll(userState.mTouchExplorationGrantedServices);
         }
 
         public void applyTo(UserState userState) {
             userState.mIsAccessibilityEnabled = mIsAccessibilityEnabled;
             userState.mIsTouchExplorationEnabled = mIsTouchExplorationEnabled;
+            userState.mIsEnhancedWebAccessibilityEnabled = mIsEnhancedWebAccessibilityEnabled;
             userState.mIsDisplayMagnificationEnabled = mIsDisplayMagnificationEnabled;
             userState.mEnabledServices.clear();
             userState.mEnabledServices.addAll(mEnabledServices);
-            userState.mTouchExplorationGrantedServices.clear();
-            userState.mTouchExplorationGrantedServices.addAll(mTouchExplorationGrantedServices);
         }
 
         public void clear() {
             mUserId = UserHandle.USER_NULL;
             mIsAccessibilityEnabled = false;
             mIsTouchExplorationEnabled = false;
+            mIsEnhancedWebAccessibilityEnabled = false;
             mIsDisplayMagnificationEnabled = false;
             mEnabledServices.clear();
             mTouchExplorationGrantedServices.clear();
@@ -2562,9 +2526,6 @@
         private final Uri mEnabledAccessibilityServicesUri = Settings.Secure.getUriFor(
                 Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES);
 
-        private final Uri mTouchExplorationGrantedAccessibilityServicesUri = Settings.Secure
-                .getUriFor(Settings.Secure.TOUCH_EXPLORATION_GRANTED_ACCESSIBILITY_SERVICES);
-
         public AccessibilityContentObserver(Handler handler) {
             super(handler);
         }
@@ -2578,9 +2539,6 @@
                     false, this, UserHandle.USER_ALL);
             contentResolver.registerContentObserver(mEnabledAccessibilityServicesUri,
                     false, this, UserHandle.USER_ALL);
-            contentResolver.registerContentObserver(
-                    mTouchExplorationGrantedAccessibilityServicesUri,
-                    false, this, UserHandle.USER_ALL);
         }
 
         @Override
@@ -2625,15 +2583,6 @@
                         manageServicesLocked(userState);
                     }
                 }
-            } else if (mTouchExplorationGrantedAccessibilityServicesUri.equals(uri)) {
-                synchronized (mLock) {
-                    // We will update when the automation service dies.
-                    if (mUiAutomationService == null) {
-                        UserState userState = getCurrentUserStateLocked();
-                        populateTouchExplorationGrantedAccessibilityServicesLocked(userState);
-                        handleTouchExplorationGrantedAccessibilityServicesChangedLocked(userState);
-                    }
-                }
             }
         }
     }
diff --git a/services/java/com/android/server/pm/PackageManagerService.java b/services/java/com/android/server/pm/PackageManagerService.java
index 626002d..829e67a 100644
--- a/services/java/com/android/server/pm/PackageManagerService.java
+++ b/services/java/com/android/server/pm/PackageManagerService.java
@@ -173,7 +173,7 @@
 public class PackageManagerService extends IPackageManager.Stub {
     static final String TAG = "PackageManager";
     static final boolean DEBUG_SETTINGS = false;
-    private static final boolean DEBUG_PREFERRED = false;
+    static final boolean DEBUG_PREFERRED = true;
     static final boolean DEBUG_UPGRADE = false;
     private static final boolean DEBUG_INSTALL = false;
     private static final boolean DEBUG_REMOVE = false;
@@ -1021,7 +1021,7 @@
 
             readPermissions();
 
-            mRestoredSettings = mSettings.readLPw(sUserManager.getUsers(false),
+            mRestoredSettings = mSettings.readLPw(this, sUserManager.getUsers(false),
                     mSdkVersion, mOnlyCore);
             long startTime = SystemClock.uptimeMillis();
 
@@ -4967,7 +4967,7 @@
         ps.haveGids = true;
     }
     
-    private final class ActivityIntentResolver
+    final class ActivityIntentResolver
             extends IntentResolver<PackageParser.ActivityIntentInfo, ResolveInfo> {
         public List<ResolveInfo> queryIntent(Intent intent, String resolvedType,
                 boolean defaultOnly, int userId) {
@@ -8830,8 +8830,10 @@
                 }
             }
 
-            if (clearPackagePreferredActivitiesLPw(packageName, UserHandle.getCallingUserId())) {
-                scheduleWriteSettingsLocked();            
+            int user = UserHandle.getCallingUserId();
+            if (clearPackagePreferredActivitiesLPw(packageName, user)) {
+                mSettings.writePackageRestrictionsLPr(user);
+                scheduleWriteSettingsLocked();
             }
         }
     }
@@ -8849,7 +8851,8 @@
             Iterator<PreferredActivity> it = pir.filterIterator();
             while (it.hasNext()) {
                 PreferredActivity pa = it.next();
-                if (pa.mPref.mComponent.getPackageName().equals(packageName)) {
+                if (packageName == null ||
+                        pa.mPref.mComponent.getPackageName().equals(packageName)) {
                     if (removed == null) {
                         removed = new ArrayList<PreferredActivity>();
                     }
@@ -8862,12 +8865,24 @@
                     pir.removeFilter(pa);
                 }
                 changed = true;
-                mSettings.writePackageRestrictionsLPr(thisUserId);
             }
         }
         return changed;
     }
 
+    public void resetPreferredActivities(int userId) {
+        mContext.enforceCallingOrSelfPermission(
+                android.Manifest.permission.SET_PREFERRED_APPLICATIONS, null);
+        // writer
+        synchronized (mPackages) {
+            int user = UserHandle.getCallingUserId();
+            clearPackagePreferredActivitiesLPw(null, user);
+            mSettings.readDefaultPreferredAppsLPw(this, user);
+            mSettings.writePackageRestrictionsLPr(user);
+            scheduleWriteSettingsLocked();
+        }
+    }
+
     public int getPreferredActivities(List<IntentFilter> outFilters,
             List<ComponentName> outActivities, String packageName) {
 
@@ -9254,6 +9269,7 @@
         }
 
         DumpState dumpState = new DumpState();
+        boolean fullPreferred = false;
         
         String packageName = null;
         
@@ -9277,7 +9293,7 @@
                 pw.println("    r[esolvers]: dump intent resolvers");
                 pw.println("    perm[issions]: dump permissions");
                 pw.println("    pref[erred]: print preferred package settings");
-                pw.println("    preferred-xml: print preferred package settings as xml");
+                pw.println("    preferred-xml [--full]: print preferred package settings as xml");
                 pw.println("    prov[iders]: dump content providers");
                 pw.println("    p[ackages]: dump installed packages");
                 pw.println("    s[hared-users]: dump shared user IDs");
@@ -9311,6 +9327,10 @@
                 dumpState.setDump(DumpState.DUMP_PREFERRED);
             } else if ("preferred-xml".equals(cmd)) {
                 dumpState.setDump(DumpState.DUMP_PREFERRED_XML);
+                if (opti < args.length && "--full".equals(args[opti])) {
+                    fullPreferred = true;
+                    opti++;
+                }
             } else if ("p".equals(cmd) || "packages".equals(cmd)) {
                 dumpState.setDump(DumpState.DUMP_PACKAGES);
             } else if ("s".equals(cmd) || "shared-users".equals(cmd)) {
@@ -9405,7 +9425,7 @@
                     serializer.startDocument(null, true);
                     serializer.setFeature(
                             "http://xmlpull.org/v1/doc/features.html#indent-output", true);
-                    mSettings.writePreferredActivitiesLPr(serializer, 0);
+                    mSettings.writePreferredActivitiesLPr(serializer, 0, fullPreferred);
                     serializer.endDocument();
                     serializer.flush();
                 } catch (IllegalArgumentException e) {
@@ -10158,7 +10178,7 @@
     /** Called by UserManagerService */
     void createNewUserLILPw(int userHandle, File path) {
         if (mInstaller != null) {
-            mSettings.createNewUserLILPw(mInstaller, userHandle, path);
+            mSettings.createNewUserLILPw(this, mInstaller, userHandle, path);
         }
     }
 
diff --git a/services/java/com/android/server/pm/PreferredActivity.java b/services/java/com/android/server/pm/PreferredActivity.java
index dbf56ef..c655bb1 100644
--- a/services/java/com/android/server/pm/PreferredActivity.java
+++ b/services/java/com/android/server/pm/PreferredActivity.java
@@ -46,8 +46,8 @@
         mPref = new PreferredComponent(this, parser);
     }
 
-    public void writeToXml(XmlSerializer serializer) throws IOException {
-        mPref.writeToXml(serializer);
+    public void writeToXml(XmlSerializer serializer, boolean full) throws IOException {
+        mPref.writeToXml(serializer, full);
         serializer.startTag(null, "filter");
             super.writeToXml(serializer);
         serializer.endTag(null, "filter");
diff --git a/services/java/com/android/server/pm/Settings.java b/services/java/com/android/server/pm/Settings.java
index e336524..13f514b 100644
--- a/services/java/com/android/server/pm/Settings.java
+++ b/services/java/com/android/server/pm/Settings.java
@@ -23,6 +23,12 @@
 import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_ENABLED;
 import static android.Manifest.permission.READ_EXTERNAL_STORAGE;
 
+import android.content.IntentFilter;
+import android.content.pm.ActivityInfo;
+import android.content.pm.ResolveInfo;
+import android.net.Uri;
+import android.os.PatternMatcher;
+import android.util.LogPrinter;
 import com.android.internal.util.FastXmlSerializer;
 import com.android.internal.util.JournaledFile;
 import com.android.internal.util.XmlUtils;
@@ -972,14 +978,14 @@
         return components;
     }
 
-    void writePreferredActivitiesLPr(XmlSerializer serializer, int userId)
+    void writePreferredActivitiesLPr(XmlSerializer serializer, int userId, boolean full)
             throws IllegalArgumentException, IllegalStateException, IOException {
         serializer.startTag(null, "preferred-activities");
         PreferredIntentResolver pir = mPreferredActivities.get(userId);
         if (pir != null) {
             for (final PreferredActivity pa : pir.filterSet()) {
                 serializer.startTag(null, TAG_ITEM);
-                pa.writeToXml(serializer);
+                pa.writeToXml(serializer, full);
                 serializer.endTag(null, TAG_ITEM);
             }
         }
@@ -1072,7 +1078,7 @@
                 }
             }
 
-            writePreferredActivitiesLPr(serializer, userId);
+            writePreferredActivitiesLPr(serializer, userId, true);
 
             serializer.endTag(null, TAG_PACKAGE_RESTRICTIONS);
 
@@ -1557,7 +1563,8 @@
         }
     }
 
-    boolean readLPw(List<UserInfo> users, int sdkVersion, boolean onlyCore) {
+    boolean readLPw(PackageManagerService service, List<UserInfo> users, int sdkVersion,
+            boolean onlyCore) {
         FileInputStream str = null;
         if (mBackupSettingsFilename.exists()) {
             try {
@@ -1588,7 +1595,7 @@
                     PackageManagerService.reportSettingsProblem(Log.INFO,
                             "No settings file; creating initial state");
                     if (!onlyCore) {
-                        readDefaultPreferredAppsLPw(0);
+                        readDefaultPreferredAppsLPw(service, 0);
                     }
                     mInternalSdkPlatform = mExternalSdkPlatform = sdkVersion;
                     return false;
@@ -1771,7 +1778,7 @@
         return true;
     }
 
-    private void readDefaultPreferredAppsLPw(int userId) {
+    void readDefaultPreferredAppsLPw(PackageManagerService service, int userId) {
         // Read preferred apps from .../etc/preferred-apps directory.
         File preferredDir = new File(Environment.getRootDirectory(), "etc/preferred-apps");
         if (!preferredDir.exists() || !preferredDir.isDirectory()) {
@@ -1793,6 +1800,7 @@
                 continue;
             }
 
+            if (PackageManagerService.DEBUG_PREFERRED) Log.d(TAG, "Reading default preferred " + f);
             FileInputStream str = null;
             try {
                 str = new FileInputStream(f);
@@ -1814,7 +1822,7 @@
                             + " does not start with 'preferred-activities'");
                     continue;
                 }
-                readPreferredActivitiesLPw(parser, userId);
+                readDefaultPreferredActivitiesLPw(service, parser, userId);
             } catch (XmlPullParserException e) {
                 Slog.w(TAG, "Error reading apps file " + f, e);
             } catch (IOException e) {
@@ -1830,6 +1838,112 @@
         }
     }
 
+    private void readDefaultPreferredActivitiesLPw(PackageManagerService service,
+            XmlPullParser parser, int userId)
+            throws XmlPullParserException, IOException {
+        int outerDepth = parser.getDepth();
+        int type;
+        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+                && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
+            if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
+                continue;
+            }
+
+            String tagName = parser.getName();
+            if (tagName.equals(TAG_ITEM)) {
+                PreferredActivity tmpPa = new PreferredActivity(parser);
+                if (tmpPa.mPref.getParseError() == null) {
+                    // The initial preferences only specify the target activity
+                    // component and intent-filter, not the set of matches.  So we
+                    // now need to query for the matches to build the correct
+                    // preferred activity entry.
+                    if (PackageManagerService.DEBUG_PREFERRED) {
+                        Log.d(TAG, "Processing preferred:");
+                        tmpPa.dump(new LogPrinter(Log.DEBUG, TAG), "  ");
+                    }
+                    final ComponentName cn = tmpPa.mPref.mComponent;
+                    Intent intent = new Intent();
+                    int flags = 0;
+                    intent.setAction(tmpPa.getAction(0));
+                    for (int i=0; i<tmpPa.countCategories(); i++) {
+                        String cat = tmpPa.getCategory(i);
+                        if (cat.equals(Intent.CATEGORY_DEFAULT)) {
+                            flags |= PackageManager.MATCH_DEFAULT_ONLY;
+                        } else {
+                            intent.addCategory(cat);
+                        }
+                    }
+                    if (tmpPa.countDataSchemes() > 0) {
+                        Uri.Builder builder = new Uri.Builder();
+                        builder.scheme(tmpPa.getDataScheme(0));
+                        if (tmpPa.countDataAuthorities() > 0) {
+                            IntentFilter.AuthorityEntry auth = tmpPa.getDataAuthority(0);
+                            if (auth.getHost() != null) {
+                                builder.authority(auth.getHost());
+                            }
+                        }
+                        if (tmpPa.countDataPaths() > 0) {
+                            PatternMatcher path = tmpPa.getDataPath(0);
+                            builder.path(path.getPath());
+                        }
+                        intent.setData(builder.build());
+                    } else if (tmpPa.countDataTypes() > 0) {
+                        intent.setType(tmpPa.getDataType(0));
+                    }
+                    List<ResolveInfo> ri = service.mActivities.queryIntent(intent,
+                            intent.getType(), flags, 0);
+                    if (PackageManagerService.DEBUG_PREFERRED) Log.d(TAG, "Queried " + intent
+                            + " results: " + ri);
+                    int match = 0;
+                    if (ri != null && ri.size() > 1) {
+                        boolean haveAct = false;
+                        boolean haveNonSys = false;
+                        ComponentName[] set = new ComponentName[ri.size()];
+                        for (int i=0; i<ri.size(); i++) {
+                            ActivityInfo ai = ri.get(i).activityInfo;
+                            set[i] = new ComponentName(ai.packageName, ai.name);
+                            if ((ai.applicationInfo.flags&ApplicationInfo.FLAG_SYSTEM) == 0) {
+                                // If any of the matches are not system apps, then
+                                // there is a third party app that is now an option...
+                                // so don't set a default since we don't want to hide it.
+                                if (PackageManagerService.DEBUG_PREFERRED) Log.d(TAG, "Result "
+                                        + ai.packageName + "/" + ai.name + ": non-system!");
+                                haveNonSys = true;
+                                break;
+                            } else if (cn.getPackageName().equals(ai.packageName)
+                                    && cn.getClassName().equals(ai.name)) {
+                                if (PackageManagerService.DEBUG_PREFERRED) Log.d(TAG, "Result "
+                                        + ai.packageName + "/" + ai.name + ": default!");
+                                haveAct = true;
+                                match = ri.get(i).match;
+                            } else {
+                                if (PackageManagerService.DEBUG_PREFERRED) Log.d(TAG, "Result "
+                                        + ai.packageName + "/" + ai.name + ": skipped");
+                            }
+                        }
+                        if (haveAct && !haveNonSys) {
+                            PreferredActivity pa = new PreferredActivity(tmpPa, match, set,
+                                    tmpPa.mPref.mComponent);
+                            editPreferredActivitiesLPw(userId).addFilter(pa);
+                        } else if (!haveNonSys) {
+                            Slog.w(TAG, "No component found for default preferred activity "
+                                    + tmpPa.mPref.mComponent);
+                        }
+                    }
+                } else {
+                    PackageManagerService.reportSettingsProblem(Log.WARN,
+                            "Error in package manager settings: <preferred-activity> "
+                                    + tmpPa.mPref.getParseError() + " at "
+                                    + parser.getPositionDescription());
+                }
+            } else {
+                PackageManagerService.reportSettingsProblem(Log.WARN,
+                        "Unknown element under <preferred-activities>: " + parser.getName());
+                XmlUtils.skipCurrentTag(parser);
+            }
+        }
+    }
+
     private int readInt(XmlPullParser parser, String ns, String name, int defValue) {
         String v = parser.getAttributeValue(ns, name);
         try {
@@ -2329,7 +2443,8 @@
         }
     }
 
-    void createNewUserLILPw(Installer installer, int userHandle, File path) {
+    void createNewUserLILPw(PackageManagerService service, Installer installer,
+            int userHandle, File path) {
         path.mkdir();
         FileUtils.setPermissions(path.toString(), FileUtils.S_IRWXU | FileUtils.S_IRWXG
                 | FileUtils.S_IXOTH, -1, -1);
@@ -2340,7 +2455,7 @@
             installer.createUserData(ps.name,
                     UserHandle.getUid(userHandle, ps.appId), userHandle);
         }
-        readDefaultPreferredAppsLPw(userHandle);
+        readDefaultPreferredAppsLPw(service, userHandle);
         writePackageRestrictionsLPr(userHandle);
     }
 
diff --git a/services/jni/com_android_server_BatteryService.cpp b/services/jni/com_android_server_BatteryService.cpp
index e6133af..485c289 100644
--- a/services/jni/com_android_server_BatteryService.cpp
+++ b/services/jni/com_android_server_BatteryService.cpp
@@ -33,6 +33,8 @@
 #include <unistd.h>
 #include <dirent.h>
 #include <linux/ioctl.h>
+#include <utils/Vector.h>
+#include <utils/String8.h>
 
 namespace android {
 
@@ -70,21 +72,28 @@
 static BatteryManagerConstants gConstants;
 
 struct PowerSupplyPaths {
-    char* acOnlinePath;
-    char* usbOnlinePath;
-    char* wirelessOnlinePath;
-    char* batteryStatusPath;
-    char* batteryHealthPath;
-    char* batteryPresentPath;
-    char* batteryCapacityPath;
-    char* batteryVoltagePath;
-    char* batteryTemperaturePath;
-    char* batteryTechnologyPath;
+    String8 batteryStatusPath;
+    String8 batteryHealthPath;
+    String8 batteryPresentPath;
+    String8 batteryCapacityPath;
+    String8 batteryVoltagePath;
+    String8 batteryTemperaturePath;
+    String8 batteryTechnologyPath;
 };
 static PowerSupplyPaths gPaths;
 
+static Vector<String8> gChargerNames;
+
 static int gVoltageDivisor = 1;
 
+enum PowerSupplyType {
+     ANDROID_POWER_SUPPLY_TYPE_UNKNOWN = 0,
+     ANDROID_POWER_SUPPLY_TYPE_AC,
+     ANDROID_POWER_SUPPLY_TYPE_USB,
+     ANDROID_POWER_SUPPLY_TYPE_WIRELESS,
+     ANDROID_POWER_SUPPLY_TYPE_BATTERY
+};
+
 static jint getBatteryStatus(const char* status)
 {
     switch (status[0]) {
@@ -133,13 +142,13 @@
     }
 }
 
-static int readFromFile(const char* path, char* buf, size_t size)
+static int readFromFile(const String8& path, char* buf, size_t size)
 {
     if (!path)
         return -1;
-    int fd = open(path, O_RDONLY, 0);
+    int fd = open(path.string(), O_RDONLY, 0);
     if (fd == -1) {
-        ALOGE("Could not open '%s'", path);
+        ALOGE("Could not open '%s'", path.string());
         return -1;
     }
     
@@ -156,7 +165,7 @@
     return count;
 }
 
-static void setBooleanField(JNIEnv* env, jobject obj, const char* path, jfieldID fieldID)
+static void setBooleanField(JNIEnv* env, jobject obj, const String8& path, jfieldID fieldID)
 {
     const int SIZE = 16;
     char buf[SIZE];
@@ -170,7 +179,7 @@
     env->SetBooleanField(obj, fieldID, value);
 }
 
-static void setIntField(JNIEnv* env, jobject obj, const char* path, jfieldID fieldID)
+static void setIntField(JNIEnv* env, jobject obj, const String8& path, jfieldID fieldID)
 {
     const int SIZE = 128;
     char buf[SIZE];
@@ -182,7 +191,7 @@
     env->SetIntField(obj, fieldID, value);
 }
 
-static void setVoltageField(JNIEnv* env, jobject obj, const char* path, jfieldID fieldID)
+static void setVoltageField(JNIEnv* env, jobject obj, const String8& path, jfieldID fieldID)
 {
     const int SIZE = 128;
     char buf[SIZE];
@@ -195,12 +204,30 @@
     env->SetIntField(obj, fieldID, value);
 }
 
+static PowerSupplyType readPowerSupplyType(const String8& path) {
+    const int SIZE = 128;
+    char buf[SIZE];
+    int length = readFromFile(path, buf, SIZE);
+
+    if (length <= 0)
+        return ANDROID_POWER_SUPPLY_TYPE_UNKNOWN;
+    if (buf[length - 1] == '\n')
+        buf[length - 1] = 0;
+    if (strcmp(buf, "Battery") == 0)
+        return ANDROID_POWER_SUPPLY_TYPE_BATTERY;
+    else if (strcmp(buf, "Mains") == 0 || strcmp(buf, "USB_DCP") == 0 ||
+             strcmp(buf, "USB_CDP") == 0 || strcmp(buf, "USB_ACA") == 0)
+        return ANDROID_POWER_SUPPLY_TYPE_AC;
+    else if (strcmp(buf, "USB") == 0)
+        return ANDROID_POWER_SUPPLY_TYPE_USB;
+    else if (strcmp(buf, "Wireless") == 0)
+        return ANDROID_POWER_SUPPLY_TYPE_WIRELESS;
+    else
+        return ANDROID_POWER_SUPPLY_TYPE_UNKNOWN;
+}
 
 static void android_server_BatteryService_update(JNIEnv* env, jobject obj)
 {
-    setBooleanField(env, obj, gPaths.acOnlinePath, gFieldIds.mAcOnline);
-    setBooleanField(env, obj, gPaths.usbOnlinePath, gFieldIds.mUsbOnline);
-    setBooleanField(env, obj, gPaths.wirelessOnlinePath, gFieldIds.mWirelessOnline);
     setBooleanField(env, obj, gPaths.batteryPresentPath, gFieldIds.mBatteryPresent);
     
     setIntField(env, obj, gPaths.batteryCapacityPath, gFieldIds.mBatteryLevel);
@@ -221,16 +248,54 @@
 
     if (readFromFile(gPaths.batteryTechnologyPath, buf, SIZE) > 0)
         env->SetObjectField(obj, gFieldIds.mBatteryTechnology, env->NewStringUTF(buf));
+
+    unsigned int i;
+    String8 path;
+    jboolean acOnline = false;
+    jboolean usbOnline = false;
+    jboolean wirelessOnline = false;
+
+    for (i = 0; i < gChargerNames.size(); i++) {
+        path.clear();
+        path.appendFormat("%s/%s/online", POWER_SUPPLY_PATH,
+                          gChargerNames[i].string());
+
+        if (readFromFile(path, buf, SIZE) > 0) {
+            if (buf[0] != '0') {
+                path.clear();
+                path.appendFormat("%s/%s/type", POWER_SUPPLY_PATH,
+                                  gChargerNames[i].string());
+                switch(readPowerSupplyType(path)) {
+                case ANDROID_POWER_SUPPLY_TYPE_AC:
+                    acOnline = true;
+                    break;
+                case ANDROID_POWER_SUPPLY_TYPE_USB:
+                    usbOnline = true;
+                    break;
+                case ANDROID_POWER_SUPPLY_TYPE_WIRELESS:
+                    wirelessOnline = true;
+                    break;
+                default:
+                    ALOGW("%s: Unknown power supply type",
+                          gChargerNames[i].string());
+                }
+            }
+        }
+    }
+
+    env->SetBooleanField(obj, gFieldIds.mAcOnline, acOnline);
+    env->SetBooleanField(obj, gFieldIds.mUsbOnline, usbOnline);
+    env->SetBooleanField(obj, gFieldIds.mWirelessOnline, wirelessOnline);
 }
 
 static JNINativeMethod sMethods[] = {
      /* name, signature, funcPtr */
-	{"native_update", "()V", (void*)android_server_BatteryService_update},
+        {"native_update", "()V", (void*)android_server_BatteryService_update},
 };
 
 int register_android_server_BatteryService(JNIEnv* env)
 {
-    char    path[PATH_MAX];
+    String8 path;
     struct dirent* entry;
 
     DIR* dir = opendir(POWER_SUPPLY_PATH);
@@ -247,76 +312,72 @@
 
             char buf[20];
             // Look for "type" file in each subdirectory
-            snprintf(path, sizeof(path), "%s/%s/type", POWER_SUPPLY_PATH, name);
-            int length = readFromFile(path, buf, sizeof(buf));
-            if (length > 0) {
-                if (buf[length - 1] == '\n')
-                    buf[length - 1] = 0;
+            path.clear();
+            path.appendFormat("%s/%s/type", POWER_SUPPLY_PATH, name);
+            switch(readPowerSupplyType(path)) {
+            case ANDROID_POWER_SUPPLY_TYPE_AC:
+            case ANDROID_POWER_SUPPLY_TYPE_USB:
+            case ANDROID_POWER_SUPPLY_TYPE_WIRELESS:
+                path.clear();
+                path.appendFormat("%s/%s/online", POWER_SUPPLY_PATH, name);
+                if (access(path.string(), R_OK) == 0)
+                    gChargerNames.add(String8(name));
+                break;
 
-                if (strcmp(buf, "Mains") == 0) {
-                    snprintf(path, sizeof(path), "%s/%s/online", POWER_SUPPLY_PATH, name);
-                    if (access(path, R_OK) == 0)
-                        gPaths.acOnlinePath = strdup(path);
-                }
-                else if (strcmp(buf, "USB") == 0) {
-                    snprintf(path, sizeof(path), "%s/%s/online", POWER_SUPPLY_PATH, name);
-                    if (access(path, R_OK) == 0)
-                        gPaths.usbOnlinePath = strdup(path);
-                }
-                else if (strcmp(buf, "Wireless") == 0) {
-                    snprintf(path, sizeof(path), "%s/%s/online", POWER_SUPPLY_PATH, name);
-                    if (access(path, R_OK) == 0)
-                        gPaths.wirelessOnlinePath = strdup(path);
-                }
-                else if (strcmp(buf, "Battery") == 0) {
-                    snprintf(path, sizeof(path), "%s/%s/status", POWER_SUPPLY_PATH, name);
-                    if (access(path, R_OK) == 0)
-                        gPaths.batteryStatusPath = strdup(path);
-                    snprintf(path, sizeof(path), "%s/%s/health", POWER_SUPPLY_PATH, name);
-                    if (access(path, R_OK) == 0)
-                        gPaths.batteryHealthPath = strdup(path);
-                    snprintf(path, sizeof(path), "%s/%s/present", POWER_SUPPLY_PATH, name);
-                    if (access(path, R_OK) == 0)
-                        gPaths.batteryPresentPath = strdup(path);
-                    snprintf(path, sizeof(path), "%s/%s/capacity", POWER_SUPPLY_PATH, name);
-                    if (access(path, R_OK) == 0)
-                        gPaths.batteryCapacityPath = strdup(path);
+            case ANDROID_POWER_SUPPLY_TYPE_BATTERY:
+                path.clear();
+                path.appendFormat("%s/%s/status", POWER_SUPPLY_PATH, name);
+                if (access(path, R_OK) == 0)
+                    gPaths.batteryStatusPath = path;
+                path.clear();
+                path.appendFormat("%s/%s/health", POWER_SUPPLY_PATH, name);
+                if (access(path, R_OK) == 0)
+                    gPaths.batteryHealthPath = path;
+                path.clear();
+                path.appendFormat("%s/%s/present", POWER_SUPPLY_PATH, name);
+                if (access(path, R_OK) == 0)
+                    gPaths.batteryPresentPath = path;
+                path.clear();
+                path.appendFormat("%s/%s/capacity", POWER_SUPPLY_PATH, name);
+                if (access(path, R_OK) == 0)
+                    gPaths.batteryCapacityPath = path;
 
-                    snprintf(path, sizeof(path), "%s/%s/voltage_now", POWER_SUPPLY_PATH, name);
-                    if (access(path, R_OK) == 0) {
-                        gPaths.batteryVoltagePath = strdup(path);
-                        // voltage_now is in microvolts, not millivolts
-                        gVoltageDivisor = 1000;
-                    } else {
-                        snprintf(path, sizeof(path), "%s/%s/batt_vol", POWER_SUPPLY_PATH, name);
-                        if (access(path, R_OK) == 0)
-                            gPaths.batteryVoltagePath = strdup(path);
-                    }
-
-                    snprintf(path, sizeof(path), "%s/%s/temp", POWER_SUPPLY_PATH, name);
-                    if (access(path, R_OK) == 0) {
-                        gPaths.batteryTemperaturePath = strdup(path);
-                    } else {
-                        snprintf(path, sizeof(path), "%s/%s/batt_temp", POWER_SUPPLY_PATH, name);
-                        if (access(path, R_OK) == 0)
-                            gPaths.batteryTemperaturePath = strdup(path);
-                    }
-
-                    snprintf(path, sizeof(path), "%s/%s/technology", POWER_SUPPLY_PATH, name);
+                path.clear();
+                path.appendFormat("%s/%s/voltage_now", POWER_SUPPLY_PATH, name);
+                if (access(path, R_OK) == 0) {
+                    gPaths.batteryVoltagePath = path;
+                    // voltage_now is in microvolts, not millivolts
+                    gVoltageDivisor = 1000;
+                } else {
+                    path.clear();
+                    path.appendFormat("%s/%s/batt_vol", POWER_SUPPLY_PATH, name);
                     if (access(path, R_OK) == 0)
-                        gPaths.batteryTechnologyPath = strdup(path);
+                            gPaths.batteryVoltagePath = path;
                 }
+
+                path.clear();
+                path.appendFormat("%s/%s/temp", POWER_SUPPLY_PATH, name);
+                if (access(path, R_OK) == 0) {
+                    gPaths.batteryTemperaturePath = path;
+                } else {
+                    path.clear();
+                    path.appendFormat("%s/%s/batt_temp", POWER_SUPPLY_PATH, name);
+                    if (access(path, R_OK) == 0)
+                            gPaths.batteryTemperaturePath = path;
+                }
+
+                path.clear();
+                path.appendFormat("%s/%s/technology", POWER_SUPPLY_PATH, name);
+                if (access(path, R_OK) == 0)
+                    gPaths.batteryTechnologyPath = path;
+                break;
             }
         }
         closedir(dir);
     }
 
-    if (!gPaths.acOnlinePath)
-        ALOGE("acOnlinePath not found");
-    if (!gPaths.usbOnlinePath)
-        ALOGE("usbOnlinePath not found");
-    if (!gPaths.wirelessOnlinePath)
-        ALOGE("wirelessOnlinePath not found");
+    if (!gChargerNames.size())
+        ALOGE("No charger supplies found");
     if (!gPaths.batteryStatusPath)
         ALOGE("batteryStatusPath not found");
     if (!gPaths.batteryHealthPath)
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java b/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java
index 0f531b7..1ab5f45 100644
--- a/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java
@@ -139,7 +139,7 @@
         // Write the package files and make sure they're parsed properly the first time
         writeOldFiles();
         Settings settings = new Settings(getContext(), getContext().getFilesDir());
-        assertEquals(true, settings.readLPw(null, 0, false));
+        assertEquals(true, settings.readLPw(null, null, 0, false));
         assertNotNull(settings.peekPackageLPr(PACKAGE_NAME_3));
         assertNotNull(settings.peekPackageLPr(PACKAGE_NAME_1));
 
@@ -157,11 +157,11 @@
         // Write the package files and make sure they're parsed properly the first time
         writeOldFiles();
         Settings settings = new Settings(getContext(), getContext().getFilesDir());
-        assertEquals(true, settings.readLPw(null, 0, false));
+        assertEquals(true, settings.readLPw(null, null, 0, false));
 
         // Create Settings again to make it read from the new files
         settings = new Settings(getContext(), getContext().getFilesDir());
-        assertEquals(true, settings.readLPw(null, 0, false));
+        assertEquals(true, settings.readLPw(null, null, 0, false));
 
         PackageSetting ps = settings.peekPackageLPr(PACKAGE_NAME_2);
         assertEquals(COMPONENT_ENABLED_STATE_DISABLED_USER, ps.getEnabled(0));
@@ -172,7 +172,7 @@
         // Write the package files and make sure they're parsed properly the first time
         writeOldFiles();
         Settings settings = new Settings(getContext(), getContext().getFilesDir());
-        assertEquals(true, settings.readLPw(null, 0, false));
+        assertEquals(true, settings.readLPw(null, null, 0, false));
 
         // Enable/Disable a package
         PackageSetting ps = settings.peekPackageLPr(PACKAGE_NAME_1);
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/ClipRegionActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/ClipRegionActivity.java
index 3d3d709..774811e 100644
--- a/tests/HwAccelerationTest/src/com/android/test/hwui/ClipRegionActivity.java
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/ClipRegionActivity.java
@@ -61,6 +61,7 @@
 
         public RegionView(Context c) {
             super(c);
+            setAlpha(0.5f);
         }
 
         public float getClipPosition() {