Merge "Import translations. DO NOT MERGE" into lmp-mr1-dev
diff --git a/Android.mk b/Android.mk
index 51a9846..a596ee7 100644
--- a/Android.mk
+++ b/Android.mk
@@ -402,9 +402,6 @@
 
 LOCAL_RMTYPEDEFS := true
 
-# List of classes and interfaces which should be loaded by the Zygote.
-LOCAL_JAVA_RESOURCE_FILES += $(LOCAL_PATH)/preloaded-classes
-
 include $(BUILD_JAVA_LIBRARY)
 framework_module := $(LOCAL_INSTALLED_MODULE)
 
diff --git a/api/current.txt b/api/current.txt
index e812a8a..46a0943 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -12821,6 +12821,7 @@
     field public static final int NOISE_REDUCTION_MODE_HIGH_QUALITY = 2; // 0x2
     field public static final int NOISE_REDUCTION_MODE_OFF = 0; // 0x0
     field public static final int REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE = 0; // 0x0
+    field public static final int REQUEST_AVAILABLE_CAPABILITIES_BURST_CAPTURE = 6; // 0x6
     field public static final int REQUEST_AVAILABLE_CAPABILITIES_MANUAL_POST_PROCESSING = 2; // 0x2
     field public static final int REQUEST_AVAILABLE_CAPABILITIES_MANUAL_SENSOR = 1; // 0x1
     field public static final int REQUEST_AVAILABLE_CAPABILITIES_RAW = 3; // 0x3
diff --git a/core/java/android/hardware/camera2/CameraCharacteristics.java b/core/java/android/hardware/camera2/CameraCharacteristics.java
index eec98b6..754f270 100644
--- a/core/java/android/hardware/camera2/CameraCharacteristics.java
+++ b/core/java/android/hardware/camera2/CameraCharacteristics.java
@@ -1156,6 +1156,7 @@
      *   <li>{@link #REQUEST_AVAILABLE_CAPABILITIES_MANUAL_POST_PROCESSING MANUAL_POST_PROCESSING}</li>
      *   <li>{@link #REQUEST_AVAILABLE_CAPABILITIES_RAW RAW}</li>
      *   <li>{@link #REQUEST_AVAILABLE_CAPABILITIES_READ_SENSOR_SETTINGS READ_SENSOR_SETTINGS}</li>
+     *   <li>{@link #REQUEST_AVAILABLE_CAPABILITIES_BURST_CAPTURE BURST_CAPTURE}</li>
      * </ul></p>
      * <p>This key is available on all devices.</p>
      *
@@ -1165,6 +1166,7 @@
      * @see #REQUEST_AVAILABLE_CAPABILITIES_MANUAL_POST_PROCESSING
      * @see #REQUEST_AVAILABLE_CAPABILITIES_RAW
      * @see #REQUEST_AVAILABLE_CAPABILITIES_READ_SENSOR_SETTINGS
+     * @see #REQUEST_AVAILABLE_CAPABILITIES_BURST_CAPTURE
      */
     @PublicKey
     public static final Key<int[]> REQUEST_AVAILABLE_CAPABILITIES =
@@ -2285,12 +2287,16 @@
      * <p>Camera devices will come in three flavors: LEGACY, LIMITED and FULL.</p>
      * <p>A FULL device will support below capabilities:</p>
      * <ul>
-     * <li>30fps at maximum resolution (== sensor resolution) is preferred, more than 20fps is required.</li>
+     * <li>30fps operation at maximum resolution (== sensor resolution) is preferred, more than
+     *   20fps is required, for at least uncompressed YUV
+     *   output. ({@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES android.request.availableCapabilities} contains BURST_CAPTURE)</li>
      * <li>Per frame control ({@link CameraCharacteristics#SYNC_MAX_LATENCY android.sync.maxLatency} <code>==</code> PER_FRAME_CONTROL)</li>
      * <li>Manual sensor control ({@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES android.request.availableCapabilities} contains MANUAL_SENSOR)</li>
-     * <li>Manual post-processing control ({@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES android.request.availableCapabilities} contains MANUAL_POST_PROCESSING)</li>
+     * <li>Manual post-processing control ({@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES android.request.availableCapabilities} contains
+     *   MANUAL_POST_PROCESSING)</li>
      * <li>Arbitrary cropping region ({@link CameraCharacteristics#SCALER_CROPPING_TYPE android.scaler.croppingType} <code>==</code> FREEFORM)</li>
-     * <li>At least 3 processed (but not stalling) format output streams ({@link CameraCharacteristics#REQUEST_MAX_NUM_OUTPUT_PROC android.request.maxNumOutputProc} <code>&gt;=</code> 3)</li>
+     * <li>At least 3 processed (but not stalling) format output streams
+     *   ({@link CameraCharacteristics#REQUEST_MAX_NUM_OUTPUT_PROC android.request.maxNumOutputProc} <code>&gt;=</code> 3)</li>
      * <li>The required stream configuration defined in android.scaler.availableStreamConfigurations</li>
      * <li>The required exposure time range defined in {@link CameraCharacteristics#SENSOR_INFO_EXPOSURE_TIME_RANGE android.sensor.info.exposureTimeRange}</li>
      * <li>The required maxFrameDuration defined in {@link CameraCharacteristics#SENSOR_INFO_MAX_FRAME_DURATION android.sensor.info.maxFrameDuration}</li>
diff --git a/core/java/android/hardware/camera2/CameraDevice.java b/core/java/android/hardware/camera2/CameraDevice.java
index 0bb742c..9e90d01 100644
--- a/core/java/android/hardware/camera2/CameraDevice.java
+++ b/core/java/android/hardware/camera2/CameraDevice.java
@@ -334,6 +334,24 @@
      * </table><br>
      * </p>
      *
+     * <p>BURST-capability ({@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES} includes
+     * {@link CameraMetadata#REQUEST_AVAILABLE_CAPABILITIES_BURST_CAPTURE BURST_CAPTURE}) devices
+     * support at least the below stream combinations in addition to those for
+     * {@link CameraMetadata#INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED LIMITED} devices. Note that all
+     * FULL-level devices support the BURST capability, and the below list is a strict subset of the
+     * list for FULL-level devices, so this table is only relevant for LIMITED-level devices that
+     * support the BURST_CAPTURE capability.
+     *
+     * <table>
+     * <tr><th colspan="5">BURST-capability additional guaranteed configurations</th></tr>
+     * <tr><th colspan="2" id="rb">Target 1</th><th colspan="2" id="rb">Target 2</th><th rowspan="2">Sample use case(s)</th> </tr>
+     * <tr><th>Type</th><th id="rb">Max size</th><th>Type</th><th id="rb">Max size</th> </tr>
+     * <tr> <td>{@code PRIV}</td><td id="rb">{@code PREVIEW}</td> <td>{@code PRIV}</td><td id="rb">{@code MAXIMUM}</td> <td>Maximum-resolution GPU processing with preview.</td> </tr>
+     * <tr> <td>{@code PRIV}</td><td id="rb">{@code PREVIEW}</td> <td>{@code YUV }</td><td id="rb">{@code MAXIMUM}</td> <td>Maximum-resolution in-app processing with preview.</td> </tr>
+     * <tr> <td>{@code YUV }</td><td id="rb">{@code PREVIEW}</td> <td>{@code YUV }</td><td id="rb">{@code MAXIMUM}</td> <td>Maximum-resolution two-input in-app processsing.</td> </tr>
+     * </table><br>
+     * </p>
+     *
      * <p>Since the capabilities of camera devices vary greatly, a given camera device may support
      * target combinations with sizes outside of these guarantees, but this can only be tested for
      * by attempting to create a session with such targets.</p>
diff --git a/core/java/android/hardware/camera2/CameraMetadata.java b/core/java/android/hardware/camera2/CameraMetadata.java
index 67cd021..271fc30 100644
--- a/core/java/android/hardware/camera2/CameraMetadata.java
+++ b/core/java/android/hardware/camera2/CameraMetadata.java
@@ -482,6 +482,26 @@
      */
     public static final int REQUEST_AVAILABLE_CAPABILITIES_READ_SENSOR_SETTINGS = 5;
 
+    /**
+     * <p>The camera device supports capturing maximum-resolution
+     * images at &gt;= 20 frames per second, in at least the
+     * uncompressed YUV format, when post-processing settings
+     * are set to FAST.</p>
+     * <p>More specifically, this means that a size matching the
+     * camera device's active array size is listed as a
+     * supported size for the YUV_420_888 format in
+     * {@link CameraCharacteristics#SCALER_STREAM_CONFIGURATION_MAP android.scaler.streamConfigurationMap}, and the
+     * minimum frame duration for that format and size is &lt;=
+     * 1/20 s.</p>
+     * <p>In addition, the {@link CameraCharacteristics#SYNC_MAX_LATENCY android.sync.maxLatency} field is
+     * guaranted to have a value between 0 and 4, inclusive.</p>
+     *
+     * @see CameraCharacteristics#SCALER_STREAM_CONFIGURATION_MAP
+     * @see CameraCharacteristics#SYNC_MAX_LATENCY
+     * @see CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES
+     */
+    public static final int REQUEST_AVAILABLE_CAPABILITIES_BURST_CAPTURE = 6;
+
     //
     // Enumeration values for CameraCharacteristics#SCALER_CROPPING_TYPE
     //
@@ -1259,8 +1279,7 @@
      * image while recording video) use case.</p>
      * <p>The camera device should take the highest-quality image
      * possible (given the other settings) without disrupting the
-     * frame rate of video recording.<br />
-     * </p>
+     * frame rate of video recording.  </p>
      * @see CaptureRequest#CONTROL_CAPTURE_INTENT
      */
     public static final int CONTROL_CAPTURE_INTENT_VIDEO_SNAPSHOT = 4;
diff --git a/core/java/android/os/Build.java b/core/java/android/os/Build.java
index f361695b..4b0cef6 100644
--- a/core/java/android/os/Build.java
+++ b/core/java/android/os/Build.java
@@ -20,8 +20,11 @@
 import android.util.Slog;
 
 import com.android.internal.telephony.TelephonyProperties;
+
 import dalvik.system.VMRuntime;
 
+import java.util.Objects;
+
 /**
  * Information about the current build, extracted from system properties.
  */
@@ -640,6 +643,32 @@
         }
     }
 
+    /**
+     * Check that device fingerprint is defined and that it matches across
+     * various partitions.
+     *
+     * @hide
+     */
+    public static boolean isFingerprintConsistent() {
+        final String system = SystemProperties.get("ro.build.fingerprint");
+        final String vendor = SystemProperties.get("ro.vendor.build.fingerprint");
+
+        if (TextUtils.isEmpty(system)) {
+            Slog.e(TAG, "Required ro.build.fingerprint is empty!");
+            return false;
+        }
+
+        if (!TextUtils.isEmpty(vendor)) {
+            if (!Objects.equals(system, vendor)) {
+                Slog.e(TAG, "Mismatched fingerprints; system reported " + system
+                        + " but vendor reported " + vendor);
+                return false;
+            }
+        }
+
+        return true;
+    }
+
     // The following properties only make sense for internal engineering builds.
     public static final long TIME = getLong("ro.build.date.utc") * 1000;
     public static final String USER = getString("ro.build.user");
diff --git a/core/java/android/view/Surface.java b/core/java/android/view/Surface.java
index 19142b8..33ce517 100644
--- a/core/java/android/view/Surface.java
+++ b/core/java/android/view/Surface.java
@@ -53,6 +53,9 @@
 
     private static native void nativeAllocateBuffers(long nativeObject);
 
+    private static native int nativeGetWidth(long nativeObject);
+    private static native int nativeGetHeight(long nativeObject);
+
     public static final Parcelable.Creator<Surface> CREATOR =
             new Parcelable.Creator<Surface>() {
         @Override
@@ -327,7 +330,9 @@
             if (mHwuiContext == null) {
                 mHwuiContext = new HwuiContext();
             }
-            return mHwuiContext.lockCanvas();
+            return mHwuiContext.lockCanvas(
+                    nativeGetWidth(mNativeObject),
+                    nativeGetHeight(mNativeObject));
         }
     }
 
@@ -576,11 +581,11 @@
             mHwuiRenderer = nHwuiCreate(mRenderNode.mNativeRenderNode, mNativeObject);
         }
 
-        Canvas lockCanvas() {
+        Canvas lockCanvas(int width, int height) {
             if (mCanvas != null) {
                 throw new IllegalStateException("Surface was already locked!");
             }
-            mCanvas = mRenderNode.start(0, 0);
+            mCanvas = mRenderNode.start(width, height);
             return mCanvas;
         }
 
diff --git a/core/java/com/android/internal/os/ZygoteInit.java b/core/java/com/android/internal/os/ZygoteInit.java
index 4dde217..d95cf71 100644
--- a/core/java/com/android/internal/os/ZygoteInit.java
+++ b/core/java/com/android/internal/os/ZygoteInit.java
@@ -45,6 +45,8 @@
 
 import java.io.BufferedReader;
 import java.io.FileDescriptor;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.InputStreamReader;
@@ -97,9 +99,9 @@
     static final int GC_LOOP_COUNT = 10;
 
     /**
-     * The name of a resource file that contains classes to preload.
+     * The path of a file that contains classes to preload.
      */
-    private static final String PRELOADED_CLASSES = "preloaded-classes";
+    private static final String PRELOADED_CLASSES = "/system/etc/preloaded-classes";
 
     /** Controls whether we should preload resources during zygote init. */
     private static final boolean PRELOAD_RESOURCES = true;
@@ -284,90 +286,92 @@
     private static void preloadClasses() {
         final VMRuntime runtime = VMRuntime.getRuntime();
 
-        InputStream is = ClassLoader.getSystemClassLoader().getResourceAsStream(
-                PRELOADED_CLASSES);
-        if (is == null) {
+        InputStream is;
+        try {
+            is = new FileInputStream(PRELOADED_CLASSES);
+        } catch (FileNotFoundException e) {
             Log.e(TAG, "Couldn't find " + PRELOADED_CLASSES + ".");
-        } else {
-            Log.i(TAG, "Preloading classes...");
-            long startTime = SystemClock.uptimeMillis();
+            return;
+        }
 
-            // Drop root perms while running static initializers.
-            setEffectiveGroup(UNPRIVILEGED_GID);
-            setEffectiveUser(UNPRIVILEGED_UID);
+        Log.i(TAG, "Preloading classes...");
+        long startTime = SystemClock.uptimeMillis();
 
-            // Alter the target heap utilization.  With explicit GCs this
-            // is not likely to have any effect.
-            float defaultUtilization = runtime.getTargetHeapUtilization();
-            runtime.setTargetHeapUtilization(0.8f);
+        // Drop root perms while running static initializers.
+        setEffectiveGroup(UNPRIVILEGED_GID);
+        setEffectiveUser(UNPRIVILEGED_UID);
 
-            // Start with a clean slate.
-            System.gc();
-            runtime.runFinalizationSync();
-            Debug.startAllocCounting();
+        // Alter the target heap utilization.  With explicit GCs this
+        // is not likely to have any effect.
+        float defaultUtilization = runtime.getTargetHeapUtilization();
+        runtime.setTargetHeapUtilization(0.8f);
 
-            try {
-                BufferedReader br
-                    = new BufferedReader(new InputStreamReader(is), 256);
+        // Start with a clean slate.
+        System.gc();
+        runtime.runFinalizationSync();
+        Debug.startAllocCounting();
 
-                int count = 0;
-                String line;
-                while ((line = br.readLine()) != null) {
-                    // Skip comments and blank lines.
-                    line = line.trim();
-                    if (line.startsWith("#") || line.equals("")) {
-                        continue;
-                    }
+        try {
+            BufferedReader br
+                = new BufferedReader(new InputStreamReader(is), 256);
 
-                    try {
-                        if (false) {
-                            Log.v(TAG, "Preloading " + line + "...");
-                        }
-                        Class.forName(line);
-                        if (Debug.getGlobalAllocSize() > PRELOAD_GC_THRESHOLD) {
-                            if (false) {
-                                Log.v(TAG,
-                                    " GC at " + Debug.getGlobalAllocSize());
-                            }
-                            System.gc();
-                            runtime.runFinalizationSync();
-                            Debug.resetGlobalAllocSize();
-                        }
-                        count++;
-                    } catch (ClassNotFoundException e) {
-                        Log.w(TAG, "Class not found for preloading: " + line);
-                    } catch (UnsatisfiedLinkError e) {
-                        Log.w(TAG, "Problem preloading " + line + ": " + e);
-                    } catch (Throwable t) {
-                        Log.e(TAG, "Error preloading " + line + ".", t);
-                        if (t instanceof Error) {
-                            throw (Error) t;
-                        }
-                        if (t instanceof RuntimeException) {
-                            throw (RuntimeException) t;
-                        }
-                        throw new RuntimeException(t);
-                    }
+            int count = 0;
+            String line;
+            while ((line = br.readLine()) != null) {
+                // Skip comments and blank lines.
+                line = line.trim();
+                if (line.startsWith("#") || line.equals("")) {
+                    continue;
                 }
 
-                Log.i(TAG, "...preloaded " + count + " classes in "
-                        + (SystemClock.uptimeMillis()-startTime) + "ms.");
-            } catch (IOException e) {
-                Log.e(TAG, "Error reading " + PRELOADED_CLASSES + ".", e);
-            } finally {
-                IoUtils.closeQuietly(is);
-                // Restore default.
-                runtime.setTargetHeapUtilization(defaultUtilization);
-
-                // Fill in dex caches with classes, fields, and methods brought in by preloading.
-                runtime.preloadDexCaches();
-
-                Debug.stopAllocCounting();
-
-                // Bring back root. We'll need it later.
-                setEffectiveUser(ROOT_UID);
-                setEffectiveGroup(ROOT_GID);
+                try {
+                    if (false) {
+                        Log.v(TAG, "Preloading " + line + "...");
+                    }
+                    Class.forName(line);
+                    if (Debug.getGlobalAllocSize() > PRELOAD_GC_THRESHOLD) {
+                        if (false) {
+                            Log.v(TAG,
+                                " GC at " + Debug.getGlobalAllocSize());
+                        }
+                        System.gc();
+                        runtime.runFinalizationSync();
+                        Debug.resetGlobalAllocSize();
+                    }
+                    count++;
+                } catch (ClassNotFoundException e) {
+                    Log.w(TAG, "Class not found for preloading: " + line);
+                } catch (UnsatisfiedLinkError e) {
+                    Log.w(TAG, "Problem preloading " + line + ": " + e);
+                } catch (Throwable t) {
+                    Log.e(TAG, "Error preloading " + line + ".", t);
+                    if (t instanceof Error) {
+                        throw (Error) t;
+                    }
+                    if (t instanceof RuntimeException) {
+                        throw (RuntimeException) t;
+                    }
+                    throw new RuntimeException(t);
+                }
             }
+
+            Log.i(TAG, "...preloaded " + count + " classes in "
+                    + (SystemClock.uptimeMillis()-startTime) + "ms.");
+        } catch (IOException e) {
+            Log.e(TAG, "Error reading " + PRELOADED_CLASSES + ".", e);
+        } finally {
+            IoUtils.closeQuietly(is);
+            // Restore default.
+            runtime.setTargetHeapUtilization(defaultUtilization);
+
+            // Fill in dex caches with classes, fields, and methods brought in by preloading.
+            runtime.preloadDexCaches();
+
+            Debug.stopAllocCounting();
+
+            // Bring back root. We'll need it later.
+            setEffectiveUser(ROOT_UID);
+            setEffectiveGroup(ROOT_GID);
         }
     }
 
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index 4d17877..c5f1d88 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -356,6 +356,15 @@
     return 0;
 }
 
+static bool hasFile(const char* file) {
+    struct stat s;
+    int res = stat(file, &s);
+    if (res == 0) {
+        return S_ISREG(s.st_mode);
+    }
+    return false;
+}
+
 /*
  * Read the persistent locale.
  */
@@ -768,10 +777,16 @@
             parseCompilerOption("dalvik.vm.image-dex2oat-filter", dex2oatImageCompilerFilterBuf,
                                 "--compiler-filter=", "-Ximage-compiler-option");
         }
+
+        // Make sure there is a preloaded-classes file.
+        if (!hasFile("/system/etc/preloaded-classes")) {
+            ALOGE("Missing preloaded-classes file, /system/etc/preloaded-classes not found: %s\n",
+                  strerror(errno));
+            goto bail;
+        }
         addOption("-Ximage-compiler-option");
-        addOption("--image-classes-zip=/system/framework/framework.jar");
-        addOption("-Ximage-compiler-option");
-        addOption("--image-classes=preloaded-classes");
+        addOption("--image-classes=/system/etc/preloaded-classes");
+
         property_get("dalvik.vm.image-dex2oat-flags", dex2oatImageFlagsBuf, "");
         parseExtraOpts(dex2oatImageFlagsBuf, "-Ximage-compiler-option");
 
diff --git a/core/jni/android_util_AssetManager.cpp b/core/jni/android_util_AssetManager.cpp
index 94098c9..fba7255 100644
--- a/core/jni/android_util_AssetManager.cpp
+++ b/core/jni/android_util_AssetManager.cpp
@@ -33,6 +33,7 @@
 
 #include <androidfw/Asset.h>
 #include <androidfw/AssetManager.h>
+#include <androidfw/AttributeFinder.h>
 #include <androidfw/ResourceTypes.h>
 
 #include <private/android_filesystem_config.h> // for AID_SYSTEM
@@ -999,6 +1000,30 @@
     theme->dumpToLog();
 }
 
+class XmlAttributeFinder : public BackTrackingAttributeFinder<XmlAttributeFinder, jsize> {
+public:
+    XmlAttributeFinder(const ResXMLParser* parser)
+        : BackTrackingAttributeFinder(0, parser != NULL ? parser->getAttributeCount() : 0)
+        , mParser(parser) {}
+
+    inline uint32_t getAttribute(jsize index) const {
+        return mParser->getAttributeNameResID(index);
+    }
+
+private:
+    const ResXMLParser* mParser;
+};
+
+class BagAttributeFinder : public BackTrackingAttributeFinder<BagAttributeFinder, const ResTable::bag_entry*> {
+public:
+    BagAttributeFinder(const ResTable::bag_entry* start, const ResTable::bag_entry* end)
+        : BackTrackingAttributeFinder(start, end) {}
+
+    inline uint32_t getAttribute(const ResTable::bag_entry* entry) const {
+        return entry->map.name.ident;
+    }
+};
+
 static jboolean android_content_AssetManager_resolveAttrs(JNIEnv* env, jobject clazz,
                                                           jlong themeToken,
                                                           jint defStyleAttr,
@@ -1074,13 +1099,13 @@
     res.lock();
 
     // Retrieve the default style bag, if requested.
-    const ResTable::bag_entry* defStyleEnt = NULL;
+    const ResTable::bag_entry* defStyleStart = NULL;
     uint32_t defStyleTypeSetFlags = 0;
     ssize_t bagOff = defStyleRes != 0
-            ? res.getBagLocked(defStyleRes, &defStyleEnt, &defStyleTypeSetFlags) : -1;
+            ? res.getBagLocked(defStyleRes, &defStyleStart, &defStyleTypeSetFlags) : -1;
     defStyleTypeSetFlags |= defStyleBagTypeSetFlags;
-    const ResTable::bag_entry* endDefStyleEnt = defStyleEnt +
-        (bagOff >= 0 ? bagOff : 0);;
+    const ResTable::bag_entry* const defStyleEnd = defStyleStart + (bagOff >= 0 ? bagOff : 0);
+    BagAttributeFinder defStyleAttrFinder(defStyleStart, defStyleEnd);
 
     // Now iterate through all of the attributes that the client has requested,
     // filling in each with whatever data we can find.
@@ -1108,20 +1133,15 @@
                     value.dataType, value.data));
         }
 
-        // Skip through the default style values until the end or the next possible match.
-        while (defStyleEnt < endDefStyleEnt && curIdent > defStyleEnt->map.name.ident) {
-            defStyleEnt++;
-        }
-        // Retrieve the current default style attribute if it matches, and step to next.
-        if (defStyleEnt < endDefStyleEnt && curIdent == defStyleEnt->map.name.ident) {
-            if (value.dataType == Res_value::TYPE_NULL) {
-                block = defStyleEnt->stringBlock;
+        if (value.dataType == Res_value::TYPE_NULL) {
+            const ResTable::bag_entry* const defStyleEntry = defStyleAttrFinder.find(curIdent);
+            if (defStyleEntry != defStyleEnd) {
+                block = defStyleEntry->stringBlock;
                 typeSetFlags = defStyleTypeSetFlags;
-                value = defStyleEnt->map.value;
+                value = defStyleEntry->map.value;
                 DEBUG_STYLES(ALOGI("-> From def style: type=0x%x, data=0x%08x",
                         value.dataType, value.data));
             }
-            defStyleEnt++;
         }
 
         uint32_t resid = 0;
@@ -1284,34 +1304,32 @@
     res.lock();
 
     // Retrieve the default style bag, if requested.
-    const ResTable::bag_entry* defStyleEnt = NULL;
+    const ResTable::bag_entry* defStyleAttrStart = NULL;
     uint32_t defStyleTypeSetFlags = 0;
     ssize_t bagOff = defStyleRes != 0
-            ? res.getBagLocked(defStyleRes, &defStyleEnt, &defStyleTypeSetFlags) : -1;
+            ? res.getBagLocked(defStyleRes, &defStyleAttrStart, &defStyleTypeSetFlags) : -1;
     defStyleTypeSetFlags |= defStyleBagTypeSetFlags;
-    const ResTable::bag_entry* endDefStyleEnt = defStyleEnt +
-        (bagOff >= 0 ? bagOff : 0);
+    const ResTable::bag_entry* const defStyleAttrEnd = defStyleAttrStart + (bagOff >= 0 ? bagOff : 0);
+    BagAttributeFinder defStyleAttrFinder(defStyleAttrStart, defStyleAttrEnd);
 
     // Retrieve the style class bag, if requested.
-    const ResTable::bag_entry* styleEnt = NULL;
+    const ResTable::bag_entry* styleAttrStart = NULL;
     uint32_t styleTypeSetFlags = 0;
-    bagOff = style != 0 ? res.getBagLocked(style, &styleEnt, &styleTypeSetFlags) : -1;
+    bagOff = style != 0 ? res.getBagLocked(style, &styleAttrStart, &styleTypeSetFlags) : -1;
     styleTypeSetFlags |= styleBagTypeSetFlags;
-    const ResTable::bag_entry* endStyleEnt = styleEnt +
-        (bagOff >= 0 ? bagOff : 0);
+    const ResTable::bag_entry* const styleAttrEnd = styleAttrStart + (bagOff >= 0 ? bagOff : 0);
+    BagAttributeFinder styleAttrFinder(styleAttrStart, styleAttrEnd);
 
     // Retrieve the XML attributes, if requested.
-    const jsize NX = xmlParser ? xmlParser->getAttributeCount() : 0;
-    jsize ix=0;
-    uint32_t curXmlAttr = xmlParser ? xmlParser->getAttributeNameResID(ix) : 0;
-
     static const ssize_t kXmlBlock = 0x10000000;
+    XmlAttributeFinder xmlAttrFinder(xmlParser);
+    const jsize xmlAttrEnd = xmlParser != NULL ? xmlParser->getAttributeCount() : 0;
 
     // Now iterate through all of the attributes that the client has requested,
     // filling in each with whatever data we can find.
     ssize_t block = 0;
     uint32_t typeSetFlags;
-    for (jsize ii=0; ii<NI; ii++) {
+    for (jsize ii = 0; ii < NI; ii++) {
         const uint32_t curIdent = (uint32_t)src[ii];
 
         DEBUG_STYLES(ALOGI("RETRIEVING ATTR 0x%08x...", curIdent));
@@ -1324,51 +1342,40 @@
         typeSetFlags = 0;
         config.density = 0;
 
-        // Skip through XML attributes until the end or the next possible match.
-        while (ix < NX && curIdent > curXmlAttr) {
-            ix++;
-            curXmlAttr = xmlParser->getAttributeNameResID(ix);
-        }
-        // Retrieve the current XML attribute if it matches, and step to next.
-        if (ix < NX && curIdent == curXmlAttr) {
+        // Walk through the xml attributes looking for the requested attribute.
+        const jsize xmlAttrIdx = xmlAttrFinder.find(curIdent);
+        if (xmlAttrIdx != xmlAttrEnd) {
+            // We found the attribute we were looking for.
             block = kXmlBlock;
-            xmlParser->getAttributeValue(ix, &value);
-            ix++;
-            curXmlAttr = xmlParser->getAttributeNameResID(ix);
+            xmlParser->getAttributeValue(xmlAttrIdx, &value);
             DEBUG_STYLES(ALOGI("-> From XML: type=0x%x, data=0x%08x",
                     value.dataType, value.data));
         }
 
-        // Skip through the style values until the end or the next possible match.
-        while (styleEnt < endStyleEnt && curIdent > styleEnt->map.name.ident) {
-            styleEnt++;
-        }
-        // Retrieve the current style attribute if it matches, and step to next.
-        if (styleEnt < endStyleEnt && curIdent == styleEnt->map.name.ident) {
-            if (value.dataType == Res_value::TYPE_NULL) {
-                block = styleEnt->stringBlock;
+        if (value.dataType == Res_value::TYPE_NULL) {
+            // Walk through the style class values looking for the requested attribute.
+            const ResTable::bag_entry* const styleAttrEntry = styleAttrFinder.find(curIdent);
+            if (styleAttrEntry != styleAttrEnd) {
+                // We found the attribute we were looking for.
+                block = styleAttrEntry->stringBlock;
                 typeSetFlags = styleTypeSetFlags;
-                value = styleEnt->map.value;
+                value = styleAttrEntry->map.value;
                 DEBUG_STYLES(ALOGI("-> From style: type=0x%x, data=0x%08x",
                         value.dataType, value.data));
             }
-            styleEnt++;
         }
 
-        // Skip through the default style values until the end or the next possible match.
-        while (defStyleEnt < endDefStyleEnt && curIdent > defStyleEnt->map.name.ident) {
-            defStyleEnt++;
-        }
-        // Retrieve the current default style attribute if it matches, and step to next.
-        if (defStyleEnt < endDefStyleEnt && curIdent == defStyleEnt->map.name.ident) {
-            if (value.dataType == Res_value::TYPE_NULL) {
-                block = defStyleEnt->stringBlock;
-                typeSetFlags = defStyleTypeSetFlags;
-                value = defStyleEnt->map.value;
+        if (value.dataType == Res_value::TYPE_NULL) {
+            // Walk through the default style values looking for the requested attribute.
+            const ResTable::bag_entry* const defStyleAttrEntry = defStyleAttrFinder.find(curIdent);
+            if (defStyleAttrEntry != defStyleAttrEnd) {
+                // We found the attribute we were looking for.
+                block = defStyleAttrEntry->stringBlock;
+                typeSetFlags = styleTypeSetFlags;
+                value = defStyleAttrEntry->map.value;
                 DEBUG_STYLES(ALOGI("-> From def style: type=0x%x, data=0x%08x",
                         value.dataType, value.data));
             }
-            defStyleEnt++;
         }
 
         uint32_t resid = 0;
@@ -1376,7 +1383,9 @@
             // Take care of resolving the found resource to its final value.
             ssize_t newBlock = theme->resolveAttributeReference(&value, block,
                     &resid, &typeSetFlags, &config);
-            if (newBlock >= 0) block = newBlock;
+            if (newBlock >= 0) {
+                block = newBlock;
+            }
             DEBUG_STYLES(ALOGI("-> Resolved attr: type=0x%x, data=0x%08x",
                     value.dataType, value.data));
         } else {
@@ -1394,7 +1403,9 @@
                     return JNI_FALSE;
                 }
 #endif
-                if (newBlock >= 0) block = newBlock;
+                if (newBlock >= 0) {
+                    block = newBlock;
+                }
                 DEBUG_STYLES(ALOGI("-> Resolved theme: type=0x%x, data=0x%08x",
                         value.dataType, value.data));
             }
@@ -1414,8 +1425,8 @@
         // Write the final value back to Java.
         dest[STYLE_TYPE] = value.dataType;
         dest[STYLE_DATA] = value.data;
-        dest[STYLE_ASSET_COOKIE] =
-            block != kXmlBlock ? reinterpret_cast<jint>(res.getTableCookie(block)) : (jint)-1;
+        dest[STYLE_ASSET_COOKIE] = block != kXmlBlock ?
+            static_cast<jint>(res.getTableCookie(block)) : -1;
         dest[STYLE_RESOURCE_ID] = resid;
         dest[STYLE_CHANGING_CONFIGURATIONS] = typeSetFlags;
         dest[STYLE_DENSITY] = config.density;
diff --git a/core/jni/android_view_Surface.cpp b/core/jni/android_view_Surface.cpp
index a0b2ca8..a39ff8e 100644
--- a/core/jni/android_view_Surface.cpp
+++ b/core/jni/android_view_Surface.cpp
@@ -357,6 +357,22 @@
     parcel->writeStrongBinder( self != 0 ? self->getIGraphicBufferProducer()->asBinder() : NULL);
 }
 
+static jint nativeGetWidth(JNIEnv* env, jclass clazz, jlong nativeObject) {
+    Surface* surface = reinterpret_cast<Surface*>(nativeObject);
+    ANativeWindow* anw = static_cast<ANativeWindow*>(surface);
+    int value = 0;
+    anw->query(anw, NATIVE_WINDOW_WIDTH, &value);
+    return value;
+}
+
+static jint nativeGetHeight(JNIEnv* env, jclass clazz, jlong nativeObject) {
+    Surface* surface = reinterpret_cast<Surface*>(nativeObject);
+    ANativeWindow* anw = static_cast<ANativeWindow*>(surface);
+    int value = 0;
+    anw->query(anw, NATIVE_WINDOW_HEIGHT, &value);
+    return value;
+}
+
 namespace uirenderer {
 
 using namespace android::uirenderer::renderthread;
@@ -426,6 +442,8 @@
             (void*)nativeReadFromParcel },
     {"nativeWriteToParcel", "(JLandroid/os/Parcel;)V",
             (void*)nativeWriteToParcel },
+    {"nativeGetWidth", "(J)I", (void*)nativeGetWidth },
+    {"nativeGetHeight", "(J)I", (void*)nativeGetHeight },
 
     // HWUI context
     {"nHwuiCreate", "(JJ)J", (void*) hwui::create },
diff --git a/core/res/res/drawable-hdpi/ic_sim_card_multi_24px_clr.png b/core/res/res/drawable-hdpi/ic_sim_card_multi_24px_clr.png
new file mode 100644
index 0000000..c4a66bb
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_sim_card_multi_24px_clr.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_sim_card_multi_48px_clr.png b/core/res/res/drawable-hdpi/ic_sim_card_multi_48px_clr.png
new file mode 100644
index 0000000..db901d9
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_sim_card_multi_48px_clr.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_sim_card_multi_24px_clr.png b/core/res/res/drawable-mdpi/ic_sim_card_multi_24px_clr.png
new file mode 100644
index 0000000..5d21285
--- /dev/null
+++ b/core/res/res/drawable-mdpi/ic_sim_card_multi_24px_clr.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_sim_card_multi_48px_clr.png b/core/res/res/drawable-mdpi/ic_sim_card_multi_48px_clr.png
new file mode 100644
index 0000000..249379d
--- /dev/null
+++ b/core/res/res/drawable-mdpi/ic_sim_card_multi_48px_clr.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_sim_card_multi_24px_clr.png b/core/res/res/drawable-xhdpi/ic_sim_card_multi_24px_clr.png
new file mode 100644
index 0000000..9675e56
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/ic_sim_card_multi_24px_clr.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_sim_card_multi_48px_clr.png b/core/res/res/drawable-xhdpi/ic_sim_card_multi_48px_clr.png
new file mode 100644
index 0000000..a57a0b9
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/ic_sim_card_multi_48px_clr.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_sim_card_multi_24px_clr.png b/core/res/res/drawable-xxhdpi/ic_sim_card_multi_24px_clr.png
new file mode 100644
index 0000000..db26fbf
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_sim_card_multi_24px_clr.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_sim_card_multi_48px_clr.png b/core/res/res/drawable-xxhdpi/ic_sim_card_multi_48px_clr.png
new file mode 100644
index 0000000..dddb0a1
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_sim_card_multi_48px_clr.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/ic_sim_card_multi_24px_clr.png b/core/res/res/drawable-xxxhdpi/ic_sim_card_multi_24px_clr.png
new file mode 100644
index 0000000..fbda037
--- /dev/null
+++ b/core/res/res/drawable-xxxhdpi/ic_sim_card_multi_24px_clr.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/ic_sim_card_multi_48px_clr.png b/core/res/res/drawable-xxxhdpi/ic_sim_card_multi_48px_clr.png
new file mode 100644
index 0000000..3316f14
--- /dev/null
+++ b/core/res/res/drawable-xxxhdpi/ic_sim_card_multi_48px_clr.png
Binary files differ
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 981c576..c4b9c5f 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -5121,4 +5121,10 @@
 
     <!-- Indication that the current volume and other effects (vibration) are being suppressed by a third party, such as a notification listener. [CHAR LIMIT=30] -->
     <string name="muted_by">Muted by <xliff:g id="third_party">%1$s</xliff:g></string>
+
+    <!-- Error message shown when there is a system error which can be solved by user performing factory reset. [CHAR LIMIT=NONE] -->
+    <string name="system_error_wipe_data">There\'s an internal problem with your device, and it may be unstable until you factory data reset.</string>
+    <!-- Error message shown when there is a system error which can be solved by the manufacturer. [CHAR LIMIT=NONE] -->
+    <string name="system_error_manufacturer">There\'s an internal problem with your device. Contact your manufacturer for details.</string>
+
 </resources>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index c592f49..640fbbd 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -1206,6 +1206,9 @@
   <java-symbol type="drawable" name="sim_dark_orange" />
   <java-symbol type="drawable" name="sim_dark_purple" />
 
+  <java-symbol type="drawable" name="ic_sim_card_multi_24px_clr" />
+  <java-symbol type="drawable" name="ic_sim_card_multi_48px_clr" />
+
   <java-symbol type="drawable" name="ic_account_circle" />
   <java-symbol type="color" name="user_icon_1" />
   <java-symbol type="color" name="user_icon_2" />
@@ -2105,4 +2108,9 @@
 
   <!-- From SignalStrength -->
   <java-symbol type="integer" name="config_LTE_RSRP_threshold_type" />
+
+  <java-symbol type="string" name="android_system_label" />
+  <java-symbol type="string" name="system_error_wipe_data" />
+  <java-symbol type="string" name="system_error_manufacturer" />
+
 </resources>
diff --git a/docs/html/sdk/installing/migrate.jd b/docs/html/sdk/installing/migrate.jd
index db1b5dd..b83f8d3 100644
--- a/docs/html/sdk/installing/migrate.jd
+++ b/docs/html/sdk/installing/migrate.jd
@@ -15,23 +15,7 @@
 </div>
 
 <p>If you've previously developed for Android using Eclipse and would like to migrate
-to Android Studio, you should export your projects from Eclipse in order to generate
-Gradle build files. You can then import your project into Android Studio.</p>
-
-
-<h2 id="Export">Export from Eclipse</h2>
-<ol>
-<li><a href="{@docRoot}tools/help/adt.html#Updating">Update your Eclipse ADT Plugin</a>
-  (you must have version 22.0 or higher).</li>
-<li>In Eclipse, select <strong>File > Export</strong>.</li>
-<li>In the window that appears, open <strong>Android</strong> and select <strong>Generate Gradle
-build files</strong>.</li>
-<li>Select the project you want to export for Android Studio and click
-<strong>Finish</strong>.</li>
-</ol>
-
-<p>Your selected project remains in the same location but now contains a {@code build.gradle}
-file and is ready for Android Studio.</p>
+to Android Studio, you can import your project into Android Studio.</p>
 
 
 <h2 id="Export">Import into Android Studio</h2>
diff --git a/include/androidfw/AttributeFinder.h b/include/androidfw/AttributeFinder.h
new file mode 100644
index 0000000..a0ffeb3
--- /dev/null
+++ b/include/androidfw/AttributeFinder.h
@@ -0,0 +1,201 @@
+/*
+ * Copyright (C) 2014 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 H_ATTRIBUTE_FINDER
+#define H_ATTRIBUTE_FINDER
+
+#include <stdint.h>
+#include <utils/KeyedVector.h>
+
+namespace android {
+
+static inline uint32_t getPackage(uint32_t attr) {
+    return attr >> 24;
+}
+
+/**
+ * A helper class to search linearly for the requested
+ * attribute, maintaining it's position and optimizing for
+ * the case that subsequent searches will involve an attribute with
+ * a higher attribute ID.
+ *
+ * In the case that a subsequent attribute has a different package ID,
+ * its resource ID may not be larger than the preceding search, so
+ * back tracking is supported for this case. This
+ * back tracking requirement is mainly for shared library
+ * resources, whose package IDs get assigned at runtime
+ * and thus attributes from a shared library may
+ * be out of order.
+ *
+ * We make two assumptions about the order of attributes:
+ * 1) The input has the same sorting rules applied to it as
+ *    the attribute data contained by this class.
+ * 2) Attributes are grouped by package ID.
+ * 3) Among attributes with the same package ID, the attributes are
+ *    sorted by increasing resource ID.
+ *
+ * Ex: 02010000, 02010001, 010100f4, 010100f5, 0x7f010001, 07f010003
+ *
+ * The total order of attributes (including package ID) can not be linear
+ * as shared libraries get assigned dynamic package IDs at runtime, which
+ * may break the sort order established at build time.
+ */
+template <typename Derived, typename Iterator>
+class BackTrackingAttributeFinder {
+public:
+    BackTrackingAttributeFinder(const Iterator& begin, const Iterator& end);
+
+    Iterator find(uint32_t attr);
+
+private:
+    void jumpToClosestAttribute(uint32_t packageId);
+    void markCurrentPackageId(uint32_t packageId);
+
+    Iterator mBegin;
+    Iterator mEnd;
+    Iterator mCurrent;
+    Iterator mLargest;
+    uint32_t mLastPackageId;
+    uint32_t mCurrentAttr;
+
+    // Package Offsets (best-case, fast look-up).
+    Iterator mFrameworkStart;
+    Iterator mAppStart;
+
+    // Worst case, we have shared-library resources.
+    KeyedVector<uint32_t, Iterator> mPackageOffsets;
+};
+
+template <typename Derived, typename Iterator> inline
+BackTrackingAttributeFinder<Derived, Iterator>::BackTrackingAttributeFinder(const Iterator& begin, const Iterator& end)
+    : mBegin(begin)
+    , mEnd(end)
+    , mCurrent(begin)
+    , mLargest(begin)
+    , mLastPackageId(0)
+    , mCurrentAttr(0)
+    , mFrameworkStart(end)
+    , mAppStart(end) {
+}
+
+template <typename Derived, typename Iterator>
+void BackTrackingAttributeFinder<Derived, Iterator>::jumpToClosestAttribute(const uint32_t packageId) {
+    switch (packageId) {
+        case 0x01:
+            mCurrent = mFrameworkStart;
+            break;
+        case 0x7f:
+            mCurrent = mAppStart;
+            break;
+        default: {
+            ssize_t idx = mPackageOffsets.indexOfKey(packageId);
+            if (idx >= 0) {
+                // We have seen this package ID before, so jump to the first
+                // attribute with this package ID.
+                mCurrent = mPackageOffsets[idx];
+            } else {
+                mCurrent = mEnd;
+            }
+            break;
+        }
+    }
+
+    // We have never seen this package ID yet, so jump to the
+    // latest/largest index we have processed so far.
+    if (mCurrent == mEnd) {
+        mCurrent = mLargest;
+    }
+
+    if (mCurrent != mEnd) {
+        mCurrentAttr = static_cast<const Derived*>(this)->getAttribute(mCurrent);
+    }
+}
+
+template <typename Derived, typename Iterator>
+void BackTrackingAttributeFinder<Derived, Iterator>::markCurrentPackageId(const uint32_t packageId) {
+    switch (packageId) {
+        case 0x01:
+            mFrameworkStart = mCurrent;
+            break;
+        case 0x7f:
+            mAppStart = mCurrent;
+            break;
+        default:
+            mPackageOffsets.add(packageId, mCurrent);
+            break;
+    }
+}
+
+template <typename Derived, typename Iterator>
+Iterator BackTrackingAttributeFinder<Derived, Iterator>::find(uint32_t attr) {
+    if (!(mBegin < mEnd)) {
+        return mEnd;
+    }
+
+    if (mCurrentAttr == 0) {
+        // One-time initialization.
+        mCurrentAttr = static_cast<const Derived*>(this)->getAttribute(mBegin);
+        mLastPackageId = getPackage(mCurrentAttr);
+        markCurrentPackageId(mLastPackageId);
+    }
+
+    // Looking for the needle (attribute we're looking for)
+    // in the haystack (the attributes we're searching through)
+    const uint32_t needlePackageId = getPackage(attr);
+    if (mLastPackageId != needlePackageId) {
+        jumpToClosestAttribute(needlePackageId);
+        mLastPackageId = needlePackageId;
+    }
+
+    // Walk through the xml attributes looking for the requested attribute.
+    while (mCurrent != mEnd) {
+        const uint32_t haystackPackageId = getPackage(mCurrentAttr);
+        if (needlePackageId == haystackPackageId && attr < mCurrentAttr) {
+            // The attribute we are looking was not found.
+            break;
+        }
+        const uint32_t prevAttr = mCurrentAttr;
+
+        // Move to the next attribute in the XML.
+        ++mCurrent;
+        if (mCurrent != mEnd) {
+            mCurrentAttr = static_cast<const Derived*>(this)->getAttribute(mCurrent);
+            const uint32_t newHaystackPackageId = getPackage(mCurrentAttr);
+            if (haystackPackageId != newHaystackPackageId) {
+                // We've moved to the next group of attributes
+                // with a new package ID, so we should record
+                // the offset of this new package ID.
+                markCurrentPackageId(newHaystackPackageId);
+            }
+        }
+
+        if (mCurrent > mLargest) {
+            // We've moved past the latest attribute we've
+            // seen.
+            mLargest = mCurrent;
+        }
+
+        if (attr == prevAttr) {
+            // We found the attribute we were looking for.
+            return mCurrent - 1;
+        }
+    }
+    return mEnd;
+}
+
+} // namespace android
+
+#endif // H_ATTRIBUTE_FINDER
diff --git a/libs/androidfw/ResourceTypes.cpp b/libs/androidfw/ResourceTypes.cpp
index 3cf1021..6dfb4dc 100644
--- a/libs/androidfw/ResourceTypes.cpp
+++ b/libs/androidfw/ResourceTypes.cpp
@@ -1185,7 +1185,11 @@
 {
     int32_t id = getAttributeNameID(idx);
     if (id >= 0 && (size_t)id < mTree.mNumResIds) {
-        return dtohl(mTree.mResIds[id]);
+        uint32_t resId = dtohl(mTree.mResIds[id]);
+        if (mTree.mDynamicRefTable != NULL) {
+            mTree.mDynamicRefTable->lookupResourceId(&resId);
+        }
+        return resId;
     }
     return 0;
 }
@@ -5977,11 +5981,11 @@
     // Do a proper lookup.
     uint8_t translatedId = mLookupTable[packageId];
     if (translatedId == 0) {
-        ALOGE("DynamicRefTable(0x%02x): No mapping for build-time package ID 0x%02x.",
+        ALOGV("DynamicRefTable(0x%02x): No mapping for build-time package ID 0x%02x.",
                 (uint8_t)mAssignedPackageId, (uint8_t)packageId);
         for (size_t i = 0; i < 256; i++) {
             if (mLookupTable[i] != 0) {
-                ALOGE("e[0x%02x] -> 0x%02x", (uint8_t)i, mLookupTable[i]);
+                ALOGV("e[0x%02x] -> 0x%02x", (uint8_t)i, mLookupTable[i]);
             }
         }
         return UNKNOWN_ERROR;
diff --git a/libs/androidfw/tests/Android.mk b/libs/androidfw/tests/Android.mk
index 2d7906f..c1014be 100644
--- a/libs/androidfw/tests/Android.mk
+++ b/libs/androidfw/tests/Android.mk
@@ -20,6 +20,7 @@
 # ==========================================================
 LOCAL_PATH:= $(call my-dir)
 testFiles := \
+    AttributeFinder_test.cpp \
     ByteBucketArray_test.cpp \
     Config_test.cpp \
     ConfigLocale_test.cpp \
diff --git a/libs/androidfw/tests/AttributeFinder_test.cpp b/libs/androidfw/tests/AttributeFinder_test.cpp
new file mode 100644
index 0000000..664709c
--- /dev/null
+++ b/libs/androidfw/tests/AttributeFinder_test.cpp
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <androidfw/AttributeFinder.h>
+
+#include <gtest/gtest.h>
+
+using android::BackTrackingAttributeFinder;
+
+class MockAttributeFinder : public BackTrackingAttributeFinder<MockAttributeFinder, int> {
+public:
+    MockAttributeFinder(const uint32_t* attrs, int len)
+        : BackTrackingAttributeFinder(0, len) {
+        mAttrs = new uint32_t[len];
+        memcpy(mAttrs, attrs, sizeof(*attrs) * len);
+    }
+
+    ~MockAttributeFinder() {
+        delete mAttrs;
+    }
+
+    inline uint32_t getAttribute(const int index) const {
+        return mAttrs[index];
+    }
+
+private:
+    uint32_t* mAttrs;
+};
+
+static const uint32_t sortedAttributes[] = {
+        0x01010000, 0x01010001, 0x01010002, 0x01010004,
+        0x02010001, 0x02010010, 0x7f010001
+};
+
+static const uint32_t packageUnsortedAttributes[] = {
+        0x02010001, 0x02010010, 0x01010000, 0x01010001,
+        0x01010002, 0x01010004, 0x7f010001
+};
+
+TEST(AttributeFinderTest, IteratesSequentially) {
+    const int end = sizeof(sortedAttributes) / sizeof(*sortedAttributes);
+    MockAttributeFinder finder(sortedAttributes, end);
+
+    EXPECT_EQ(0, finder.find(0x01010000));
+    EXPECT_EQ(1, finder.find(0x01010001));
+    EXPECT_EQ(2, finder.find(0x01010002));
+    EXPECT_EQ(3, finder.find(0x01010004));
+    EXPECT_EQ(4, finder.find(0x02010001));
+    EXPECT_EQ(5, finder.find(0x02010010));
+    EXPECT_EQ(6, finder.find(0x7f010001));
+    EXPECT_EQ(end, finder.find(0x7f010002));
+}
+
+TEST(AttributeFinderTest, PackagesAreOutOfOrder) {
+    const int end = sizeof(sortedAttributes) / sizeof(*sortedAttributes);
+    MockAttributeFinder finder(sortedAttributes, end);
+
+    EXPECT_EQ(6, finder.find(0x7f010001));
+    EXPECT_EQ(end, finder.find(0x7f010002));
+    EXPECT_EQ(4, finder.find(0x02010001));
+    EXPECT_EQ(5, finder.find(0x02010010));
+    EXPECT_EQ(0, finder.find(0x01010000));
+    EXPECT_EQ(1, finder.find(0x01010001));
+    EXPECT_EQ(2, finder.find(0x01010002));
+    EXPECT_EQ(3, finder.find(0x01010004));
+}
+
+TEST(AttributeFinderTest, SomeAttributesAreNotFound) {
+    const int end = sizeof(sortedAttributes) / sizeof(*sortedAttributes);
+    MockAttributeFinder finder(sortedAttributes, end);
+
+    EXPECT_EQ(0, finder.find(0x01010000));
+    EXPECT_EQ(1, finder.find(0x01010001));
+    EXPECT_EQ(2, finder.find(0x01010002));
+    EXPECT_EQ(end, finder.find(0x01010003));
+    EXPECT_EQ(3, finder.find(0x01010004));
+    EXPECT_EQ(end, finder.find(0x01010005));
+    EXPECT_EQ(end, finder.find(0x01010006));
+    EXPECT_EQ(4, finder.find(0x02010001));
+    EXPECT_EQ(end, finder.find(0x02010002));
+}
+
+TEST(AttributeFinderTest, FindAttributesInPackageUnsortedAttributeList) {
+    const int end = sizeof(packageUnsortedAttributes) / sizeof(*packageUnsortedAttributes);
+    MockAttributeFinder finder(packageUnsortedAttributes, end);
+
+    EXPECT_EQ(2, finder.find(0x01010000));
+    EXPECT_EQ(3, finder.find(0x01010001));
+    EXPECT_EQ(4, finder.find(0x01010002));
+    EXPECT_EQ(end, finder.find(0x01010003));
+    EXPECT_EQ(5, finder.find(0x01010004));
+    EXPECT_EQ(end, finder.find(0x01010005));
+    EXPECT_EQ(end, finder.find(0x01010006));
+    EXPECT_EQ(0, finder.find(0x02010001));
+    EXPECT_EQ(end, finder.find(0x02010002));
+    EXPECT_EQ(1, finder.find(0x02010010));
+    EXPECT_EQ(6, finder.find(0x7f010001));
+}
diff --git a/packages/SystemUI/res/layout/qs_detail_item.xml b/packages/SystemUI/res/layout/qs_detail_item.xml
index 55139fb..ea2e1e1 100644
--- a/packages/SystemUI/res/layout/qs_detail_item.xml
+++ b/packages/SystemUI/res/layout/qs_detail_item.xml
@@ -31,7 +31,7 @@
     <LinearLayout
         android:layout_width="0dp"
         android:layout_height="wrap_content"
-        android:layout_marginStart="20dp"
+        android:layout_marginStart="12dp"
         android:layout_weight="1"
         android:orientation="vertical" >
 
diff --git a/packages/SystemUI/res/layout/remember_permission_checkbox.xml b/packages/SystemUI/res/layout/remember_permission_checkbox.xml
index a21acb3..4985ff5 100644
--- a/packages/SystemUI/res/layout/remember_permission_checkbox.xml
+++ b/packages/SystemUI/res/layout/remember_permission_checkbox.xml
@@ -20,9 +20,9 @@
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
-    android:paddingStart="8dp"
-    android:paddingEnd="8dp"
-    android:paddingTop="8dp">
+    android:paddingStart="16dp"
+    android:paddingEnd="16dp"
+    android:paddingTop="16dp">
 
     <CheckBox
         android:id="@+id/remember"
diff --git a/packages/SystemUI/res/layout/status_bar_expanded_header.xml b/packages/SystemUI/res/layout/status_bar_expanded_header.xml
index 7ea9145..9912e89c 100644
--- a/packages/SystemUI/res/layout/status_bar_expanded_header.xml
+++ b/packages/SystemUI/res/layout/status_bar_expanded_header.xml
@@ -38,8 +38,8 @@
         android:layout_alignParentEnd="true"
         android:background="@drawable/ripple_drawable" >
         <ImageView android:id="@+id/multi_user_avatar"
-            android:layout_width="24dp"
-            android:layout_height="24dp"
+            android:layout_width="@dimen/multi_user_avatar_expanded_size"
+            android:layout_height="@dimen/multi_user_avatar_expanded_size"
             android:layout_gravity="center"
             android:scaleType="centerInside"/>
     </com.android.systemui.statusbar.phone.MultiUserSwitch>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 841bef5..3d9f723 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -405,6 +405,9 @@
     <!-- The width of user avatar when on Keyguard -->
     <dimen name="multi_user_avatar_keyguard_size">22dp</dimen>
 
+    <!-- The width of user avatar when expanded -->
+    <dimen name="multi_user_avatar_expanded_size">24dp</dimen>
+
     <!-- The font size of the time when collapsed in QS -->
     <dimen name="qs_time_collapsed_size">14sp</dimen>
 
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java
index ee699d2..98d4112 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java
@@ -22,6 +22,7 @@
 import android.os.Bundle;
 import android.os.Debug;
 import android.os.IBinder;
+import android.os.Process;
 import android.util.Log;
 import android.view.MotionEvent;
 
@@ -52,6 +53,10 @@
     }
 
     void checkPermission() {
+        // Avoid deadlock by avoiding calling back into the system process.
+        if (Binder.getCallingUid() == Process.SYSTEM_UID) return;
+
+        // Otherwise,explicitly check for caller permission ...
         if (getBaseContext().checkCallingOrSelfPermission(PERMISSION) != PERMISSION_GRANTED) {
             Log.w(TAG, "Caller needs permission '" + PERMISSION + "' to call " + Debug.getCaller());
             throw new SecurityException("Access denied to process: " + Binder.getCallingPid()
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitch.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitch.java
index 4715d0a..82f5a9e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitch.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitch.java
@@ -67,15 +67,18 @@
 
     @Override
     public void onClick(View v) {
-        if (opensUserSwitcherWhenClicked()) {
+        if (UserSwitcherController.isUserSwitcherAvailable(mUserManager)) {
             if (mKeyguardMode) {
                 if (mKeyguardUserSwitcher != null) {
                     mKeyguardUserSwitcher.show(true /* animate */);
                 }
             } else {
                 if (mQsPanel != null) {
-                    mQsPanel.showDetailAdapter(true,
-                            mQsPanel.getHost().getUserSwitcherController().userDetailAdapter);
+                    UserSwitcherController userSwitcherController =
+                            mQsPanel.getHost().getUserSwitcherController();
+                    if (userSwitcherController != null) {
+                        mQsPanel.showDetailAdapter(true, userSwitcherController.userDetailAdapter);
+                    }
                 }
             }
         } else {
@@ -92,12 +95,14 @@
 
         if (isClickable()) {
             String text;
-            if (opensUserSwitcherWhenClicked()) {
+            if (UserSwitcherController.isUserSwitcherAvailable(mUserManager)) {
                 String currentUser = null;
                 if (mQsPanel != null) {
                     UserSwitcherController controller = mQsPanel.getHost()
                             .getUserSwitcherController();
-                    currentUser = controller.getCurrentUserName(mContext);
+                    if (controller != null) {
+                        currentUser = controller.getCurrentUserName(mContext);
+                    }
                 }
                 if (TextUtils.isEmpty(currentUser)) {
                     text = mContext.getString(R.string.accessibility_multi_user_switch_switcher);
@@ -121,8 +126,4 @@
         return false;
     }
 
-    private boolean opensUserSwitcherWhenClicked() {
-        UserManager um = UserManager.get(getContext());
-        return UserManager.supportsMultipleUsers() && um.isUserSwitcherEnabled();
-    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
index 47ce603..a044743 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
@@ -98,6 +98,7 @@
     private boolean mCollapseAfterPeek;
     private boolean mExpanding;
     private boolean mGestureWaitForTouchSlop;
+    private boolean mDozingOnDown;
     private Runnable mPeekRunnable = new Runnable() {
         @Override
         public void run() {
@@ -244,6 +245,7 @@
                 mUpdateFlingOnLayout = false;
                 mPeekTouching = mPanelClosedOnDown;
                 mTouchAboveFalsingThreshold = false;
+                mDozingOnDown = isDozing();
                 if (mVelocityTracker == null) {
                     initVelocityTracker();
                 }
@@ -418,6 +420,7 @@
                 mHasLayoutedSinceDown = false;
                 mUpdateFlingOnLayout = false;
                 mTouchAboveFalsingThreshold = false;
+                mDozingOnDown = isDozing();
                 initVelocityTracker();
                 trackMovement(event);
                 break;
@@ -937,7 +940,7 @@
     private boolean onMiddleClicked() {
         switch (mStatusBar.getBarState()) {
             case StatusBarState.KEYGUARD:
-                if (!isDozing()) {
+                if (!mDozingOnDown) {
                     startUnlockHintAnimation();
                 }
                 return true;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
index d94f122..f5c994a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -74,6 +74,7 @@
 import android.os.RemoteException;
 import android.os.SystemClock;
 import android.os.UserHandle;
+import android.os.UserManager;
 import android.provider.Settings;
 import android.service.notification.NotificationListenerService;
 import android.service.notification.NotificationListenerService.RankingMap;
@@ -853,11 +854,16 @@
         mKeyguardBottomArea.setAccessibilityController(mAccessibilityController);
         mNextAlarmController = new NextAlarmController(mContext);
         mKeyguardMonitor = new KeyguardMonitor();
-        mUserSwitcherController = new UserSwitcherController(mContext, mKeyguardMonitor);
-
+        if (UserSwitcherController.isUserSwitcherAvailable(UserManager.get(mContext))) {
+            mUserSwitcherController = new UserSwitcherController(mContext, mKeyguardMonitor);
+        }
         mKeyguardUserSwitcher = new KeyguardUserSwitcher(mContext,
                 (ViewStub) mStatusBarWindow.findViewById(R.id.keyguard_user_switcher),
                 mKeyguardStatusBar, mNotificationPanel, mUserSwitcherController);
+        if (mUserSwitcherController != null) {
+            mUserSwitcherController.setKeyguardUserSwitcherAvailable(
+                    mKeyguardUserSwitcher.isEnabled());
+        }
 
 
         // Set up the quick settings tile panel
@@ -1510,7 +1516,8 @@
         // If the user switcher is simple then disable QS during setup because
         // the user intends to use the lock screen user switcher, QS in not needed.
         mNotificationPanel.setQsExpansionEnabled(isDeviceProvisioned()
-                && (!mUserSwitcherController.isSimpleUserSwitcher() || mUserSetup));
+                && (mUserSetup || mUserSwitcherController == null
+                        || !mUserSwitcherController.isSimpleUserSwitcher()));
         mShadeUpdates.check();
     }
 
@@ -2123,6 +2130,9 @@
 
     public void setQsExpanded(boolean expanded) {
         mStatusBarWindowManager.setQsExpanded(expanded);
+        if (mUserSwitcherController != null) {
+            mUserSwitcherController.setQsExpanded(expanded);
+        }
     }
 
     public boolean isGoingToNotificationShade() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcher.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcher.java
index c71bccd..0392e0d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcher.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcher.java
@@ -58,7 +58,9 @@
     public KeyguardUserSwitcher(Context context, ViewStub userSwitcher,
             KeyguardStatusBarView statusBarView, NotificationPanelView panelView,
             UserSwitcherController userSwitcherController) {
-        if (context.getResources().getBoolean(R.bool.config_keyguardUserSwitcher) || ALWAYS_ON) {
+        boolean keyguardUserSwitcherEnabled =
+                context.getResources().getBoolean(R.bool.config_keyguardUserSwitcher) || ALWAYS_ON;
+        if (userSwitcherController != null && keyguardUserSwitcherEnabled) {
             mUserSwitcherContainer = (Container) userSwitcher.inflate();
             mUserSwitcher = (ViewGroup)
                     mUserSwitcherContainer.findViewById(R.id.keyguard_user_switcher_inner);
@@ -225,6 +227,10 @@
         }
     };
 
+    public boolean isEnabled() {
+        return mUserSwitcherContainer != null;
+    }
+
     public static class Adapter extends UserSwitcherController.BaseUserAdapter implements
             View.OnClickListener {
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserInfoController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserInfoController.java
index d50e39f..a8d4f13 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserInfoController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserInfoController.java
@@ -23,6 +23,7 @@
 import android.content.IntentFilter;
 import android.content.pm.PackageManager;
 import android.content.pm.UserInfo;
+import android.content.res.Resources;
 import android.database.Cursor;
 import android.graphics.Bitmap;
 import android.graphics.drawable.BitmapDrawable;
@@ -131,8 +132,11 @@
         final int userId = userInfo.id;
         final boolean isGuest = userInfo.isGuest();
         final String userName = userInfo.name;
-        final int avatarSize
-                = mContext.getResources().getDimensionPixelSize(R.dimen.max_avatar_size);
+
+        final Resources res = mContext.getResources();
+        final int avatarSize = Math.max(
+                res.getDimensionPixelSize(R.dimen.multi_user_avatar_expanded_size),
+                res.getDimensionPixelSize(R.dimen.multi_user_avatar_keyguard_size));
 
         final Context context = currentUserContext;
         mUserInfoTask = new AsyncTask<Void, Void, Pair<String, Drawable>>() {
@@ -160,8 +164,9 @@
                     // Try and read the display name from the local profile
                     final Cursor cursor = context.getContentResolver().query(
                             ContactsContract.Profile.CONTENT_URI, new String[] {
-                            ContactsContract.CommonDataKinds.Phone._ID, ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME},
-                            null, null, null);
+                                    ContactsContract.CommonDataKinds.Phone._ID,
+                                    ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME
+                            }, null, null, null);
                     if (cursor != null) {
                         try {
                             if (cursor.moveToFirst()) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
index 5c7909a..5f6c399 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
@@ -78,6 +78,9 @@
     private boolean mSimpleUserSwitcher;
     private boolean mAddUsersWhenLocked;
 
+    private boolean mKeyguardUserSwitcherAvailable;
+    private boolean mQsExpanded;
+
     public UserSwitcherController(Context context, KeyguardMonitor keyguardMonitor) {
         mContext = context;
         mGuestResumeSessionReceiver.register(context);
@@ -116,16 +119,18 @@
      */
     @SuppressWarnings("unchecked")
     private void refreshUsers(int forcePictureLoadForId) {
-
-        SparseArray<Bitmap> bitmaps = new SparseArray<>(mUsers.size());
-        final int N = mUsers.size();
-        for (int i = 0; i < N; i++) {
-            UserRecord r = mUsers.get(i);
-            if (r == null || r.info == null
-                    || r.info.id == forcePictureLoadForId || r.picture == null) {
-                continue;
+        SparseArray<Bitmap> bitmaps = null;
+        if (allowCachingOfBitmaps()) {
+            bitmaps = new SparseArray<>(mUsers.size());
+            final int N = mUsers.size();
+            for (int i = 0; i < N; i++) {
+                UserRecord r = mUsers.get(i);
+                if (r == null || r.info == null
+                        || r.info.id == forcePictureLoadForId || r.picture == null) {
+                    continue;
+                }
+                bitmaps.put(r.info.id, r.picture);
             }
-            bitmaps.put(r.info.id, r.picture);
         }
 
         final boolean addUsersWhenLocked = mAddUsersWhenLocked;
@@ -151,13 +156,15 @@
                                 true /* isGuest */, isCurrent, false /* isAddUser */,
                                 false /* isRestricted */);
                     } else if (info.supportsSwitchTo()) {
-                        Bitmap picture = bitmaps.get(info.id);
-                        if (picture == null) {
-                            picture = mUserManager.getUserIcon(info.id);
-                        }
-                        if (picture != null) {
-                            picture = BitmapHelper.createCircularClip(
-                                    picture, avatarSize, avatarSize);
+                        Bitmap picture = bitmaps != null ? bitmaps.get(info.id) : null;
+                        if (picture == null && allowCachingOfBitmaps()) {
+                            Bitmap loadedPicture = mUserManager.getUserIcon(info.id);
+
+                            if (loadedPicture != null) {
+                                picture = BitmapHelper.createCircularClip(
+                                        loadedPicture, avatarSize, avatarSize);
+                                loadedPicture.recycle();
+                            }
                         }
                         int index = isCurrent ? 0 : records.size();
                         records.add(index, new UserRecord(info, picture, false /* isGuest */,
@@ -552,6 +559,32 @@
         }
     }
 
+    /**
+     * Notify if the keyguard user switcher is available.
+     */
+    public void setKeyguardUserSwitcherAvailable(boolean available) {
+        boolean oldShouldCacheBitmaps = allowCachingOfBitmaps();
+        mKeyguardUserSwitcherAvailable = available;
+        if (allowCachingOfBitmaps() != oldShouldCacheBitmaps) {
+            refreshUsers(UserHandle.USER_NULL);
+        }
+    }
+
+    /**
+     * Notify if the quick settings are expanded.
+     */
+    public void setQsExpanded(boolean qsExpanded) {
+        boolean oldShouldCacheBitmaps = allowCachingOfBitmaps();
+        mQsExpanded = qsExpanded;
+        if (allowCachingOfBitmaps() != oldShouldCacheBitmaps) {
+            refreshUsers(UserHandle.USER_NULL);
+        }
+    }
+
+    private boolean allowCachingOfBitmaps() {
+        return mQsExpanded || mKeyguardUserSwitcherAvailable;
+    }
+
     private final class AddUserDialog extends SystemUIDialog implements
             DialogInterface.OnClickListener {
 
@@ -589,4 +622,9 @@
             }
         }
     }
+
+    public static boolean isUserSwitcherAvailable(UserManager um) {
+        return UserManager.supportsMultipleUsers() && um.isUserSwitcherEnabled();
+    }
+
 }
diff --git a/services/core/java/com/android/server/SystemConfig.java b/services/core/java/com/android/server/SystemConfig.java
index f4fb519..92fbc1e 100644
--- a/services/core/java/com/android/server/SystemConfig.java
+++ b/services/core/java/com/android/server/SystemConfig.java
@@ -16,6 +16,7 @@
 
 package com.android.server;
 
+import android.app.ActivityManager;
 import android.content.pm.FeatureInfo;
 import android.os.*;
 import android.os.Process;
@@ -177,6 +178,8 @@
             return;
         }
 
+        final boolean lowRam = ActivityManager.isLowRamDeviceStatic();
+
         try {
             XmlPullParser parser = Xml.newPullParser();
             parser.setInput(permReader);
@@ -276,10 +279,17 @@
 
                 } else if ("feature".equals(name)) {
                     String fname = parser.getAttributeValue(null, "name");
+                    boolean allowed;
+                    if (!lowRam) {
+                        allowed = true;
+                    } else {
+                        String notLowRam = parser.getAttributeValue(null, "notLowRam");
+                        allowed = !"true".equals(notLowRam);
+                    }
                     if (fname == null) {
                         Slog.w(TAG, "<feature> without name at "
                                 + parser.getPositionDescription());
-                    } else {
+                    } else if (allowed) {
                         //Log.i(TAG, "Got feature " + fname);
                         FeatureInfo fi = new FeatureInfo();
                         fi.name = fname;
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index d311ad9..772192a 100755
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -61,7 +61,6 @@
 import com.android.internal.app.IVoiceInteractor;
 import com.android.internal.app.ProcessMap;
 import com.android.internal.app.ProcessStats;
-import com.android.internal.content.PackageMonitor;
 import com.android.internal.os.BackgroundThread;
 import com.android.internal.os.BatteryStatsImpl;
 import com.android.internal.os.ProcessCpuTracker;
@@ -1183,7 +1182,7 @@
     static final int SERVICE_TIMEOUT_MSG = 12;
     static final int UPDATE_TIME_ZONE = 13;
     static final int SHOW_UID_ERROR_MSG = 14;
-    static final int IM_FEELING_LUCKY_MSG = 15;
+    static final int SHOW_FINGERPRINT_ERROR_MSG = 15;
     static final int PROC_START_TIMEOUT_MSG = 20;
     static final int DO_PENDING_ACTIVITY_LAUNCHES_MSG = 21;
     static final int KILL_APPLICATION_MSG = 22;
@@ -1212,13 +1211,13 @@
     static final int FINISH_BOOTING_MSG = 45;
     static final int START_USER_SWITCH_MSG = 46;
     static final int SEND_LOCALE_TO_MOUNT_DAEMON_MSG = 47;
+    static final int DISMISS_DIALOG_MSG = 48;
 
     static final int FIRST_ACTIVITY_STACK_MSG = 100;
     static final int FIRST_BROADCAST_QUEUE_MSG = 200;
     static final int FIRST_COMPAT_MODE_MSG = 300;
     static final int FIRST_SUPERVISOR_STACK_MSG = 100;
 
-    AlertDialog mUidAlert;
     CompatModeDialog mCompatModeDialog;
     long mLastMemUsageReportTime = 0;
 
@@ -1447,27 +1446,27 @@
                 }
             } break;
             case SHOW_UID_ERROR_MSG: {
-                String title = "System UIDs Inconsistent";
-                String text = "UIDs on the system are inconsistent, you need to wipe your"
-                        + " data partition or your device will be unstable.";
-                Log.e(TAG, title + ": " + text);
                 if (mShowDialogs) {
-                    // XXX This is a temporary dialog, no need to localize.
                     AlertDialog d = new BaseErrorDialog(mContext);
                     d.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ERROR);
                     d.setCancelable(false);
-                    d.setTitle(title);
-                    d.setMessage(text);
-                    d.setButton(DialogInterface.BUTTON_POSITIVE, "I'm Feeling Lucky",
-                            mHandler.obtainMessage(IM_FEELING_LUCKY_MSG));
-                    mUidAlert = d;
+                    d.setTitle(mContext.getText(R.string.android_system_label));
+                    d.setMessage(mContext.getText(R.string.system_error_wipe_data));
+                    d.setButton(DialogInterface.BUTTON_POSITIVE, mContext.getText(R.string.ok),
+                            mHandler.obtainMessage(DISMISS_DIALOG_MSG, d));
                     d.show();
                 }
             } break;
-            case IM_FEELING_LUCKY_MSG: {
-                if (mUidAlert != null) {
-                    mUidAlert.dismiss();
-                    mUidAlert = null;
+            case SHOW_FINGERPRINT_ERROR_MSG: {
+                if (mShowDialogs) {
+                    AlertDialog d = new BaseErrorDialog(mContext);
+                    d.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ERROR);
+                    d.setCancelable(false);
+                    d.setTitle(mContext.getText(R.string.android_system_label));
+                    d.setMessage(mContext.getText(R.string.system_error_manufacturer));
+                    d.setButton(DialogInterface.BUTTON_POSITIVE, mContext.getText(R.string.ok),
+                            mHandler.obtainMessage(DISMISS_DIALOG_MSG, d));
+                    d.show();
                 }
             } break;
             case PROC_START_TIMEOUT_MSG: {
@@ -1727,6 +1726,11 @@
                 }
                 break;
             }
+            case DISMISS_DIALOG_MSG: {
+                final Dialog d = (Dialog) msg.obj;
+                d.dismiss();
+                break;
+            }
             }
         }
     };
@@ -1776,7 +1780,8 @@
                     }
                 }
 
-                int i=0, num=0;
+                int i = 0;
+                int num = 0;
                 long[] tmp = new long[1];
                 do {
                     ProcessRecord proc;
@@ -1826,99 +1831,6 @@
         }
     };
 
-    /**
-     * Monitor for package changes and update our internal state.
-     */
-    private final PackageMonitor mPackageMonitor = new PackageMonitor() {
-        @Override
-        public void onPackageRemoved(String packageName, int uid) {
-            // Remove all tasks with activities in the specified package from the list of recent tasks
-            final int eventUserId = getChangingUserId();
-            synchronized (ActivityManagerService.this) {
-                for (int i = mRecentTasks.size() - 1; i >= 0; i--) {
-                    TaskRecord tr = mRecentTasks.get(i);
-                    if (tr.userId != eventUserId) continue;
-
-                    ComponentName cn = tr.intent.getComponent();
-                    if (cn != null && cn.getPackageName().equals(packageName)) {
-                        // If the package name matches, remove the task
-                        removeTaskByIdLocked(tr.taskId, true);
-                    }
-                }
-            }
-        }
-
-        @Override
-        public boolean onPackageChanged(String packageName, int uid, String[] components) {
-            onPackageModified(packageName);
-            return true;
-        }
-
-        @Override
-        public void onPackageModified(String packageName) {
-            final int eventUserId = getChangingUserId();
-            final IPackageManager pm = AppGlobals.getPackageManager();
-            final ArrayList<Pair<Intent, Integer>> recentTaskIntents =
-                    new ArrayList<Pair<Intent, Integer>>();
-            final HashSet<ComponentName> componentsKnownToExist = new HashSet<ComponentName>();
-            final ArrayList<Integer> tasksToRemove = new ArrayList<Integer>();
-            // Copy the list of recent tasks so that we don't hold onto the lock on
-            // ActivityManagerService for long periods while checking if components exist.
-            synchronized (ActivityManagerService.this) {
-                for (int i = mRecentTasks.size() - 1; i >= 0; i--) {
-                    TaskRecord tr = mRecentTasks.get(i);
-                    if (tr.userId != eventUserId) continue;
-
-                    recentTaskIntents.add(new Pair<Intent, Integer>(tr.intent, tr.taskId));
-                }
-            }
-            // Check the recent tasks and filter out all tasks with components that no longer exist.
-            for (int i = recentTaskIntents.size() - 1; i >= 0; i--) {
-                Pair<Intent, Integer> p = recentTaskIntents.get(i);
-                ComponentName cn = p.first.getComponent();
-                if (cn != null && cn.getPackageName().equals(packageName)) {
-                    if (componentsKnownToExist.contains(cn)) {
-                        // If we know that the component still exists in the package, then skip
-                        continue;
-                    }
-                    try {
-                        ActivityInfo info = pm.getActivityInfo(cn, 0, eventUserId);
-                        if (info != null) {
-                            componentsKnownToExist.add(cn);
-                        } else {
-                            tasksToRemove.add(p.second);
-                        }
-                    } catch (RemoteException e) {
-                        Log.e(TAG, "Failed to query activity info for component: " + cn, e);
-                    }
-                }
-            }
-            // Prune all the tasks with removed components from the list of recent tasks
-            synchronized (ActivityManagerService.this) {
-                for (int i = tasksToRemove.size() - 1; i >= 0; i--) {
-                    removeTaskByIdLocked(tasksToRemove.get(i), false);
-                }
-            }
-        }
-
-        @Override
-        public boolean onHandleForceStop(Intent intent, String[] packages, int uid, boolean doit) {
-            // Force stop the specified packages
-            int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0);
-            if (packages != null) {
-                for (String pkg : packages) {
-                    synchronized (ActivityManagerService.this) {
-                        if (forceStopPackageLocked(pkg, -1, false, false, false, false, false,
-                                userId, "finished booting")) {
-                            return true;
-                        }
-                    }
-                }
-            }
-            return false;
-        }
-    };
-
     public void setSystemProcess() {
         try {
             ServiceManager.addService(Context.ACTIVITY_SERVICE, this, true);
@@ -6166,8 +6078,26 @@
             }
         }
 
-        // Register receivers to handle package update events
-        mPackageMonitor.register(mContext, Looper.getMainLooper(), UserHandle.ALL, false);
+        IntentFilter pkgFilter = new IntentFilter();
+        pkgFilter.addAction(Intent.ACTION_QUERY_PACKAGE_RESTART);
+        pkgFilter.addDataScheme("package");
+        mContext.registerReceiver(new BroadcastReceiver() {
+            @Override
+            public void onReceive(Context context, Intent intent) {
+                String[] pkgs = intent.getStringArrayExtra(Intent.EXTRA_PACKAGES);
+                if (pkgs != null) {
+                    for (String pkg : pkgs) {
+                        synchronized (ActivityManagerService.this) {
+                            if (forceStopPackageLocked(pkg, -1, false, false, false, false, false,
+                                    0, "finished booting")) {
+                                setResultCode(Activity.RESULT_OK);
+                                return;
+                            }
+                        }
+                    }
+                }
+            }
+        }, pkgFilter);
 
         // Let system services know.
         mSystemServiceManager.startBootPhase(SystemService.PHASE_BOOT_COMPLETED);
@@ -8401,6 +8331,47 @@
         }
     }
 
+    private void removeTasksByPackageNameLocked(String packageName, int userId) {
+        // Remove all tasks with activities in the specified package from the list of recent tasks
+        for (int i = mRecentTasks.size() - 1; i >= 0; i--) {
+            TaskRecord tr = mRecentTasks.get(i);
+            if (tr.userId != userId) continue;
+
+            ComponentName cn = tr.intent.getComponent();
+            if (cn != null && cn.getPackageName().equals(packageName)) {
+                // If the package name matches, remove the task.
+                removeTaskByIdLocked(tr.taskId, true);
+            }
+        }
+    }
+
+    private void removeTasksByRemovedPackageComponentsLocked(String packageName, int userId) {
+        final IPackageManager pm = AppGlobals.getPackageManager();
+        final HashSet<ComponentName> componentsKnownToExist = new HashSet<ComponentName>();
+
+        for (int i = mRecentTasks.size() - 1; i >= 0; i--) {
+            TaskRecord tr = mRecentTasks.get(i);
+            if (tr.userId != userId) continue;
+
+            ComponentName cn = tr.intent.getComponent();
+            if (cn != null && cn.getPackageName().equals(packageName)) {
+                // Skip if component still exists in the package.
+                if (componentsKnownToExist.contains(cn)) continue;
+
+                try {
+                    ActivityInfo info = pm.getActivityInfo(cn, 0, userId);
+                    if (info != null) {
+                        componentsKnownToExist.add(cn);
+                    } else {
+                        removeTaskByIdLocked(tr.taskId, false);
+                    }
+                } catch (RemoteException e) {
+                    Log.e(TAG, "Activity info query failed. component=" + cn, e);
+                }
+            }
+        }
+    }
+
     /**
      * Removes the task with the specified task id.
      *
@@ -11250,13 +11221,18 @@
 
             try {
                 if (AppGlobals.getPackageManager().hasSystemUidErrors()) {
-                    Message msg = Message.obtain();
-                    msg.what = SHOW_UID_ERROR_MSG;
-                    mHandler.sendMessage(msg);
+                    Slog.e(TAG, "UIDs on the system are inconsistent, you need to wipe your"
+                            + " data partition or your device will be unstable.");
+                    mHandler.obtainMessage(SHOW_UID_ERROR_MSG).sendToTarget();
                 }
             } catch (RemoteException e) {
             }
 
+            if (!Build.isFingerprintConsistent()) {
+                Slog.e(TAG, "Build fingerprint is not consistent, warning user");
+                mHandler.obtainMessage(SHOW_FINGERPRINT_ERROR_MSG).sendToTarget();
+            }
+
             long ident = Binder.clearCallingIdentity();
             try {
                 Intent intent = new Intent(Intent.ACTION_USER_STARTED);
@@ -13962,7 +13938,9 @@
 
         ArrayList<MemItem> procMems = new ArrayList<MemItem>();
         final SparseArray<MemItem> procMemsMap = new SparseArray<MemItem>();
-        long nativePss=0, dalvikPss=0, otherPss=0;
+        long nativePss = 0;
+        long dalvikPss = 0;
+        long otherPss = 0;
         long[] miscPss = new long[Debug.MemoryInfo.NUM_OTHER_STATS];
 
         long oomPss[] = new long[DUMP_MEM_OOM_LABEL.length];
@@ -15661,126 +15639,133 @@
             }
         }
 
-        // Handle special intents: if this broadcast is from the package
-        // manager about a package being removed, we need to remove all of
-        // its activities from the history stack.
-        final boolean uidRemoved = Intent.ACTION_UID_REMOVED.equals(
-                intent.getAction());
-        if (Intent.ACTION_PACKAGE_REMOVED.equals(intent.getAction())
-                || Intent.ACTION_PACKAGE_CHANGED.equals(intent.getAction())
-                || Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE.equals(intent.getAction())
-                || Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE.equals(intent.getAction())
-                || uidRemoved) {
-            if (checkComponentPermission(
-                    android.Manifest.permission.BROADCAST_PACKAGE_REMOVED,
-                    callingPid, callingUid, -1, true)
-                    == PackageManager.PERMISSION_GRANTED) {
-                if (uidRemoved) {
-                    final Bundle intentExtras = intent.getExtras();
-                    final int uid = intentExtras != null
-                            ? intentExtras.getInt(Intent.EXTRA_UID) : -1;
-                    if (uid >= 0) {
-                        BatteryStatsImpl bs = mBatteryStatsService.getActiveStatistics();
-                        synchronized (bs) {
-                            bs.removeUidStatsLocked(uid);
-                        }
-                        mAppOpsService.uidRemoved(uid);
+        final String action = intent.getAction();
+        if (action != null) {
+            switch (action) {
+                case Intent.ACTION_UID_REMOVED:
+                case Intent.ACTION_PACKAGE_REMOVED:
+                case Intent.ACTION_PACKAGE_CHANGED:
+                case Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE:
+                case Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE:
+                    // Handle special intents: if this broadcast is from the package
+                    // manager about a package being removed, we need to remove all of
+                    // its activities from the history stack.
+                    if (checkComponentPermission(
+                            android.Manifest.permission.BROADCAST_PACKAGE_REMOVED,
+                            callingPid, callingUid, -1, true)
+                            != PackageManager.PERMISSION_GRANTED) {
+                        String msg = "Permission Denial: " + intent.getAction()
+                                + " broadcast from " + callerPackage + " (pid=" + callingPid
+                                + ", uid=" + callingUid + ")"
+                                + " requires "
+                                + android.Manifest.permission.BROADCAST_PACKAGE_REMOVED;
+                        Slog.w(TAG, msg);
+                        throw new SecurityException(msg);
                     }
-                } else {
-                    // If resources are unavailable just force stop all
-                    // those packages and flush the attribute cache as well.
-                    if (Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE.equals(intent.getAction())) {
-                        String list[] = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
-                        if (list != null && (list.length > 0)) {
-                            for (String pkg : list) {
-                                forceStopPackageLocked(pkg, -1, false, true, true, false, false, userId,
-                                        "storage unmount");
+                    switch (action) {
+                        case Intent.ACTION_UID_REMOVED:
+                            final Bundle intentExtras = intent.getExtras();
+                            final int uid = intentExtras != null
+                                    ? intentExtras.getInt(Intent.EXTRA_UID) : -1;
+                            if (uid >= 0) {
+                                BatteryStatsImpl bs = mBatteryStatsService.getActiveStatistics();
+                                synchronized (bs) {
+                                    bs.removeUidStatsLocked(uid);
+                                }
+                                mAppOpsService.uidRemoved(uid);
                             }
+                            break;
+                        case Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE:
+                            // If resources are unavailable just force stop all those packages
+                            // and flush the attribute cache as well.
+                            String list[] =
+                                    intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
+                            if (list != null && list.length > 0) {
+                                for (int i = 0; i < list.length; i++) {
+                                    forceStopPackageLocked(list[i], -1, false, true, true,
+                                            false, false, userId, "storage unmount");
+                                }
+                                cleanupRecentTasksLocked(UserHandle.USER_ALL);
+                                sendPackageBroadcastLocked(
+                                        IApplicationThread.EXTERNAL_STORAGE_UNAVAILABLE, list,
+                                        userId);
+                            }
+                            break;
+                        case Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE:
                             cleanupRecentTasksLocked(UserHandle.USER_ALL);
-                            sendPackageBroadcastLocked(
-                                    IApplicationThread.EXTERNAL_STORAGE_UNAVAILABLE, list, userId);
-                        }
-                    } else if (Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE.equals(
-                            intent.getAction())) {
-                        cleanupRecentTasksLocked(UserHandle.USER_ALL);
-                    } else {
-                        Uri data = intent.getData();
-                        String ssp;
-                        if (data != null && (ssp=data.getSchemeSpecificPart()) != null) {
-                            boolean removed = Intent.ACTION_PACKAGE_REMOVED.equals(
-                                    intent.getAction());
-                            boolean fullUninstall = removed &&
-                                    !intent.getBooleanExtra(Intent.EXTRA_REPLACING, false);
-                            if (!intent.getBooleanExtra(Intent.EXTRA_DONT_KILL_APP, false)) {
-                                forceStopPackageLocked(ssp, UserHandle.getAppId(
-                                        intent.getIntExtra(Intent.EXTRA_UID, -1)), false, true, true,
-                                        false, fullUninstall, userId,
-                                        removed ? "pkg removed" : "pkg changed");
-                            }
-                            if (removed) {
-                                sendPackageBroadcastLocked(IApplicationThread.PACKAGE_REMOVED,
-                                        new String[] {ssp}, userId);
-                                if (!intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) {
-                                    mAppOpsService.packageRemoved(
-                                            intent.getIntExtra(Intent.EXTRA_UID, -1), ssp);
+                            break;
+                        case Intent.ACTION_PACKAGE_REMOVED:
+                        case Intent.ACTION_PACKAGE_CHANGED:
+                            Uri data = intent.getData();
+                            String ssp;
+                            if (data != null && (ssp=data.getSchemeSpecificPart()) != null) {
+                                boolean removed = Intent.ACTION_PACKAGE_REMOVED.equals(action);
+                                boolean fullUninstall = removed &&
+                                        !intent.getBooleanExtra(Intent.EXTRA_REPLACING, false);
+                                if (!intent.getBooleanExtra(Intent.EXTRA_DONT_KILL_APP, false)) {
+                                    forceStopPackageLocked(ssp, UserHandle.getAppId(
+                                            intent.getIntExtra(Intent.EXTRA_UID, -1)),
+                                            false, true, true, false, fullUninstall, userId,
+                                            removed ? "pkg removed" : "pkg changed");
+                                }
+                                if (removed) {
+                                    sendPackageBroadcastLocked(IApplicationThread.PACKAGE_REMOVED,
+                                            new String[] {ssp}, userId);
+                                    if (fullUninstall) {
+                                        mAppOpsService.packageRemoved(
+                                                intent.getIntExtra(Intent.EXTRA_UID, -1), ssp);
 
-                                    // Remove all permissions granted from/to this package
-                                    removeUriPermissionsForPackageLocked(ssp, userId, true);
+                                        // Remove all permissions granted from/to this package
+                                        removeUriPermissionsForPackageLocked(ssp, userId, true);
+
+                                        removeTasksByPackageNameLocked(ssp, userId);
+                                    }
+                                } else {
+                                    removeTasksByRemovedPackageComponentsLocked(ssp, userId);
                                 }
                             }
+                            break;
+                    }
+                    break;
+                case Intent.ACTION_PACKAGE_ADDED:
+                    // Special case for adding a package: by default turn on compatibility mode.
+                    Uri data = intent.getData();
+                    String ssp;
+                    if (data != null && (ssp = data.getSchemeSpecificPart()) != null) {
+                        final boolean replacing =
+                                intent.getBooleanExtra(Intent.EXTRA_REPLACING, false);
+                        mCompatModePackages.handlePackageAddedLocked(ssp, replacing);
+
+                        if (replacing) {
+                            removeTasksByRemovedPackageComponentsLocked(ssp, userId);
                         }
                     }
-                }
-            } else {
-                String msg = "Permission Denial: " + intent.getAction()
-                        + " broadcast from " + callerPackage + " (pid=" + callingPid
-                        + ", uid=" + callingUid + ")"
-                        + " requires "
-                        + android.Manifest.permission.BROADCAST_PACKAGE_REMOVED;
-                Slog.w(TAG, msg);
-                throw new SecurityException(msg);
+                    break;
+                case Intent.ACTION_TIMEZONE_CHANGED:
+                    // If this is the time zone changed action, queue up a message that will reset
+                    // the timezone of all currently running processes. This message will get
+                    // queued up before the broadcast happens.
+                    mHandler.sendEmptyMessage(UPDATE_TIME_ZONE);
+                    break;
+                case Intent.ACTION_TIME_CHANGED:
+                    // If the user set the time, let all running processes know.
+                    final int is24Hour =
+                            intent.getBooleanExtra(Intent.EXTRA_TIME_PREF_24_HOUR_FORMAT, false) ? 1
+                                    : 0;
+                    mHandler.sendMessage(mHandler.obtainMessage(UPDATE_TIME, is24Hour, 0));
+                    BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
+                    synchronized (stats) {
+                        stats.noteCurrentTimeChangedLocked();
+                    }
+                    break;
+                case Intent.ACTION_CLEAR_DNS_CACHE:
+                    mHandler.sendEmptyMessage(CLEAR_DNS_CACHE_MSG);
+                    break;
+                case Proxy.PROXY_CHANGE_ACTION:
+                    ProxyInfo proxy = intent.getParcelableExtra(Proxy.EXTRA_PROXY_INFO);
+                    mHandler.sendMessage(mHandler.obtainMessage(UPDATE_HTTP_PROXY_MSG, proxy));
+                    break;
             }
-
-        // Special case for adding a package: by default turn on compatibility
-        // mode.
-        } else if (Intent.ACTION_PACKAGE_ADDED.equals(intent.getAction())) {
-            Uri data = intent.getData();
-            String ssp;
-            if (data != null && (ssp=data.getSchemeSpecificPart()) != null) {
-                mCompatModePackages.handlePackageAddedLocked(ssp,
-                        intent.getBooleanExtra(Intent.EXTRA_REPLACING, false));
-            }
-        }
-
-        /*
-         * If this is the time zone changed action, queue up a message that will reset the timezone
-         * of all currently running processes. This message will get queued up before the broadcast
-         * happens.
-         */
-        if (Intent.ACTION_TIMEZONE_CHANGED.equals(intent.getAction())) {
-            mHandler.sendEmptyMessage(UPDATE_TIME_ZONE);
-        }
-
-        /*
-         * If the user set the time, let all running processes know.
-         */
-        if (Intent.ACTION_TIME_CHANGED.equals(intent.getAction())) {
-            final int is24Hour = intent.getBooleanExtra(
-                    Intent.EXTRA_TIME_PREF_24_HOUR_FORMAT, false) ? 1 : 0;
-            mHandler.sendMessage(mHandler.obtainMessage(UPDATE_TIME, is24Hour, 0));
-            BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
-            synchronized (stats) {
-                stats.noteCurrentTimeChangedLocked();
-            }
-        }
-
-        if (Intent.ACTION_CLEAR_DNS_CACHE.equals(intent.getAction())) {
-            mHandler.sendEmptyMessage(CLEAR_DNS_CACHE_MSG);
-        }
-
-        if (Proxy.PROXY_CHANGE_ACTION.equals(intent.getAction())) {
-            ProxyInfo proxy = intent.getParcelableExtra(Proxy.EXTRA_PROXY_INFO);
-            mHandler.sendMessage(mHandler.obtainMessage(UPDATE_HTTP_PROXY_MSG, proxy));
         }
 
         // Add to the sticky list if requested.
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index 0cf22493..db0f53b 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -1298,7 +1298,12 @@
                 if (userHandle == 0 || user == null || mRemovingUserIds.get(userHandle)) {
                     return false;
                 }
+
+                // We remember deleted user IDs to prevent them from being
+                // reused during the current boot; they can still be reused
+                // after a reboot.
                 mRemovingUserIds.put(userHandle, true);
+
                 try {
                     mAppOpsService.removeUser(userHandle);
                 } catch (RemoteException e) {
@@ -1387,18 +1392,6 @@
         // Remove this user from the list
         mUsers.remove(userHandle);
 
-        // Have user ID linger for several seconds to let external storage VFS
-        // cache entries expire. This must be greater than the 'entry_valid'
-        // timeout used by the FUSE daemon.
-        mHandler.postDelayed(new Runnable() {
-            @Override
-            public void run() {
-                synchronized (mPackagesLock) {
-                    mRemovingUserIds.delete(userHandle);
-                }
-            }
-        }, MINUTE_IN_MILLIS);
-
         mRestrictionsPinStates.remove(userHandle);
         // Remove user file
         AtomicFile userFile = new AtomicFile(new File(mUsersDir, userHandle + XML_SUFFIX));
diff --git a/services/core/java/com/android/server/wm/WindowAnimator.java b/services/core/java/com/android/server/wm/WindowAnimator.java
index 345e8af..fe2e0a6 100644
--- a/services/core/java/com/android/server/wm/WindowAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowAnimator.java
@@ -221,6 +221,24 @@
         }
     }
 
+    private boolean shouldForceHide(WindowState win) {
+        final WindowState imeTarget = mService.mInputMethodTarget;
+        final boolean showImeOverKeyguard = imeTarget != null && imeTarget.isVisibleNow() &&
+                (imeTarget.getAttrs().flags & FLAG_SHOW_WHEN_LOCKED) != 0;
+
+        final WindowState winShowWhenLocked = (WindowState) mPolicy.getWinShowWhenLockedLw();
+        final AppWindowToken appShowWhenLocked = winShowWhenLocked == null ?
+                null : winShowWhenLocked.mAppToken;
+        final boolean hideWhenLocked =
+                !(((win.mIsImWindow || imeTarget == win) && showImeOverKeyguard)
+                        || (appShowWhenLocked != null && (appShowWhenLocked == win.mAppToken ||
+                        // Show error dialogs over apps that dismiss keyguard.
+                        (win.mAttrs.privateFlags & PRIVATE_FLAG_SYSTEM_ERROR) != 0)));
+        return ((mForceHiding == KEYGUARD_ANIMATING_IN)
+                && (!win.mWinAnimator.isAnimating() || hideWhenLocked))
+                || ((mForceHiding == KEYGUARD_SHOWN) && hideWhenLocked);
+    }
+
     private void updateWindowsLocked(final int displayId) {
         ++mAnimTransactionSequence;
 
@@ -256,14 +274,6 @@
 
         mForceHiding = KEYGUARD_NOT_SHOWN;
 
-        final WindowState imeTarget = mService.mInputMethodTarget;
-        final boolean showImeOverKeyguard = imeTarget != null && imeTarget.isVisibleNow() &&
-                (imeTarget.getAttrs().flags & FLAG_SHOW_WHEN_LOCKED) != 0;
-
-        final WindowState winShowWhenLocked = (WindowState) mPolicy.getWinShowWhenLockedLw();
-        final AppWindowToken appShowWhenLocked = winShowWhenLocked == null ?
-                null : winShowWhenLocked.mAppToken;
-
         boolean wallpaperInUnForceHiding = false;
         boolean startingInUnForceHiding = false;
         ArrayList<WindowStateAnimator> unForceHiding = null;
@@ -272,7 +282,8 @@
             WindowState win = windows.get(i);
             WindowStateAnimator winAnimator = win.mWinAnimator;
             final int flags = win.mAttrs.flags;
-
+            boolean canBeForceHidden = mPolicy.canBeForceHidden(win, win.mAttrs);
+            boolean shouldBeForceHidden = shouldForceHide(win);
             if (winAnimator.mSurfaceControl != null) {
                 final boolean wasAnimating = winAnimator.mWasAnimating;
                 final boolean nowAnimating = winAnimator.stepAnimationLocked(mCurrentTime);
@@ -332,15 +343,8 @@
                             + " vis=" + win.mViewVisibility
                             + " hidden=" + win.mRootToken.hidden
                             + " anim=" + win.mWinAnimator.mAnimation);
-                } else if (mPolicy.canBeForceHidden(win, win.mAttrs)) {
-                    final boolean hideWhenLocked =
-                            !(((win.mIsImWindow || imeTarget == win) && showImeOverKeyguard)
-                            || (appShowWhenLocked != null && (appShowWhenLocked == win.mAppToken ||
-                            // Show error dialogs over apps that dismiss keyguard.
-                            (win.mAttrs.privateFlags & PRIVATE_FLAG_SYSTEM_ERROR) != 0)));
-                    if (((mForceHiding == KEYGUARD_ANIMATING_IN)
-                                && (!winAnimator.isAnimating() || hideWhenLocked))
-                            || ((mForceHiding == KEYGUARD_SHOWN) && hideWhenLocked)) {
+                } else if (canBeForceHidden) {
+                    if (shouldBeForceHidden) {
                         if (!win.hideLw(false, false)) {
                             // Was already hidden
                             continue;
@@ -411,6 +415,16 @@
                 }
             }
 
+            // If the window doesn't have a surface, the only thing we care about is the correct
+            // policy visibility.
+            else if (canBeForceHidden) {
+                if (shouldBeForceHidden) {
+                    win.hideLw(false, false);
+                } else {
+                    win.showLw(false, false);
+                }
+            }
+
             final AppWindowToken atoken = win.mAppToken;
             if (winAnimator.mDrawState == WindowStateAnimator.READY_TO_SHOW) {
                 if (atoken == null || atoken.allDrawn) {
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
index 82b7f8b..f5d4867 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
@@ -136,11 +136,14 @@
                     Settings.Secure.VOICE_INTERACTION_SERVICE, userHandle);
             ComponentName curRecognizer = getCurRecognizer(userHandle);
             VoiceInteractionServiceInfo curInteractorInfo = null;
-            if (curInteractorStr == null && curRecognizer != null) {
+            if (curInteractorStr == null && curRecognizer != null
+                    && !ActivityManager.isLowRamDeviceStatic()) {
                 // If there is no interactor setting, that means we are upgrading
                 // from an older platform version.  If the current recognizer is not
                 // set or matches the preferred recognizer, then we want to upgrade
                 // the user to have the default voice interaction service enabled.
+                // Note that we don't do this for low-RAM devices, since we aren't
+                // supporting voice interaction services there.
                 curInteractorInfo = findAvailInteractor(userHandle, curRecognizer);
                 if (curInteractorInfo != null) {
                     // Looks good!  We'll apply this one.  To make it happen, we clear the
@@ -150,6 +153,15 @@
                 }
             }
 
+            // If we are on a svelte device, make sure an interactor is not currently
+            // enabled; if it is, turn it off.
+            if (ActivityManager.isLowRamDeviceStatic() && curInteractorStr != null) {
+                if (!TextUtils.isEmpty(curInteractorStr)) {
+                    setCurInteractor(null, userHandle);
+                    curInteractorStr = "";
+                }
+            }
+
             if (curRecognizer != null) {
                 // If we already have at least a recognizer, then we probably want to
                 // leave things as they are...  unless something has disappeared.
@@ -171,10 +183,11 @@
                 }
             }
 
-            // Initializing settings, look for an interactor first.
-            if (curInteractorInfo == null) {
+            // Initializing settings, look for an interactor first (but only on non-svelte).
+            if (curInteractorInfo == null && !ActivityManager.isLowRamDeviceStatic()) {
                 curInteractorInfo = findAvailInteractor(userHandle, null);
             }
+
             if (curInteractorInfo != null) {
                 // Eventually it will be an error to not specify this.
                 setCurInteractor(new ComponentName(curInteractorInfo.getServiceInfo().packageName,
diff --git a/telephony/java/android/telephony/SubscriptionInfo.java b/telephony/java/android/telephony/SubscriptionInfo.java
index 26f17c8..a3ace36 100644
--- a/telephony/java/android/telephony/SubscriptionInfo.java
+++ b/telephony/java/android/telephony/SubscriptionInfo.java
@@ -34,6 +34,11 @@
 public class SubscriptionInfo implements Parcelable {
 
     /**
+     * Size of text to render on the icon.
+     */
+    private static final int TEXT_SIZE = 22;
+
+    /**
      * Subscription Identifier, this is a device unique number
      * and not an index into an array
      */
@@ -201,10 +206,11 @@
         paint.setColorFilter(null);
 
         // Write the sim slot index.
+        paint.setAntiAlias(true);
         paint.setTypeface(Typeface.create("sans-serif", Typeface.NORMAL));
         paint.setColor(Color.WHITE);
-        paint.setTextSize(12);
-        final String index = Integer.toString(mSimSlotIndex);
+        paint.setTextSize(TEXT_SIZE);
+        final String index = Integer.toString(mSimSlotIndex + 1);
         final Rect textBound = new Rect();
         paint.getTextBounds(index, 0, 1, textBound);
         final float xOffset = (width / 2.f) - textBound.centerX();