Merge "Remove no longer needed http proxy handling code, it's obsolete now"
diff --git a/api/current.txt b/api/current.txt
index c0ed81a..c34f5ed 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -4771,6 +4771,7 @@
     method public boolean isActivePasswordSufficient();
     method public boolean isAdminActive(android.content.ComponentName);
     method public boolean isDeviceOwnerApp(java.lang.String);
+    method public boolean isProfileOwnerApp(java.lang.String);
     method public void lockNow();
     method public void removeActiveAdmin(android.content.ComponentName);
     method public boolean resetPassword(java.lang.String, int);
@@ -11274,6 +11275,7 @@
     field public static final android.hardware.camera2.CameraMetadata.Key LENS_INFO_HYPERFOCAL_DISTANCE;
     field public static final android.hardware.camera2.CameraMetadata.Key LENS_INFO_MINIMUM_FOCUS_DISTANCE;
     field public static final android.hardware.camera2.CameraMetadata.Key LENS_INFO_SHADING_MAP_SIZE;
+    field public static final android.hardware.camera2.CameraMetadata.Key REQUEST_MAX_NUM_INPUT_STREAMS;
     field public static final android.hardware.camera2.CameraMetadata.Key REQUEST_MAX_NUM_OUTPUT_STREAMS;
     field public static final android.hardware.camera2.CameraMetadata.Key REQUEST_PARTIAL_RESULT_COUNT;
     field public static final android.hardware.camera2.CameraMetadata.Key REQUEST_PIPELINE_MAX_DEPTH;
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index ab82531..40bdb73 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -26,6 +26,7 @@
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
 import android.os.Handler;
+import android.os.Process;
 import android.os.RemoteCallback;
 import android.os.RemoteException;
 import android.os.ServiceManager;
@@ -1681,4 +1682,88 @@
         }
         return null;
     }
+
+    /**
+     * @hide
+     * Sets the given package as the profile owner of the given user profile. The package must
+     * already be installed and there shouldn't be an existing profile owner registered for this
+     * user. Also, this method must be called before the user has been used for the first time.
+     * @param packageName the package name of the application to be registered as profile owner.
+     * @param ownerName the human readable name of the organisation associated with this DPM.
+     * @return whether the package was successfully registered as the profile owner.
+     * @throws IllegalArgumentException if packageName is null, the package isn't installed, or
+     *         the user has already been set up.
+     */
+    public boolean setProfileOwner(String packageName, String ownerName)
+            throws IllegalArgumentException {
+        if (mService != null) {
+            try {
+                return mService.setProfileOwner(packageName, ownerName,
+                        Process.myUserHandle().getIdentifier());
+            } catch (RemoteException re) {
+                Log.w(TAG, "Failed to set profile owner", re);
+                throw new IllegalArgumentException("Couldn't set profile owner.", re);
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Used to determine if a particular package is registered as the Profile Owner for the
+     * current user. A profile owner is a special device admin that has additional priviledges
+     * within the managed profile.
+     *
+     * @param packageName The package name of the app to compare with the registered profile owner.
+     * @return Whether or not the package is registered as the profile owner.
+     */
+    public boolean isProfileOwnerApp(String packageName) {
+        if (mService != null) {
+            try {
+                String profileOwnerPackage = mService.getProfileOwner(
+                        Process.myUserHandle().getIdentifier());
+                return profileOwnerPackage != null && profileOwnerPackage.equals(packageName);
+            } catch (RemoteException re) {
+                Log.w(TAG, "Failed to check profile owner");
+            }
+        }
+        return false;
+    }
+
+    /**
+     * @hide
+     * @return the packageName of the owner of the given user profile or null if no profile
+     * owner has been set for that user.
+     * @throws IllegalArgumentException if the userId is invalid.
+     */
+    public String getProfileOwner() throws IllegalArgumentException {
+        if (mService != null) {
+            try {
+                return mService.getProfileOwner(Process.myUserHandle().getIdentifier());
+            } catch (RemoteException re) {
+                Log.w(TAG, "Failed to get profile owner");
+                throw new IllegalArgumentException(
+                        "Requested profile owner for invalid userId", re);
+            }
+        }
+        return null;
+    }
+
+    /**
+     * @hide
+     * @return the human readable name of the organisation associated with this DPM or null if
+     *         one is not set.
+     * @throws IllegalArgumentException if the userId is invalid.
+     */
+    public String getProfileOwnerName() throws IllegalArgumentException {
+        if (mService != null) {
+            try {
+                return mService.getProfileOwnerName(Process.myUserHandle().getIdentifier());
+            } catch (RemoteException re) {
+                Log.w(TAG, "Failed to get profile owner");
+                throw new IllegalArgumentException(
+                        "Requested profile owner for invalid userId", re);
+            }
+        }
+        return null;
+    }
 }
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index 172c47c..9d189db 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -103,6 +103,10 @@
     String getDeviceOwner();
     String getDeviceOwnerName();
 
+    boolean setProfileOwner(String packageName, String ownerName, int userHandle);
+    String getProfileOwner(int userHandle);
+    String getProfileOwnerName(int userHandle);
+
     boolean installCaCert(in byte[] certBuffer);
     void uninstallCaCert(in byte[] certBuffer);
 }
diff --git a/core/java/android/hardware/camera2/CameraCharacteristics.java b/core/java/android/hardware/camera2/CameraCharacteristics.java
index bb8b184..913b273 100644
--- a/core/java/android/hardware/camera2/CameraCharacteristics.java
+++ b/core/java/android/hardware/camera2/CameraCharacteristics.java
@@ -398,16 +398,44 @@
             new Key<Byte>("android.quirks.usePartialResult", byte.class);
 
     /**
-     * <p>How many output streams can be allocated at
-     * the same time for each type of stream</p>
-     * <p>Video snapshot with preview callbacks requires 3
-     * processed streams (preview, record, app callbacks) and
-     * one JPEG stream (snapshot)</p>
+     * <p>The maximum numbers of different types of output streams
+     * that can be configured and used simultaneously by a camera device.</p>
+     * <p>This is a 3 element tuple that contains the max number of output simultaneous
+     * streams for raw sensor, processed (and uncompressed), and JPEG formats respectively.
+     * For example, if max raw sensor format output stream number is 1, max YUV streams
+     * number is 3, and max JPEG stream number is 2, then this tuple should be <code>(1, 3, 2)</code>.</p>
+     * <p>This lists the upper bound of the number of output streams supported by
+     * the camera device. Using more streams simultaneously may require more hardware and
+     * CPU resources that will consume more power. The image format for a output stream can
+     * be any supported format provided by {@link CameraCharacteristics#SCALER_AVAILABLE_FORMATS android.scaler.availableFormats}. The formats
+     * defined in {@link CameraCharacteristics#SCALER_AVAILABLE_FORMATS android.scaler.availableFormats} can be catergorized into the 3 stream types
+     * as below:</p>
+     * <ul>
+     * <li>JPEG-compressed format: BLOB.</li>
+     * <li>Raw formats: RAW_SENSOR and RAW_OPAQUE.</li>
+     * <li>processed, uncompressed formats: YCbCr_420_888, YCrCb_420_SP, YV12.</li>
+     * </ul>
+     *
+     * @see CameraCharacteristics#SCALER_AVAILABLE_FORMATS
      */
     public static final Key<int[]> REQUEST_MAX_NUM_OUTPUT_STREAMS =
             new Key<int[]>("android.request.maxNumOutputStreams", int[].class);
 
     /**
+     * <p>The maximum numbers of any type of input streams
+     * that can be configured and used simultaneously by a camera device.</p>
+     * <p>When set to 0, it means no input stream is supported.</p>
+     * <p>The image format for a input stream can be any supported format provided
+     * by android.scaler.availableInputFormats. When using an input stream, there must be
+     * at least one output stream configured to to receive the reprocessed images.</p>
+     * <p>For example, for Zero Shutter Lag (ZSL) still capture use case, the input
+     * stream image format will be RAW_OPAQUE, the associated output stream image format
+     * should be JPEG.</p>
+     */
+    public static final Key<Integer> REQUEST_MAX_NUM_INPUT_STREAMS =
+            new Key<Integer>("android.request.maxNumInputStreams", int.class);
+
+    /**
      * <p>Specifies the number of maximum pipeline stages a frame
      * has to go through from when it's exposed to when it's available
      * to the framework.</p>
diff --git a/core/java/android/hardware/camera2/CaptureRequest.java b/core/java/android/hardware/camera2/CaptureRequest.java
index 1327ba9..ee18041 100644
--- a/core/java/android/hardware/camera2/CaptureRequest.java
+++ b/core/java/android/hardware/camera2/CaptureRequest.java
@@ -373,13 +373,15 @@
     /**
      * <p>A color transform matrix to use to transform
      * from sensor RGB color space to output linear sRGB color space</p>
-     * <p>This matrix is either set by HAL when the request
+     * <p>This matrix is either set by the camera device when the request
      * {@link CaptureRequest#COLOR_CORRECTION_MODE android.colorCorrection.mode} is not TRANSFORM_MATRIX, or
      * directly by the application in the request when the
      * {@link CaptureRequest#COLOR_CORRECTION_MODE android.colorCorrection.mode} is TRANSFORM_MATRIX.</p>
-     * <p>In the latter case, the HAL may round the matrix to account
-     * for precision issues; the final rounded matrix should be
-     * reported back in this matrix result metadata.</p>
+     * <p>In the latter case, the camera device may round the matrix to account
+     * for precision issues; the final rounded matrix should be reported back
+     * in this matrix result metadata. The transform should keep the magnitude
+     * of the output color values within <code>[0, 1.0]</code> (assuming input color
+     * values is within the normalized range <code>[0, 1.0]</code>), or clipping may occur.</p>
      *
      * @see CaptureRequest#COLOR_CORRECTION_MODE
      */
@@ -463,10 +465,23 @@
 
     /**
      * <p>Whether AE is currently locked to its latest
-     * calculated values</p>
+     * calculated values.</p>
      * <p>Note that even when AE is locked, the flash may be
-     * fired if the AE mode is ON_AUTO_FLASH / ON_ALWAYS_FLASH /
+     * fired if the {@link CaptureRequest#CONTROL_AE_MODE android.control.aeMode} is ON_AUTO_FLASH / ON_ALWAYS_FLASH /
      * ON_AUTO_FLASH_REDEYE.</p>
+     * <p>If AE precapture is triggered (see {@link CaptureRequest#CONTROL_AE_PRECAPTURE_TRIGGER android.control.aePrecaptureTrigger})
+     * when AE is already locked, the camera device will not change the exposure time
+     * ({@link CaptureRequest#SENSOR_EXPOSURE_TIME android.sensor.exposureTime}) and sensitivity ({@link CaptureRequest#SENSOR_SENSITIVITY android.sensor.sensitivity})
+     * parameters. The flash may be fired if the android.control.aeMode
+     * is ON_AUTO_FLASH/ON_AUTO_FLASH_REDEYE and the scene is too dark. If the
+     * {@link CaptureRequest#CONTROL_AE_MODE android.control.aeMode} is ON_ALWAYS_FLASH, the scene may become overexposed.</p>
+     * <p>See {@link CaptureResult#CONTROL_AE_STATE android.control.aeState} for AE lock related state transition details.</p>
+     *
+     * @see CaptureRequest#CONTROL_AE_MODE
+     * @see CaptureRequest#CONTROL_AE_PRECAPTURE_TRIGGER
+     * @see CaptureResult#CONTROL_AE_STATE
+     * @see CaptureRequest#SENSOR_EXPOSURE_TIME
+     * @see CaptureRequest#SENSOR_SENSITIVITY
      */
     public static final Key<Boolean> CONTROL_AE_LOCK =
             new Key<Boolean>("android.control.aeLock", boolean.class);
diff --git a/core/java/android/hardware/camera2/CaptureResult.java b/core/java/android/hardware/camera2/CaptureResult.java
index 46d95b1..160b6fc 100644
--- a/core/java/android/hardware/camera2/CaptureResult.java
+++ b/core/java/android/hardware/camera2/CaptureResult.java
@@ -126,13 +126,15 @@
     /**
      * <p>A color transform matrix to use to transform
      * from sensor RGB color space to output linear sRGB color space</p>
-     * <p>This matrix is either set by HAL when the request
+     * <p>This matrix is either set by the camera device when the request
      * {@link CaptureRequest#COLOR_CORRECTION_MODE android.colorCorrection.mode} is not TRANSFORM_MATRIX, or
      * directly by the application in the request when the
      * {@link CaptureRequest#COLOR_CORRECTION_MODE android.colorCorrection.mode} is TRANSFORM_MATRIX.</p>
-     * <p>In the latter case, the HAL may round the matrix to account
-     * for precision issues; the final rounded matrix should be
-     * reported back in this matrix result metadata.</p>
+     * <p>In the latter case, the camera device may round the matrix to account
+     * for precision issues; the final rounded matrix should be reported back
+     * in this matrix result metadata. The transform should keep the magnitude
+     * of the output color values within <code>[0, 1.0]</code> (assuming input color
+     * values is within the normalized range <code>[0, 1.0]</code>), or clipping may occur.</p>
      *
      * @see CaptureRequest#COLOR_CORRECTION_MODE
      */
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index 27c0f5d..4879be6 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -507,10 +507,7 @@
         
         public long time;
 
-        // The command codes 0-3 can be written with delta updates; all others require
-        // that a full entry be written.
-        public static final byte CMD_UPDATE = 0;
-        public static final byte CMD_EVENT = 1;
+        public static final byte CMD_UPDATE = 0;        // These can be written as deltas
         public static final byte CMD_NULL = -1;
         public static final byte CMD_START = 4;
         public static final byte CMD_OVERFLOW = 5;
@@ -520,15 +517,8 @@
         /**
          * Return whether the command code is a delta data update.
          */
-        public static boolean isDeltaData(byte cmd) {
-            return cmd >= 0 && cmd <= 3;
-        }
-
-        /**
-         * Return whether the command code is a delta data update.
-         */
         public boolean isDeltaData() {
-            return cmd >= 0 && cmd <= 3;
+            return cmd == CMD_UPDATE;
         }
 
         public byte batteryLevel;
@@ -555,16 +545,16 @@
         // These states always appear directly in the first int token
         // of a delta change; they should be ones that change relatively
         // frequently.
-        public static final int STATE_WAKE_LOCK_FLAG = 1<<30;
-        public static final int STATE_SENSOR_ON_FLAG = 1<<29;
-        public static final int STATE_GPS_ON_FLAG = 1<<28;
-        public static final int STATE_PHONE_SCANNING_FLAG = 1<<27;
-        public static final int STATE_WIFI_RUNNING_FLAG = 1<<26;
-        public static final int STATE_WIFI_FULL_LOCK_FLAG = 1<<25;
-        public static final int STATE_WIFI_SCAN_FLAG = 1<<24;
-        public static final int STATE_WIFI_MULTICAST_ON_FLAG = 1<<23;
+        public static final int STATE_WAKE_LOCK_FLAG = 1<<31;
+        public static final int STATE_SENSOR_ON_FLAG = 1<<30;
+        public static final int STATE_GPS_ON_FLAG = 1<<29;
+        public static final int STATE_WIFI_FULL_LOCK_FLAG = 1<<28;
+        public static final int STATE_WIFI_SCAN_FLAG = 1<<29;
+        public static final int STATE_WIFI_MULTICAST_ON_FLAG = 1<<26;
         // These are on the lower bits used for the command; if they change
         // we need to write another int of data.
+        public static final int STATE_WIFI_RUNNING_FLAG = 1<<24;
+        public static final int STATE_PHONE_SCANNING_FLAG = 1<<23;
         public static final int STATE_AUDIO_ON_FLAG = 1<<22;
         public static final int STATE_VIDEO_ON_FLAG = 1<<21;
         public static final int STATE_SCREEN_ON_FLAG = 1<<20;
@@ -628,7 +618,8 @@
             } else {
                 dest.writeInt(0);
             }
-            if (cmd == CMD_EVENT) {
+            dest.writeInt(eventCode);
+            if (eventCode != EVENT_NONE) {
                 dest.writeInt(eventCode);
                 eventTag.writeToParcel(dest, flags);
             }
@@ -652,13 +643,10 @@
             } else {
                 wakelockTag = null;
             }
-            if (cmd == CMD_EVENT) {
-                eventCode = src.readInt();
+            eventCode = src.readInt();
+            if (eventCode != EVENT_NONE) {
                 eventTag = localEventTag;
                 eventTag.readFromParcel(src);
-            } else {
-                eventCode = EVENT_NONE;
-                eventTag = null;
             }
             numReadInts += (src.dataPosition()-start)/4;
         }
@@ -681,6 +669,16 @@
         public void setTo(HistoryItem o) {
             time = o.time;
             cmd = o.cmd;
+            setToCommon(o);
+        }
+
+        public void setTo(long time, byte cmd, HistoryItem o) {
+            this.time = time;
+            this.cmd = cmd;
+            setToCommon(o);
+        }
+
+        private void setToCommon(HistoryItem o) {
             batteryLevel = o.batteryLevel;
             batteryStatus = o.batteryStatus;
             batteryHealth = o.batteryHealth;
@@ -703,32 +701,6 @@
             }
         }
 
-        public void setTo(long time, byte cmd, int eventCode, int eventUid, String eventName,
-                HistoryItem o) {
-            this.time = time;
-            this.cmd = cmd;
-            this.eventCode = eventCode;
-            if (eventCode != EVENT_NONE) {
-                eventTag = localEventTag;
-                eventTag.setTo(eventName, eventUid);
-            } else {
-                eventTag = null;
-            }
-            batteryLevel = o.batteryLevel;
-            batteryStatus = o.batteryStatus;
-            batteryHealth = o.batteryHealth;
-            batteryPlugType = o.batteryPlugType;
-            batteryTemperature = o.batteryTemperature;
-            batteryVoltage = o.batteryVoltage;
-            states = o.states;
-            if (o.wakelockTag != null) {
-                wakelockTag = localWakelockTag;
-                wakelockTag.setTo(o.wakelockTag);
-            } else {
-                wakelockTag = null;
-            }
-        }
-
         public boolean sameNonEvent(HistoryItem o) {
             return batteryLevel == o.batteryLevel
                     && batteryStatus == o.batteryStatus
@@ -938,36 +910,36 @@
     
     public static final BitDescription[] HISTORY_STATE_DESCRIPTIONS
             = new BitDescription[] {
-        new BitDescription(HistoryItem.STATE_BATTERY_PLUGGED_FLAG, "plugged", "BP"),
-        new BitDescription(HistoryItem.STATE_SCREEN_ON_FLAG, "screen", "S"),
+        new BitDescription(HistoryItem.STATE_WAKE_LOCK_FLAG, "wake_lock", "w"),
+        new BitDescription(HistoryItem.STATE_SENSOR_ON_FLAG, "sensor", "s"),
         new BitDescription(HistoryItem.STATE_GPS_ON_FLAG, "gps", "g"),
-        new BitDescription(HistoryItem.STATE_PHONE_IN_CALL_FLAG, "phone_in_call", "Pcl"),
-        new BitDescription(HistoryItem.STATE_PHONE_SCANNING_FLAG, "phone_scanning", "Psc"),
-        new BitDescription(HistoryItem.STATE_WIFI_ON_FLAG, "wifi", "W"),
-        new BitDescription(HistoryItem.STATE_WIFI_RUNNING_FLAG, "wifi_running", "Wr"),
         new BitDescription(HistoryItem.STATE_WIFI_FULL_LOCK_FLAG, "wifi_full_lock", "Wl"),
         new BitDescription(HistoryItem.STATE_WIFI_SCAN_FLAG, "wifi_scan", "Ws"),
         new BitDescription(HistoryItem.STATE_WIFI_MULTICAST_ON_FLAG, "wifi_multicast", "Wm"),
-        new BitDescription(HistoryItem.STATE_BLUETOOTH_ON_FLAG, "bluetooth", "b"),
+        new BitDescription(HistoryItem.STATE_WIFI_RUNNING_FLAG, "wifi_running", "Wr"),
+        new BitDescription(HistoryItem.STATE_PHONE_SCANNING_FLAG, "phone_scanning", "Psc"),
         new BitDescription(HistoryItem.STATE_AUDIO_ON_FLAG, "audio", "a"),
         new BitDescription(HistoryItem.STATE_VIDEO_ON_FLAG, "video", "v"),
-        new BitDescription(HistoryItem.STATE_WAKE_LOCK_FLAG, "wake_lock", "w"),
-        new BitDescription(HistoryItem.STATE_SENSOR_ON_FLAG, "sensor", "s"),
-        new BitDescription(HistoryItem.STATE_BRIGHTNESS_MASK,
-                HistoryItem.STATE_BRIGHTNESS_SHIFT, "brightness", "Sb",
-                SCREEN_BRIGHTNESS_NAMES, SCREEN_BRIGHTNESS_SHORT_NAMES),
+        new BitDescription(HistoryItem.STATE_SCREEN_ON_FLAG, "screen", "S"),
+        new BitDescription(HistoryItem.STATE_BATTERY_PLUGGED_FLAG, "plugged", "BP"),
+        new BitDescription(HistoryItem.STATE_PHONE_IN_CALL_FLAG, "phone_in_call", "Pcl"),
+        new BitDescription(HistoryItem.STATE_WIFI_ON_FLAG, "wifi", "W"),
+        new BitDescription(HistoryItem.STATE_BLUETOOTH_ON_FLAG, "bluetooth", "b"),
+        new BitDescription(HistoryItem.STATE_DATA_CONNECTION_MASK,
+                HistoryItem.STATE_DATA_CONNECTION_SHIFT, "data_conn", "Pcn",
+                DATA_CONNECTION_NAMES, DATA_CONNECTION_NAMES),
+        new BitDescription(HistoryItem.STATE_PHONE_STATE_MASK,
+                HistoryItem.STATE_PHONE_STATE_SHIFT, "phone_state", "Pst",
+                new String[] {"in", "out", "emergency", "off"},
+                new String[] {"in", "out", "em", "off"}),
         new BitDescription(HistoryItem.STATE_SIGNAL_STRENGTH_MASK,
                 HistoryItem.STATE_SIGNAL_STRENGTH_SHIFT, "signal_strength", "Pss",
                 SignalStrength.SIGNAL_STRENGTH_NAMES, new String[] {
                     "0", "1", "2", "3", "4"
         }),
-        new BitDescription(HistoryItem.STATE_PHONE_STATE_MASK,
-                HistoryItem.STATE_PHONE_STATE_SHIFT, "phone_state", "Pst",
-                new String[] {"in", "out", "emergency", "off"},
-                new String[] {"in", "out", "em", "off"}),
-        new BitDescription(HistoryItem.STATE_DATA_CONNECTION_MASK,
-                HistoryItem.STATE_DATA_CONNECTION_SHIFT, "data_conn", "Pcn",
-                DATA_CONNECTION_NAMES, DATA_CONNECTION_NAMES),
+        new BitDescription(HistoryItem.STATE_BRIGHTNESS_MASK,
+                HistoryItem.STATE_BRIGHTNESS_SHIFT, "brightness", "Sb",
+                SCREEN_BRIGHTNESS_NAMES, SCREEN_BRIGHTNESS_SHORT_NAMES),
     };
 
     /**
@@ -2464,7 +2436,8 @@
                     else if (rec.batteryLevel < 100) pw.print("0");
                     pw.print(rec.batteryLevel);
                     pw.print(" ");
-                    if (rec.states < 0x10) pw.print("0000000");
+                    if (rec.states < 0) ;
+                    else if (rec.states < 0x10) pw.print("0000000");
                     else if (rec.states < 0x100) pw.print("000000");
                     else if (rec.states < 0x1000) pw.print("00000");
                     else if (rec.states < 0x10000) pw.print("0000");
diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java
index 3a9611e..0439eeb 100644
--- a/core/java/android/os/PowerManager.java
+++ b/core/java/android/os/PowerManager.java
@@ -223,6 +223,13 @@
     public static final int ON_AFTER_RELEASE = 0x20000000;
 
     /**
+     * Wake lock flag: This wake lock is not important for logging events.  If a later
+     * wake lock is acquired that is important, it will be considered the one to log.
+     * @hide
+     */
+    public static final int UNIMPORTANT_FOR_LOGGING = 0x40000000;
+
+    /**
      * Flag for {@link WakeLock#release release(int)} to defer releasing a
      * {@link #PROXIMITY_SCREEN_OFF_WAKE_LOCK} wake lock until the proximity sensor returns
      * a negative value.
@@ -634,8 +641,8 @@
      * </p>
      */
     public final class WakeLock {
-        private final int mFlags;
-        private final String mTag;
+        private int mFlags;
+        private String mTag;
         private final String mPackageName;
         private final IBinder mToken;
         private int mCount;
@@ -829,6 +836,17 @@
             }
         }
 
+        /** @hide */
+        public void setTag(String tag) {
+            mTag = tag;
+        }
+
+        /** @hide */
+        public void setUnimportantForLogging(boolean state) {
+            if (state) mFlags |= UNIMPORTANT_FOR_LOGGING;
+            else mFlags &= ~UNIMPORTANT_FOR_LOGGING;
+        }
+
         @Override
         public String toString() {
             synchronized (mToken) {
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index b9a898e..9332578 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -6057,6 +6057,14 @@
          */
         public static final String WIFI_BOUNCE_DELAY_OVERRIDE_MS = "wifi_bounce_delay_override_ms";
 
+        /**
+         * Defines global runtime overrides to window policy.
+         *
+         * See {@link com.android.internal.policy.impl.PolicyControl} for value format.
+         *
+         * @hide
+         */
+        public static final String POLICY_CONTROL = "policy_control";
 
         /**
          * Settings to backup. This is here so that it's in the same place as the settings
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 518908f..2710fdf 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -14983,7 +14983,6 @@
      * @param displayList Valid display list for the background drawable
      */
     private void setBackgroundDisplayListProperties(DisplayList displayList) {
-        displayList.setProjectBackwards((mPrivateFlags3 & PFLAG3_PROJECT_BACKGROUND) != 0);
         displayList.setTranslationX(mScrollX);
         displayList.setTranslationY(mScrollY);
     }
@@ -15014,6 +15013,7 @@
 
         // Set up drawable properties that are view-independent.
         displayList.setLeftTopRightBottom(bounds.left, bounds.top, bounds.right, bounds.bottom);
+        displayList.setProjectBackwards(drawable.isProjected());
         displayList.setClipToBounds(false);
         return displayList;
     }
@@ -15363,18 +15363,16 @@
     public void invalidateDrawable(Drawable drawable) {
         if (verifyDrawable(drawable)) {
             if (drawable == mBackground && mBackgroundDisplayList != null) {
-                // If we're using a background display list, we only need to
-                // invalidate the display list and notify the parent to redraw.
+                // We'll need to redraw the display list.
                 mBackgroundDisplayList.clear();
-                invalidateViewProperty(true, false);
-            } else {
-                final Rect dirty = drawable.getBounds();
-                final int scrollX = mScrollX;
-                final int scrollY = mScrollY;
-
-                invalidate(dirty.left + scrollX, dirty.top + scrollY,
-                        dirty.right + scrollX, dirty.bottom + scrollY);
             }
+
+            final Rect dirty = drawable.getDirtyBounds();
+            final int scrollX = mScrollX;
+            final int scrollY = mScrollY;
+
+            invalidate(dirty.left + scrollX, dirty.top + scrollY,
+                    dirty.right + scrollX, dirty.bottom + scrollY);
         }
     }
 
@@ -15386,6 +15384,7 @@
      * @param when the time at which the action must occur. Uses the
      *        {@link SystemClock#uptimeMillis} timebase.
      */
+    @Override
     public void scheduleDrawable(Drawable who, Runnable what, long when) {
         if (verifyDrawable(who) && what != null) {
             final long delay = when - SystemClock.uptimeMillis();
@@ -15405,6 +15404,7 @@
      * @param who the recipient of the action
      * @param what the action to cancel
      */
+    @Override
     public void unscheduleDrawable(Drawable who, Runnable what) {
         if (verifyDrawable(who) && what != null) {
             if (mAttachInfo != null) {
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 7ee33c1..826bcec 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -845,8 +845,8 @@
 
     /**
      * Loads the URL with postData using "POST" method into this WebView. If url
-     * is not a network URL, it will be loaded with {link
-     * {@link #loadUrl(String)} instead.
+     * is not a network URL, it will be loaded with {@link #loadUrl(String)}
+     * instead, ignoring the postData param.
      *
      * @param url the URL of the resource to load
      * @param postData the data will be passed to "POST" request, which must be
@@ -855,7 +855,11 @@
     public void postUrl(String url, byte[] postData) {
         checkThread();
         if (DebugFlags.TRACE_API) Log.d(LOGTAG, "postUrl=" + url);
-        mProvider.postUrl(url, postData);
+        if (URLUtil.isNetworkUrl(url)) {
+            mProvider.postUrl(url, postData);
+        } else {
+            mProvider.loadUrl(url);
+        }
     }
 
     /**
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 3be23b7..65b79fc 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -4814,6 +4814,8 @@
 
     @Override
     public void invalidateDrawable(Drawable drawable) {
+        boolean handled = false;
+
         if (verifyDrawable(drawable)) {
             final Rect dirty = drawable.getBounds();
             int scrollX = mScrollX;
@@ -4831,6 +4833,7 @@
 
                     scrollX += mPaddingLeft;
                     scrollY += compoundPaddingTop + (vspace - drawables.mDrawableHeightLeft) / 2;
+                    handled = true;
                 } else if (drawable == drawables.mDrawableRight) {
                     final int compoundPaddingTop = getCompoundPaddingTop();
                     final int compoundPaddingBottom = getCompoundPaddingBottom();
@@ -4838,6 +4841,7 @@
 
                     scrollX += (mRight - mLeft - mPaddingRight - drawables.mDrawableSizeRight);
                     scrollY += compoundPaddingTop + (vspace - drawables.mDrawableHeightRight) / 2;
+                    handled = true;
                 } else if (drawable == drawables.mDrawableTop) {
                     final int compoundPaddingLeft = getCompoundPaddingLeft();
                     final int compoundPaddingRight = getCompoundPaddingRight();
@@ -4845,6 +4849,7 @@
 
                     scrollX += compoundPaddingLeft + (hspace - drawables.mDrawableWidthTop) / 2;
                     scrollY += mPaddingTop;
+                    handled = true;
                 } else if (drawable == drawables.mDrawableBottom) {
                     final int compoundPaddingLeft = getCompoundPaddingLeft();
                     final int compoundPaddingRight = getCompoundPaddingRight();
@@ -4852,11 +4857,18 @@
 
                     scrollX += compoundPaddingLeft + (hspace - drawables.mDrawableWidthBottom) / 2;
                     scrollY += (mBottom - mTop - mPaddingBottom - drawables.mDrawableSizeBottom);
+                    handled = true;
                 }
             }
 
-            invalidate(dirty.left + scrollX, dirty.top + scrollY,
-                    dirty.right + scrollX, dirty.bottom + scrollY);
+            if (handled) {
+                invalidate(dirty.left + scrollX, dirty.top + scrollY,
+                        dirty.right + scrollX, dirty.bottom + scrollY);
+            }
+        }
+
+        if (!handled) {
+            super.invalidateDrawable(drawable);
         }
     }
 
diff --git a/core/java/com/android/internal/app/IBatteryStats.aidl b/core/java/com/android/internal/app/IBatteryStats.aidl
index 1946d86..9a04760 100644
--- a/core/java/com/android/internal/app/IBatteryStats.aidl
+++ b/core/java/com/android/internal/app/IBatteryStats.aidl
@@ -35,10 +35,11 @@
 
     void noteEvent(int code, String name, int uid);
 
-    void noteStartWakelock(int uid, int pid, String name, int type);
+    void noteStartWakelock(int uid, int pid, String name, int type, boolean unimportantForLogging);
     void noteStopWakelock(int uid, int pid, String name, int type);
 
-    void noteStartWakelockFromSource(in WorkSource ws, int pid, String name, int type);
+    void noteStartWakelockFromSource(in WorkSource ws, int pid, String name, int type,
+            boolean unimportantForLogging);
     void noteStopWakelockFromSource(in WorkSource ws, int pid, String name, int type);
 
     void noteVibratorOn(int uid, long durationMillis);
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index 68c41fa..21d2e52 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -77,7 +77,7 @@
  */
 public final class BatteryStatsImpl extends BatteryStats {
     private static final String TAG = "BatteryStatsImpl";
-    private static final boolean DEBUG = false;
+    private static final boolean DEBUG = true;
     private static final boolean DEBUG_HISTORY = false;
     private static final boolean USE_OLD_HISTORY = false;   // for debugging.
 
@@ -87,7 +87,7 @@
     private static final int MAGIC = 0xBA757475; // 'BATSTATS'
 
     // Current on-disk Parcel version
-    private static final int VERSION = 75 + (USE_OLD_HISTORY ? 1000 : 0);
+    private static final int VERSION = 77 + (USE_OLD_HISTORY ? 1000 : 0);
 
     // Maximum number of items we will record in the history.
     private static final int MAX_HISTORY_ITEMS = 2000;
@@ -226,6 +226,9 @@
     long mRealtimeStart;
     long mLastRealtime;
 
+    int mWakeLockNesting;
+    boolean mWakeLockImportant;
+
     boolean mScreenOn;
     StopwatchTimer mScreenOnTimer;
 
@@ -1513,23 +1516,23 @@
     }
 
     // Part of initial delta int that specifies the time delta.
-    static final int DELTA_TIME_MASK = 0x1ffff;
-    static final int DELTA_TIME_LONG = 0x1ffff;   // The delta is a following long
-    static final int DELTA_TIME_INT = 0x1fffe;    // The delta is a following int
-    static final int DELTA_TIME_ABS = 0x1fffd;    // Following is an entire abs update.
-    // Part of initial delta int holding the command code.
-    static final int DELTA_CMD_MASK = 0x3;
-    static final int DELTA_CMD_SHIFT = 17;
+    static final int DELTA_TIME_MASK = 0xfffff;
+    static final int DELTA_TIME_LONG = 0xfffff;   // The delta is a following long
+    static final int DELTA_TIME_INT = 0xffffe;    // The delta is a following int
+    static final int DELTA_TIME_ABS = 0xffffd;    // Following is an entire abs update.
     // Flag in delta int: a new battery level int follows.
-    static final int DELTA_BATTERY_LEVEL_FLAG = 0x00080000;
+    static final int DELTA_BATTERY_LEVEL_FLAG   = 0x00400000;
     // Flag in delta int: a new full state and battery status int follows.
-    static final int DELTA_STATE_FLAG = 0x00100000;
+    static final int DELTA_STATE_FLAG           = 0x00800000;
     // Flag in delta int: contains a wakelock tag.
-    static final int DELTA_WAKELOCK_FLAG = 0x00200000;
-    static final int DELTA_STATE_MASK = 0xffc00000;
+    static final int DELTA_WAKELOCK_FLAG        = 0x01000000;
+    // Flag in delta int: contains an event description.
+    static final int DELTA_EVENT_FLAG           = 0x02000000;
+    // These upper bits are the frequently changing state bits.
+    static final int DELTA_STATE_MASK           = 0xfc000000;
 
     public void writeHistoryDelta(Parcel dest, HistoryItem cur, HistoryItem last) {
-        if (last == null || !last.isDeltaData() || !cur.isDeltaData()) {
+        if (last == null || cur.cmd != HistoryItem.CMD_UPDATE) {
             dest.writeInt(DELTA_TIME_ABS);
             cur.writeToParcel(dest, 0);
             return;
@@ -1547,9 +1550,7 @@
         } else {
             deltaTimeToken = (int)deltaTime;
         }
-        int firstToken = deltaTimeToken
-                | (cur.cmd<<DELTA_CMD_SHIFT)
-                | (cur.states&DELTA_STATE_MASK);
+        int firstToken = deltaTimeToken | (cur.states&DELTA_STATE_MASK);
         final int batteryLevelInt = buildBatteryLevelInt(cur);
         final boolean batteryLevelIntChanged = batteryLevelInt != lastBatteryLevelInt;
         if (batteryLevelIntChanged) {
@@ -1563,6 +1564,9 @@
         if (cur.wakelockTag != null) {
             firstToken |= DELTA_WAKELOCK_FLAG;
         }
+        if (cur.eventCode != HistoryItem.EVENT_NONE) {
+            firstToken |= DELTA_EVENT_FLAG;
+        }
         dest.writeInt(firstToken);
         if (DEBUG) Slog.i(TAG, "WRITE DELTA: firstToken=0x" + Integer.toHexString(firstToken)
                 + " deltaTime=" + deltaTime);
@@ -1599,7 +1603,7 @@
             if (DEBUG) Slog.i(TAG, "WRITE DELTA: wakelockTag=#" + cur.wakelockTag.poolIdx
                 + " " + cur.wakelockTag.uid + ":" + cur.wakelockTag.string);
         }
-        if (cur.cmd == HistoryItem.CMD_EVENT) {
+        if (cur.eventCode != HistoryItem.EVENT_NONE) {
             int index = writeHistoryTag(cur.eventTag);
             int codeAndIndex = (cur.eventCode&0xffff) | (index<<16);
             dest.writeInt(codeAndIndex);
@@ -1625,7 +1629,7 @@
     public void readHistoryDelta(Parcel src, HistoryItem cur) {
         int firstToken = src.readInt();
         int deltaTimeToken = firstToken&DELTA_TIME_MASK;
-        cur.cmd = (byte)((firstToken>>DELTA_CMD_SHIFT)&DELTA_CMD_MASK);
+        cur.cmd = HistoryItem.CMD_UPDATE;
         cur.numReadInts = 1;
         if (DEBUG) Slog.i(TAG, "READ DELTA: firstToken=0x" + Integer.toHexString(firstToken)
                 + " deltaTimeToken=" + deltaTimeToken);
@@ -1691,7 +1695,7 @@
             cur.wakelockTag = null;
         }
 
-        if (cur.cmd == HistoryItem.CMD_EVENT) {
+        if ((firstToken&DELTA_EVENT_FLAG) != 0) {
             cur.eventTag = cur.localEventTag;
             final int codeAndIndex = src.readInt();
             cur.eventCode = (codeAndIndex&0xffff);
@@ -1720,6 +1724,8 @@
         if (mHistoryBufferLastPos >= 0 && mHistoryLastWritten.cmd == HistoryItem.CMD_UPDATE
                 && timeDiff < 1000 && (diffStates&lastDiffStates) == 0
                 && (mHistoryLastWritten.wakelockTag == null || mHistoryCur.wakelockTag == null)
+                && (mHistoryLastWritten.eventCode == HistoryItem.EVENT_NONE
+                        || mHistoryCur.eventCode == HistoryItem.EVENT_NONE)
                 && mHistoryLastWritten.batteryLevel == mHistoryCur.batteryLevel
                 && mHistoryLastWritten.batteryStatus == mHistoryCur.batteryStatus
                 && mHistoryLastWritten.batteryHealth == mHistoryCur.batteryHealth
@@ -1742,6 +1748,14 @@
                 mHistoryCur.wakelockTag = mHistoryCur.localWakelockTag;
                 mHistoryCur.wakelockTag.setTo(mHistoryLastWritten.wakelockTag);
             }
+            // If the last written history had an event, we need to retain it.
+            // Note that the condition above made sure that we aren't in a case where
+            // both it and the current history item have an event.
+            if (mHistoryLastWritten.eventCode != HistoryItem.EVENT_NONE) {
+                mHistoryCur.eventCode = mHistoryLastWritten.eventCode;
+                mHistoryCur.eventTag = mHistoryCur.localEventTag;
+                mHistoryCur.eventTag.setTo(mHistoryLastWritten.eventTag);
+            }
             mHistoryLastWritten.setTo(mHistoryLastLastWritten);
         }
 
@@ -1772,26 +1786,18 @@
         addHistoryBufferLocked(curTime, HistoryItem.CMD_UPDATE);
     }
 
-    void addHistoryBufferLocked(long curTime, byte cmd) {
-        addHistoryBufferLocked(curTime, cmd, HistoryItem.EVENT_NONE, null, 0);
-    }
-
-    void addHistoryBufferEventLocked(long curTime, int eventCode, String eventName, int eventUid) {
-        addHistoryBufferLocked(curTime, HistoryItem.CMD_EVENT, eventCode, eventName, eventUid);
-    }
-
-    private void addHistoryBufferLocked(long curTime, byte cmd,
-            int eventCode, String eventName, int eventUid) {
+    private void addHistoryBufferLocked(long curTime, byte cmd) {
         if (mIteratingHistory) {
             throw new IllegalStateException("Can't do this while iterating history!");
         }
         mHistoryBufferLastPos = mHistoryBuffer.dataPosition();
         mHistoryLastLastWritten.setTo(mHistoryLastWritten);
-        mHistoryLastWritten.setTo(mHistoryBaseTime + curTime, cmd,
-                eventCode, eventUid, eventName, mHistoryCur);
+        mHistoryLastWritten.setTo(mHistoryBaseTime + curTime, cmd, mHistoryCur);
         writeHistoryDelta(mHistoryBuffer, mHistoryLastWritten, mHistoryLastLastWritten);
         mLastHistoryTime = curTime;
         mHistoryCur.wakelockTag = null;
+        mHistoryCur.eventCode = HistoryItem.EVENT_NONE;
+        mHistoryCur.eventTag = null;
         if (DEBUG_HISTORY) Slog.i(TAG, "Writing history buffer: was " + mHistoryBufferLastPos
                 + " now " + mHistoryBuffer.dataPosition()
                 + " size is now " + mHistoryBuffer.dataSize());
@@ -1829,8 +1835,7 @@
                 mHistoryLastEnd = null;
             } else {
                 mChangedStates |= mHistoryEnd.states^mHistoryCur.states;
-                mHistoryEnd.setTo(mHistoryEnd.time, HistoryItem.CMD_UPDATE,
-                        HistoryItem.EVENT_NONE, 0, null, mHistoryCur);
+                mHistoryEnd.setTo(mHistoryEnd.time, HistoryItem.CMD_UPDATE, mHistoryCur);
             }
             return;
         }
@@ -1860,7 +1865,11 @@
     }
 
     void addHistoryEventLocked(long curTime, int code, String name, int uid) {
-        addHistoryBufferEventLocked(curTime, code, name, uid);
+        mHistoryCur.eventCode = code;
+        mHistoryCur.eventTag = mHistoryCur.localEventTag;
+        mHistoryCur.eventTag.string = name;
+        mHistoryCur.eventTag.uid = uid;
+        addHistoryBufferLocked(curTime);
     }
 
     void addHistoryRecordLocked(long curTime, byte cmd) {
@@ -1870,8 +1879,7 @@
         } else {
             rec = new HistoryItem();
         }
-        rec.setTo(mHistoryBaseTime + curTime, cmd,
-                HistoryItem.EVENT_NONE, 0, null, mHistoryCur);
+        rec.setTo(mHistoryBaseTime + curTime, cmd, mHistoryCur);
 
         addHistoryRecordLocked(rec);
     }
@@ -1905,8 +1913,8 @@
         mHistoryBuffer.setDataSize(0);
         mHistoryBuffer.setDataPosition(0);
         mHistoryBuffer.setDataCapacity(MAX_HISTORY_BUFFER / 2);
-        mHistoryLastLastWritten.cmd = HistoryItem.CMD_NULL;
-        mHistoryLastWritten.cmd = HistoryItem.CMD_NULL;
+        mHistoryLastLastWritten.clear();
+        mHistoryLastWritten.clear();
         mHistoryTagPool.clear();
         mNextHistoryTagIdx = 0;
         mNumHistoryTagChars = 0;
@@ -1942,8 +1950,6 @@
         mBluetoothPingStart = -1;
     }
 
-    int mWakeLockNesting;
-
     public void addIsolatedUidLocked(int isolatedUid, int appUid) {
         mIsolatedUids.put(isolatedUid, appUid);
     }
@@ -1965,7 +1971,8 @@
         addHistoryEventLocked(SystemClock.elapsedRealtime(), code, name, uid);
     }
 
-    public void noteStartWakeLocked(int uid, int pid, String name, int type) {
+    public void noteStartWakeLocked(int uid, int pid, String name, int type,
+            boolean unimportantForLogging) {
         uid = mapUid(uid);
         if (type == WAKE_TYPE_PARTIAL) {
             // Only care about partial wake locks, since full wake locks
@@ -1977,7 +1984,18 @@
                 mHistoryCur.wakelockTag = mHistoryCur.localWakelockTag;
                 mHistoryCur.wakelockTag.string = name;
                 mHistoryCur.wakelockTag.uid = uid;
+                mWakeLockImportant = !unimportantForLogging;
                 addHistoryRecordLocked(SystemClock.elapsedRealtime());
+            } else if (!mWakeLockImportant && !unimportantForLogging) {
+                if (mHistoryLastWritten.wakelockTag != null) {
+                    // We'll try to update the last tag.
+                    mHistoryLastWritten.wakelockTag = null;
+                    mHistoryCur.wakelockTag = mHistoryCur.localWakelockTag;
+                    mHistoryCur.wakelockTag.string = name;
+                    mHistoryCur.wakelockTag.uid = uid;
+                    addHistoryRecordLocked(SystemClock.elapsedRealtime());
+                }
+                mWakeLockImportant = true;
             }
             mWakeLockNesting++;
         }
@@ -2010,10 +2028,11 @@
         }
     }
 
-    public void noteStartWakeFromSourceLocked(WorkSource ws, int pid, String name, int type) {
+    public void noteStartWakeFromSourceLocked(WorkSource ws, int pid, String name, int type,
+            boolean unimportantForLogging) {
         int N = ws.size();
         for (int i=0; i<N; i++) {
-            noteStartWakeLocked(ws.get(i), pid, name, type);
+            noteStartWakeLocked(ws.get(i), pid, name, type, unimportantForLogging);
         }
     }
 
@@ -2224,7 +2243,7 @@
 
             // Fake a wake lock, so we consider the device waked as long
             // as the screen is on.
-            noteStartWakeLocked(-1, -1, "screen", WAKE_TYPE_PARTIAL);
+            noteStartWakeLocked(-1, -1, "screen", WAKE_TYPE_PARTIAL, false);
             
             // Update discharge amounts.
             if (mOnBatteryInternal) {
@@ -4979,6 +4998,9 @@
     public boolean startIteratingHistoryLocked() {
         if (DEBUG_HISTORY) Slog.i(TAG, "ITERATING: buff size=" + mHistoryBuffer.dataSize()
                 + " pos=" + mHistoryBuffer.dataPosition());
+        if (mHistoryBuffer.dataSize() <= 0) {
+            return false;
+        }
         mHistoryBuffer.setDataPosition(0);
         mReadOverflow = false;
         mIteratingHistory = true;
@@ -4992,7 +5014,7 @@
             mReadHistoryUids[idx] = tag.uid;
             mReadHistoryChars += tag.string.length() + 1;
         }
-        return mHistoryBuffer.dataSize() > 0;
+        return true;
     }
 
     @Override
@@ -5075,8 +5097,37 @@
         mDischargeAmountScreenOff = 0;
         mDischargeAmountScreenOffSinceCharge = 0;
     }
-    
-    public void resetAllStatsLocked() {
+
+    public void resetAllStatsCmdLocked() {
+        resetAllStatsLocked();
+        long uptime = SystemClock.uptimeMillis() * 1000;
+        long mSecRealtime = SystemClock.elapsedRealtime();
+        long realtime = mSecRealtime * 1000;
+        mDischargeStartLevel = mHistoryCur.batteryLevel;
+        pullPendingStateUpdatesLocked();
+        addHistoryRecordLocked(mSecRealtime);
+        mDischargeCurrentLevel = mDischargeUnplugLevel = mHistoryCur.batteryLevel;
+        if ((mHistoryCur.states&HistoryItem.STATE_BATTERY_PLUGGED_FLAG) != 0) {
+            mTrackBatteryPastUptime = 0;
+            mTrackBatteryPastRealtime = 0;
+        } else {
+            mTrackBatteryUptimeStart = uptime;
+            mTrackBatteryRealtimeStart = realtime;
+            mUnpluggedBatteryUptime = getBatteryUptimeLocked(uptime);
+            mUnpluggedBatteryRealtime = getBatteryRealtimeLocked(realtime);
+            if (mScreenOn) {
+                mDischargeScreenOnUnplugLevel = mHistoryCur.batteryLevel;
+                mDischargeScreenOffUnplugLevel = 0;
+            } else {
+                mDischargeScreenOnUnplugLevel = 0;
+                mDischargeScreenOffUnplugLevel = mHistoryCur.batteryLevel;
+            }
+            mDischargeAmountScreenOn = 0;
+            mDischargeAmountScreenOff = 0;
+        }
+    }
+
+    private void resetAllStatsLocked() {
         mStartCount = 0;
         initTimes();
         mScreenOnTimer.reset(this, false);
@@ -5292,7 +5343,7 @@
             if (!onBattery && status == BatteryManager.BATTERY_STATUS_FULL) {
                 // We don't record history while we are plugged in and fully charged.
                 // The next time we are unplugged, history will be cleared.
-                mRecordingHistory = false;
+                mRecordingHistory = DEBUG;
             }
         }
     }
diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml
index b550545..49d13f2 100644
--- a/core/res/res/values-af/strings.xml
+++ b/core/res/res/values-af/strings.xml
@@ -423,6 +423,8 @@
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Laat die program toe om enige geïnstalleer mediadekodeerder te gebruik om te kan dekodeer vir terugspeel."</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"bestuur vertroude eiebewyse"</string>
     <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Laat die program CA-sertifikate as vertroude eiebewyse installeer en deïnstalleer."</string>
+    <string name="permlab_bindIdleService" msgid="7521398788076342815">"bind aan ledige dienste"</string>
+    <string name="permdesc_bindIdleService" msgid="3062157929989572890">"Laat die program met programgedefinieerde ledige dienste omgaan."</string>
     <string name="permlab_diagnostic" msgid="8076743953908000342">"lees/skryf na bronne wat diag besit"</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"Laat die program toe om na enige hulpbron wat deur die diag-groep besit word, te skryf, byvoorbeeld lêers in /dev. Dit kan potensieel stelselstabiliteit en sekuriteit affekteer. Dit moet NET gebruik word vir hardewarespesifieke diagnose deur die vervaardiger of operateur."</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"aktiveer of deaktiveer programkomponente"</string>
diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml
index 861ae68..c8daf99 100644
--- a/core/res/res/values-am/strings.xml
+++ b/core/res/res/values-am/strings.xml
@@ -423,6 +423,8 @@
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"ለመልሰህ አጫውት ፍታን በማንኛውም የተጫኑ በማህደረ መረጃ ዲኮደር ለመጠቀም  ለመተግበሪያ ይፈቅዳል።"</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"የታመኑ ምስክርነቶችን ያስተዳድሩ"</string>
     <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"መተግበሪያው CA የምስክር ወረቀቶችን እንደሚታመኑ ምስክርነቶች አንዲጭን እና እንዲያራግፍ ይፍቀዱ።"</string>
+    <string name="permlab_bindIdleService" msgid="7521398788076342815">"ከስራ ፈት አገልግሎቶች ጋር ይሰሩ"</string>
+    <string name="permdesc_bindIdleService" msgid="3062157929989572890">"መተግበሪያው በመተግበሪያ ከተገለጹ ስራ ፈት አገልግሎቶች ጋር እንዲስተጋብር ያስችላል።"</string>
     <string name="permlab_diagnostic" msgid="8076743953908000342">"በdiag ባለቤትነት ያሉ ንብረቶችን አንብብ/ፃፍ"</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"በዲያግ ቡድን ባለቤትነት ወደ አለ ማንኛውም ንብረት ለምሳሌ በ/dev ያሉ ፋይሎች ለማንበብ እና ለመፃፍ ለመተግበሪያው ይፈቅዳሉ። ይህ በመሰረቱ የስርዓት መረጋጋትን እና ደህንነትን ሊጎዳ ይችላል። ይህ ውስን የሀርድዌር-ተኮር ዲያግኖስቲክስ በአምራቹ ወይም ከዋኙ ብቻ መሆን አለበት።"</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"የመተግበሪያ ምንዝሮችን አንቃ ወይም አቦዝን"</string>
diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
index e20b7b4..fca2a18a 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -423,6 +423,8 @@
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"السماح للتطبيق باستخدام أي برنامج فك تشفير وسائط مثبت لفك التشفير من أجل التشغيل."</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"إدارة بيانات الاعتماد الموثوقة"</string>
     <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"‏السماح للتطبيق بتثبيت شهادات CA وإلغاء تثبيتها باعتبارها بيانات اعتماد محل ثقة."</string>
+    <string name="permlab_bindIdleService" msgid="7521398788076342815">"الالتزام بالخدمات الخاملة"</string>
+    <string name="permdesc_bindIdleService" msgid="3062157929989572890">"للسماح للتطبيق بالتفاعل مع الخدمات الخاملة التي يحددها التطبيق."</string>
     <string name="permlab_diagnostic" msgid="8076743953908000342">"قراءة/كتابة إلى الموارد المملوكة بواسطة التشخيص"</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"‏للسماح للتطبيق بالقراءة والكتابة إلى أي مورد مملوك بواسطة مجموعة التشخيصات؛ على سبيل المثال، الملفات في /dev. من المحتمل أن يؤثر ذلك في استقرار النظام وأمانه. يجب ألا يستخدم ذلك سوى للتشخيصات الخاصة بالنظام من قِبل المصنِّع أو المشغِّل."</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"تمكين مكونات التطبيق أو تعطيلها"</string>
diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml
index 1dbb050..064a2ac 100644
--- a/core/res/res/values-bg/strings.xml
+++ b/core/res/res/values-bg/strings.xml
@@ -423,6 +423,8 @@
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Разрешава на приложението да използва всеки инсталиран медиен декодер с цел декодиране за възпроизвеждане."</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"управление на надеждните идентификационни данни"</string>
     <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Разрешава на приложението да инсталира и деинсталира сертификати от сертифициращи органи като надеждни идентификационни данни."</string>
+    <string name="permlab_bindIdleService" msgid="7521398788076342815">"обвързване с услуги при неактивност"</string>
+    <string name="permdesc_bindIdleService" msgid="3062157929989572890">"Разрешава на приложението да взаимодейства с дефинирани от приложения услуги при неактивност."</string>
     <string name="permlab_diagnostic" msgid="8076743953908000342">"четене/запис в ресурси, притежавани от diag"</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"Разрешава на приложението да чете и записва във всеки ресурс, притежаван от групата diag, например файловете в /dev. Това потенциално може да засегне стабилността и сигурността на системата. То трябва да се използва САМО за диагностика, конкретно за хардуера, от страна на производителя или оператора."</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"активиране или деактивиране на компоненти на приложенията"</string>
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index 8eadf2c..9b8faaf 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -423,6 +423,8 @@
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Permet que l\'aplicació utilitzi qualsevol descodificador de mitjans instal·lat per descodificar per a la reproducció."</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"gestiona les credencials de confiança"</string>
     <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Permet que l\'aplicació instal·li i desinstal·li certificats de CA com a credencials de confiança."</string>
+    <string name="permlab_bindIdleService" msgid="7521398788076342815">"vincula als serveis inactius"</string>
+    <string name="permdesc_bindIdleService" msgid="3062157929989572890">"Permet que l\'aplicació interaccioni amb els serveis inactius definits per l\'aplicació."</string>
     <string name="permlab_diagnostic" msgid="8076743953908000342">"llegir/escriure recursos propietat de diag"</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"Permet que l\'aplicació llegeixi i escrigui a qualsevol recurs propietat del grup diag; per exemple, els fitxers de /dev. Això podria afectar l\'estabilitat i la seguretat del sistema. NOMÉS l\'hauria d\'utilitzar el fabricant o l\'operador per a diagnòstics específics de maquinari."</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"activa o desactiva els components de l\'aplicació"</string>
diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
index 8cf6d8d..3163607 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -423,6 +423,8 @@
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Umožňuje aplikaci používat libovolný nainstalovaný dekodér médií k dekódování při přehrávání."</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"správa důvěryhodných identifikačních údajů"</string>
     <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Umožňuje aplikaci instalovat a odinstalovat certifikáty CA jako důvěryhodné identifikační údaje."</string>
+    <string name="permlab_bindIdleService" msgid="7521398788076342815">"napojit se na nečinné služby"</string>
+    <string name="permdesc_bindIdleService" msgid="3062157929989572890">"Umožňuje aplikaci ovlivňovat nečinné služby definované aplikacemi."</string>
     <string name="permlab_diagnostic" msgid="8076743953908000342">"čtení nebo zápis do prostředků funkce diag"</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"Umožňuje aplikaci číst libovolné prostředky ve skupině diag, např. soubory ve složce /dev, a zapisovat do nich. Může dojít k ovlivnění stability a bezpečnosti systému. Toto nastavení by měl používat POUZE výrobce či operátor pro diagnostiku hardwaru."</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"aktivace či deaktivace komponent aplikací"</string>
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index 565578f..6420fdd 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -423,6 +423,8 @@
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Tillader, at appen bruger enhver installeret medieafkoder til at afkode til afspilning."</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"administrer pålidelige logonoplysninger"</string>
     <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Tillader, at appen installerer og afinstallerer CA-certifikater som pålidelige loginoplysninger."</string>
+    <string name="permlab_bindIdleService" msgid="7521398788076342815">"knyt til dvaletjenester"</string>
+    <string name="permdesc_bindIdleService" msgid="3062157929989572890">"Tillader, at appen interagerer med dvaletjenester, som defineres af applikationen."</string>
     <string name="permlab_diagnostic" msgid="8076743953908000342">"læs/skriv til ressourcer ejet af diag"</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"Tillader, at appen kan læse og skrive til alle ressourcer, der ejes af diag-gruppen,  f.eks. filer i /dev. Dette kan muligvis påvirke systemets stabilitet og sikkerhed. Dette bør KUN bruges til hardwarespecifik diagnosticering, som foretages af producenten eller udbyderen."</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"aktivere eller deaktivere appkomponenter"</string>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index b244fd9..078aa90 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -423,6 +423,8 @@
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Ermöglicht der App, alle installierten Mediendecodierer zur Wiedergabe zu verwenden."</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"Vertrauenswürdige Anmeldedaten verwalten"</string>
     <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Ermöglicht der App, CA-Zertifikate als vertrauenswürdige Anmeldedaten zu installieren und zu deinstallieren."</string>
+    <string name="permlab_bindIdleService" msgid="7521398788076342815">"An inaktive Dienste binden"</string>
+    <string name="permdesc_bindIdleService" msgid="3062157929989572890">"Ermöglicht der App, mit anwendungsdefinierten inaktiven Diensten zu interagieren"</string>
     <string name="permlab_diagnostic" msgid="8076743953908000342">"Lese-/Schreibberechtigung für zu Diagnosegruppe gehörige Elemente"</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"Ermöglicht der App, alle Elemente in der Diagnosegruppe zu lesen und zu bearbeiten, etwa Dateien in \"/dev\". Dies könnte eine potenzielle Gefährdung für die Stabilität und Sicherheit des Systems darstellen und sollte NUR für hardwarespezifische Diagnosen des Herstellers oder Mobilfunkanbieters verwendet werden."</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"App-Komponenten aktivieren oder deaktivieren"</string>
diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml
index b7050dc..dac6757 100644
--- a/core/res/res/values-el/strings.xml
+++ b/core/res/res/values-el/strings.xml
@@ -423,6 +423,8 @@
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Επιτρέπει στην εφαρμογή τη χρήση οποιουδήποτε εγκατεστημένου αποκωδικοποιητή μέσων για αναπαραγωγή."</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"διαχείριση αξιόπιστων διαπιστευτηρίων"</string>
     <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Επιτρέπει στην εφαρμογή την εγκατάσταση και την απεγκατάσταση πιστοποιητικών CA ως αξιόπιστων διαπιστευτηρίων."</string>
+    <string name="permlab_bindIdleService" msgid="7521398788076342815">"σύνδεση σε υπηρεσίες αδράνειας"</string>
+    <string name="permdesc_bindIdleService" msgid="3062157929989572890">"Επιτρέπει στην εφαρμογή να αλληλεπιδρά με αδρανείς υπηρεσίες που καθορίζονται από την εφαρμογή."</string>
     <string name="permlab_diagnostic" msgid="8076743953908000342">"ανάγνωση/εγγραφή σε πόρους που ανήκουν στο διαγνωστικό"</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"Επιτρέπει στην εφαρμογή την ανάγνωση και την εγγραφή σε οποιονδήποτε πόρο που ανήκει στην ομάδα διαγνωστικού (π.χ. αρχεία στον κατάλογο /dev). Αυτό ενδέχεται να επηρεάσει την σταθερότητα και την ασφάλεια του συστήματος. Θα πρέπει να χρησιμοποιείται ΜΟΝΟ για διαγνωστικά υλικού από τον κατασκευαστή ή τον χειριστή."</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"ενεργοποίηση ή απενεργοποίηση στοιχείων εφαρμογής"</string>
diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml
index fdaae8b..50089cb 100644
--- a/core/res/res/values-en-rGB/strings.xml
+++ b/core/res/res/values-en-rGB/strings.xml
@@ -423,6 +423,8 @@
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Allows the app to use any installed media decoder to decode for playback."</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"manage trusted credentials"</string>
     <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Allows the app to install and uninstall CA certificates as trusted credentials."</string>
+    <string name="permlab_bindIdleService" msgid="7521398788076342815">"bind to idle services"</string>
+    <string name="permdesc_bindIdleService" msgid="3062157929989572890">"Allows the app to interact with application-defined idle services."</string>
     <string name="permlab_diagnostic" msgid="8076743953908000342">"read/write to resources owned by diag"</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"Allows the app to read and write to any resource owned by the diag group; for example, files in /dev. This could potentially affect system stability and security. This should ONLY be used for hardware-specific diagnostics by the manufacturer or operator."</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"enable or disable app components"</string>
diff --git a/core/res/res/values-en-rIN/strings.xml b/core/res/res/values-en-rIN/strings.xml
index fdaae8b..50089cb 100644
--- a/core/res/res/values-en-rIN/strings.xml
+++ b/core/res/res/values-en-rIN/strings.xml
@@ -423,6 +423,8 @@
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Allows the app to use any installed media decoder to decode for playback."</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"manage trusted credentials"</string>
     <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Allows the app to install and uninstall CA certificates as trusted credentials."</string>
+    <string name="permlab_bindIdleService" msgid="7521398788076342815">"bind to idle services"</string>
+    <string name="permdesc_bindIdleService" msgid="3062157929989572890">"Allows the app to interact with application-defined idle services."</string>
     <string name="permlab_diagnostic" msgid="8076743953908000342">"read/write to resources owned by diag"</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"Allows the app to read and write to any resource owned by the diag group; for example, files in /dev. This could potentially affect system stability and security. This should ONLY be used for hardware-specific diagnostics by the manufacturer or operator."</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"enable or disable app components"</string>
diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml
index 1e94bd9..5c1eee4 100644
--- a/core/res/res/values-es-rUS/strings.xml
+++ b/core/res/res/values-es-rUS/strings.xml
@@ -423,6 +423,8 @@
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Permite que la aplicación use cualquier decodificador de archivos multimedia instalado para la reproducción."</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"administrar credenciales de confianza"</string>
     <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Permite que la aplicación instale y desinstale certificados de CA como credenciales de confianza."</string>
+    <string name="permlab_bindIdleService" msgid="7521398788076342815">"vincular con servicios inactivos"</string>
+    <string name="permdesc_bindIdleService" msgid="3062157929989572890">"Permite que la aplicación interaccione con servicios inactivos definidos por la aplicación."</string>
     <string name="permlab_diagnostic" msgid="8076743953908000342">"leer y escribir a recursos dentro del grupo de diagnóstico"</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"Permite que la aplicación lea y escriba en cualquier recurso propiedad del grupo de diagnóstico como, por ejemplo, archivos in/dev. Este permiso podría afectar la seguridad y estabilidad del sistema. SOLO se debe utilizar para diagnósticos específicos de hardware realizados por el fabricante o el operador."</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"activar o desactivar componentes de la aplicación"</string>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index 75f1c6d..906df2c 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -423,6 +423,8 @@
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Permite que la aplicación use cualquier decodificador de archivos multimedia instalado para la reproducción."</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"administrar credenciales de confianza"</string>
     <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Permite que la aplicación instale y desinstale certificados de CA como credenciales de confianza."</string>
+    <string name="permlab_bindIdleService" msgid="7521398788076342815">"ocultar para servicios inactivos"</string>
+    <string name="permdesc_bindIdleService" msgid="3062157929989572890">"Permite que la aplicación interactúe con servicios inactivos definidos por la aplicación."</string>
     <string name="permlab_diagnostic" msgid="8076743953908000342">"leer/escribir en los recursos propiedad del grupo de diagnóstico"</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"Permite que la aplicación consulte y escriba en cualquier recurso del grupo de diagnóstico como, por ejemplo, archivos en /dev. Este permiso podría afectar a la seguridad y estabilidad del sistema. SOLO se debe usar para diagnósticos específicos de hardware realizados por el fabricante o el operador."</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"habilitar o inhabilitar componentes de la aplicación"</string>
@@ -1526,7 +1528,7 @@
     <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"Desbloqueando tarjeta SIM…"</string>
     <string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"Código PIN incorrecto"</string>
     <string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"Introduce un código PIN con una longitud comprendida entre cuatro y ocho dígitos."</string>
-    <string name="kg_invalid_sim_puk_hint" msgid="6025069204539532000">"El código PUK debe tener ocho números."</string>
+    <string name="kg_invalid_sim_puk_hint" msgid="6025069204539532000">"El código PUK debe tener 8 números."</string>
     <string name="kg_invalid_puk" msgid="3638289409676051243">"Vuelve a introducir el código PUK correcto. Si introduces un código incorrecto varias veces, se inhabilitará la tarjeta SIM."</string>
     <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"Los códigos PIN no coinciden."</string>
     <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Demasiados intentos incorrectos de crear el patrón"</string>
diff --git a/core/res/res/values-et-rEE/strings.xml b/core/res/res/values-et-rEE/strings.xml
index dcf38ac..0fb2a12 100644
--- a/core/res/res/values-et-rEE/strings.xml
+++ b/core/res/res/values-et-rEE/strings.xml
@@ -423,6 +423,8 @@
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Võimaldab rakendusel taasesituseks kasutada mis tahes installitud meediumidekooderit."</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"usaldusväärsete mandaatide haldamine"</string>
     <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Lubab rakendusel installida ja desinstallida usaldusväärsete mandaatidena CA-sertifikaate."</string>
+    <string name="permlab_bindIdleService" msgid="7521398788076342815">"sidumine tegevusetute teenustega"</string>
+    <string name="permdesc_bindIdleService" msgid="3062157929989572890">"Lubab rakendusel suhelda rakenduse määratud tegevusetute teenustega."</string>
     <string name="permlab_diagnostic" msgid="8076743953908000342">"loe/kirjuta valija allikaid"</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"Võimaldab rakendusel lugeda valimisrühma mis tahes ressurssi ja sellesse kirjutada (näiteks kaustas /dev olevad failid). See võib mõjutada süsteemi stabiilsust ja turvet. Seda tohiks kasutada tootja või operaator AINULT riistvaraspetsiifiliseks diagnostikaks."</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"Rakenduse komponentide lubamine või keelamine"</string>
@@ -1526,7 +1528,7 @@
     <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"SIM-kaardi avamine ..."</string>
     <string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"Vale PIN-kood."</string>
     <string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"Sisestage 4–8-numbriline PIN-kood."</string>
-    <string name="kg_invalid_sim_puk_hint" msgid="6025069204539532000">"PUK-kood peab sisaldama 8 numbrit."</string>
+    <string name="kg_invalid_sim_puk_hint" msgid="6025069204539532000">"PUK-kood peab koosnema 8 numbrist."</string>
     <string name="kg_invalid_puk" msgid="3638289409676051243">"Sisestage uuesti õige PUK-kood. Korduvkatsete korral keelatakse SIM jäädavalt."</string>
     <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"PIN-koodid ei ole vastavuses"</string>
     <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Liiga palju mustrikatseid"</string>
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index 465d1e2..57af25e 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -423,6 +423,8 @@
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"‏اجازه می‎دهد برنامه از هر رمزگشای رسانه نصب شده‌ای استفاده کند تا برای پخش رمزگشایی شود."</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"مدیریت اطلاعات کاربری مورد اعتماد"</string>
     <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"‏به برنامه امکان می‌دهد گواهینامه‌های CA را به عنوان اطلاعات کاربری مورد اعتماد نصب یا حذف نصب کند."</string>
+    <string name="permlab_bindIdleService" msgid="7521398788076342815">"اتصال با سرویس‌های غیرفعال"</string>
+    <string name="permdesc_bindIdleService" msgid="3062157929989572890">"به برنامه اجازه می‌دهد با سرویس‌های غیرفعال تعریف شده توسط برنامه تعامل داشته باشد."</string>
     <string name="permlab_diagnostic" msgid="8076743953908000342">"خواندن/نوشتن منابع متعلق به تشخیص"</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"‏به برنامه اجازه می‌دهد هر منبعی را که متعلق به گروه تشخیص است بخواند و در آن بنویسد؛ به‌عنوان مثال، فایل‌های /dev. این امر به‌صورت بالقوه می‌تواند بر پایدار بودن و امنیت سیستم تأثیر بگذارد. این تنها باید برای تشخیص‎‌های مختص سخت‌افزار توسط تولیدکننده یا اپراتور استفاده شود."</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"فعال یا غیر فعال کردن اجزای برنامه"</string>
diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml
index 5f1ecbd..c5bcda7 100644
--- a/core/res/res/values-fi/strings.xml
+++ b/core/res/res/values-fi/strings.xml
@@ -423,6 +423,10 @@
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Sallii sovelluksen käyttää mitä tahansa asennettua tietovälineen koodin purkajaa toistoa varten."</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"hallinnoi luotettavia varmenteita"</string>
     <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Antaa sovellukselle luvan asentaa ja poistaa luotettavia CA-varmenteita."</string>
+    <!-- no translation found for permlab_bindIdleService (7521398788076342815) -->
+    <skip />
+    <!-- no translation found for permdesc_bindIdleService (3062157929989572890) -->
+    <skip />
     <string name="permlab_diagnostic" msgid="8076743953908000342">"lue diag:in omistamia resursseja / kirjoita resursseihin"</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"Antaa sovelluksen lukea ja kirjoittaa diag-ryhmän omistamiin resursseihin, esimerkiksi /dev-hakemistossa oleviin tiedostoihin. Tämä voi vaikuttaa järjestelmän vakauteen ja turvallisuuteen. Tämä lupa tulee myöntää VAIN valmistajan tai operaattorin laitteistotesteille."</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"sovelluskomponenttien ottaminen käyttöön tai pois käytöstä"</string>
diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml
index 2375194..5b866c6 100644
--- a/core/res/res/values-fr-rCA/strings.xml
+++ b/core/res/res/values-fr-rCA/strings.xml
@@ -423,6 +423,8 @@
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Permet à une application d\'utiliser n\'importe quel décodeur installé pour lire les fichiers multimédias."</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"gérer les certificats de confiance"</string>
     <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Permet à l\'application d\'installer et de désinstaller les certificats CA en tant que certificats de confiance."</string>
+    <string name="permlab_bindIdleService" msgid="7521398788076342815">"lier aux services inactifs"</string>
+    <string name="permdesc_bindIdleService" msgid="3062157929989572890">"Permet à l\'application d\'interagir avec les services inactifs définis par l\'application."</string>
     <string name="permlab_diagnostic" msgid="8076743953908000342">"lire ou modifier les ressources appartenant au groupe de diagnostics"</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"Permet à l\'application d\'obtenir des droits en lecture et en écriture pour toute ressource appartenant au groupe de diagnostics (par exemple, les fichiers du répertoire /dev). Cela peut affecter la stabilité et la sécurité du système. Cette fonctionnalité est UNIQUEMENT réservée aux diagnostics matériels effectués par le fabricant ou le fournisseur de services."</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"activer ou désactiver les composants d\'une application"</string>
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index 685ed04..4ea32f4 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -423,6 +423,8 @@
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Permet à une application d\'utiliser n\'importe quel décodeur installé pour lire les fichiers multimédias."</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"gérer les certificats de confiance"</string>
     <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Permet à l\'application d\'installer et de désinstaller les certificats CA en tant que certificats de confiance."</string>
+    <string name="permlab_bindIdleService" msgid="7521398788076342815">"associer aux services d\'inactivité"</string>
+    <string name="permdesc_bindIdleService" msgid="3062157929989572890">"Permettre à l\'application d\'interagir avec les services d\'inactivité définis par des applications"</string>
     <string name="permlab_diagnostic" msgid="8076743953908000342">"Lecture/écriture dans les ressources appartenant aux diagnostics"</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"Permet à l\'application d\'obtenir des droits en lecture/écriture concernant toute ressource appartenant au groupe de diagnostics (par exemple, les fichiers du répertoire /dev). Ceci peut affecter la stabilité et la sécurité du système. Cette fonctionnalité est UNIQUEMENT réservée aux diagnostics matériels effectués par le fabricant ou l\'opérateur."</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"activer ou désactiver les composants de l\'application"</string>
diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml
index 264a0e5..15ffe52 100644
--- a/core/res/res/values-hi/strings.xml
+++ b/core/res/res/values-hi/strings.xml
@@ -423,6 +423,8 @@
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"ऐप्स  को प्लेबैक डीकोड करने के लिए किसी भी इंस्टॉल किए गए डीकोडर का उपयोग करने देता है."</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"विश्वसनीय क्रेडेंशियल प्रबंधित करें"</string>
     <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"ऐप्स  को CA प्रमाणपत्रों को विश्वसनीय क्रेडेंशियल के रूप में इंस्टॉल और अनइंस्टॉल करने दें"</string>
+    <string name="permlab_bindIdleService" msgid="7521398788076342815">"निष्क्रिय सेवाओं से आबद्ध करें"</string>
+    <string name="permdesc_bindIdleService" msgid="3062157929989572890">"ऐप्स को एप्लिकेशन-परिभाषित निष्क्रिय सेवाओं के साथ सहभागिता करने की अनुमति देता है."</string>
     <string name="permlab_diagnostic" msgid="8076743953908000342">"निदान के स्‍वामित्‍व वाले संसाधनों को पढ़ें/लिखें"</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"ऐप्स को diag समूह के स्‍वामित्‍व वाले किसी संसाधन को पढ़ने और उसमें लिखने देता है; उदाहरण के लिए, /dev की फ़ाइलें. यह सिस्‍टम की स्‍थिरता और सुरक्षा को संभावित रूप से प्रभावित कर सकता है. इसका उपयोग निर्माता या ऑपरेटर द्वारा केवल हार्डवेयर-विशिष्ट निदान के लिए किया जाना चाहिए."</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"ऐप्स घटकों को सक्षम या अक्षम करें"</string>
diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml
index 0880d2f..cc52a10 100644
--- a/core/res/res/values-hr/strings.xml
+++ b/core/res/res/values-hr/strings.xml
@@ -423,6 +423,8 @@
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Aplikaciji omogućuje korištenje bilo kojim instaliranim dekoderom medija za dekodiranje radi reprodukcije."</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"upravljanje pouzdanim vjerodajnicama"</string>
     <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Omogućuje aplikaciji instaliranje i deinstaliranje CA certifikata kao pouzdanih vjerodajnica."</string>
+    <string name="permlab_bindIdleService" msgid="7521398788076342815">"veži uz usluge u mirovanju"</string>
+    <string name="permdesc_bindIdleService" msgid="3062157929989572890">"Omogućuje aplikaciji interakciju s uslugama u mirovanju definiranim aplikacijom."</string>
     <string name="permlab_diagnostic" msgid="8076743953908000342">"pisanje/čitanje u resursima čije je vlasnik dijagnostika"</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"Aplikaciji omogućuje čitanje i pisanje na bilo koji resurs u vlasništvu dijag. grupe; na primjer, datoteke u sustavu /dev. To bi moglo utjecati na stabilnost sustava i sigurnost. Dozvolu bi trebao upotrebljavati proizvođač ili operater SAMO za dijagnostiku koja se odnosi na hardver."</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"omogućavanje ili onemogućavanje komponenti aplikacije"</string>
diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml
index 5eadb47..60e026f1 100644
--- a/core/res/res/values-hu/strings.xml
+++ b/core/res/res/values-hu/strings.xml
@@ -423,6 +423,8 @@
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Lehetővé teszi egy alkalmazás számára bármely telepített médiadekóder használatát a lejátszás dekódolásához."</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"megbízható tanúsítványok kezelése"</string>
     <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Lehetővé teszi az alkalmazás számára a CA tanúsítványok telepítését és eltávolítását."</string>
+    <string name="permlab_bindIdleService" msgid="7521398788076342815">"csatolás tétlen szolgáltatásokhoz"</string>
+    <string name="permdesc_bindIdleService" msgid="3062157929989572890">"Engedélyezi az alkalmazás kommunikációját az alkalmazás által meghatározott, tétlen szolgáltatásokkal."</string>
     <string name="permlab_diagnostic" msgid="8076743953908000342">"a diag tulajdonában lévő erőforrások olvasása és írása"</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"Lehetővé teszi egy alkalmazás számára, hogy olvassa és írja a diagnosztikai csoport minden erőforrását, például a /dev könyvtárban lévő fájlokat. Ez potenciálisan befolyásolhatja a rendszer stabilitását és biztonságát, ezért CSAK a gyártó vagy a szolgáltató használhatja hardverspecifikus diagnosztizálásra."</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"alkalmazáskomponensek be- és kikapcsolása"</string>
diff --git a/core/res/res/values-hy-rAM/strings.xml b/core/res/res/values-hy-rAM/strings.xml
index 1a5228d..534c570 100644
--- a/core/res/res/values-hy-rAM/strings.xml
+++ b/core/res/res/values-hy-rAM/strings.xml
@@ -423,6 +423,8 @@
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Թույլ է տալիս հավելվածին օգտագործել ցանկացած տեղադրված մեդիա վերծանիչ` նվագարկումը ապակոդավորելու համար:"</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"կառավարել վստահելի հավաստագրերը"</string>
     <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Թույլատրում է հավելվածին տեղադրել և ապատեղադրել CA վկայագրերը՝ որպես վստահելի հավաստագրեր:"</string>
+    <string name="permlab_bindIdleService" msgid="7521398788076342815">"կապակցել ոչ ակտիվ ծառայությունների հետ"</string>
+    <string name="permdesc_bindIdleService" msgid="3062157929989572890">"Թույլ է տալիս ծրագրին փոխգործակցել ոչ ակտիվ ծառայությունների հետ, որոնցում ծրագրերը մեծ դեր ունեն:"</string>
     <string name="permlab_diagnostic" msgid="8076743953908000342">"կարդալ կամ գրել ախտորոշիչին պատկանող ռեսուրսները"</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"Թույլ է տալիս հավելվածին կարդալ և գրել ախտորոշիչ խմբին պատկանող ցանկացած ռեսուրսում, ինչպես օրինակ ֆայլերը /dev-ում: Դա կարող է ազդել համակարգի կայունության և անվտանգության վրա: Սա պետք է օգտագործել միայն արտադրողի կամ օպերատորի կողմից սարքին հատուկ ախտորոշման համար:"</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"միացնել կամ անջատել հավելվածի բաղադրիչները"</string>
diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml
index 0e1d5b6..c7a8d36 100644
--- a/core/res/res/values-in/strings.xml
+++ b/core/res/res/values-in/strings.xml
@@ -423,6 +423,8 @@
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Mengizinkan apl menggunakan pengawasandi media apa pun yang terpasang guna mengawasandikan media untuk diputar."</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"kelola kredensial tepercaya"</string>
     <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Izinkan aplikasi memasang dan mencopot pemasangan sertifikat CA sebagai kredensial tepercaya."</string>
+    <string name="permlab_bindIdleService" msgid="7521398788076342815">"mengikat ke layanan nganggur"</string>
+    <string name="permdesc_bindIdleService" msgid="3062157929989572890">"Memungkinkan aplikasi berinteraksi dengan layanan nganggur yang ditetapkan oleh aplikasi."</string>
     <string name="permlab_diagnostic" msgid="8076743953908000342">"baca/tulis ke sumber daya yang dimiliki oleh diag"</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"Mengizinkan apl membaca dan menulis ke sumber daya apa pun yang dimiliki oleh grup diag; misalnya, file dalam /dev. Izin ini berpotensi memengaruhi kestabilan dan keamanan sistem. Sebaiknya ini HANYA digunakan untuk diagnosis khusus perangkat keras oleh pabrikan atau operator."</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"mengaktifkan atau menonaktifkan komponen apl"</string>
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index 75c887ef..56ec024 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -423,6 +423,8 @@
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Consente all\'applicazione di utilizzare qualsiasi decoder multimediale installato per la decodifica ai fini della riproduzione."</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"gestione di credenziali attendibili"</string>
     <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Consente all\'app di installare e disinstallare certificati CA come credenziali attendibili."</string>
+    <string name="permlab_bindIdleService" msgid="7521398788076342815">"associazione a servizi non disponibili"</string>
+    <string name="permdesc_bindIdleService" msgid="3062157929989572890">"Consente all\'app di interagire con i servizi non disponibili definiti dall\'applicazione."</string>
     <string name="permlab_diagnostic" msgid="8076743953908000342">"lettura/scrittura risorse di proprietà di diag"</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"Consente all\'applicazione di leggere le risorse del gruppo diag e scrivere in esse, ad esempio i file in /dev. Ciò potrebbe influire su stabilità e sicurezza del sistema. Dovrebbe essere utilizzata SOLTANTO per diagnostiche specifiche dell\'hardware effettuate dal produttore o dall\'operatore."</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"attivazione/disattivazione componenti applicazioni"</string>
diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml
index 008d078..8bd1b0c 100644
--- a/core/res/res/values-iw/strings.xml
+++ b/core/res/res/values-iw/strings.xml
@@ -423,6 +423,8 @@
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"הרשאה זו מאפשרת לאפליקציה להשתמש בכל מפענח מדיה מותקן כדי לבצע פענוח להשמעה."</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"ניהול פרטי כניסה מהימנים"</string>
     <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"‏מאפשרת לאפליקציה להתקין ולהסיר אישורי CA כפרטי כניסה מהימנים."</string>
+    <string name="permlab_bindIdleService" msgid="7521398788076342815">"אגד עם שירותים במצב לא פעיל"</string>
+    <string name="permdesc_bindIdleService" msgid="3062157929989572890">"מאפשר אינטראקטיביות של האפליקציה עם שירותים המוגדרים על ידי האפליקציה כבמצב לא פעיל."</string>
     <string name="permlab_diagnostic" msgid="8076743953908000342">"‏קרא/כתוב במשאבים בבעלות diag"</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"‏מאפשר לאפליקציה לקרוא ולכתוב בכל משאב שבבעלות קבוצת ה-diag; לדוגמה, קבצים ב-‎/dev. פעולה זו עשויה להשפיע על היציבות והאבטחה של המערכת. אפשרות זו צריכה לשמש רק את היצרן או המפעיל, לצורך אבחונים ספציפיים לחומרה."</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"הפעלה או השבתה של רכיבי אפליקציות"</string>
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index 4a994b2..209c7fd 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -423,6 +423,8 @@
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"インストール済みのメディアデコーダーを使用して再生用にデコードすることをアプリに許可します。"</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"信頼できる認証情報の管理"</string>
     <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"CA証明書を信頼できる認証情報としてインストールしたりアンインストールしたりすることをアプリに許可します。"</string>
+    <string name="permlab_bindIdleService" msgid="7521398788076342815">"アイドルサービスへのバインディング"</string>
+    <string name="permdesc_bindIdleService" msgid="3062157929989572890">"アプリ定義のアイドルサービスとの通信をアプリに許可します。"</string>
     <string name="permlab_diagnostic" msgid="8076743953908000342">"diagが所有するリソースの読み書き"</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"diagグループが所有するリソース(/dev内のファイルなど)の読み書きをアプリに許可します。許可すると、システムの安定性とセキュリティに影響が生じる可能性があります。メーカー/通信事業者によるハードウェア固有の診断以外には使用しないでください。"</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"アプリのコンポーネントの有効/無効化"</string>
diff --git a/core/res/res/values-ka-rGE/strings.xml b/core/res/res/values-ka-rGE/strings.xml
index 7e13e96..12f56a3 100644
--- a/core/res/res/values-ka-rGE/strings.xml
+++ b/core/res/res/values-ka-rGE/strings.xml
@@ -423,6 +423,10 @@
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"აპს დასაკრავად შეეძლება გამოიყენოს ნებისმიერი დაყენებული მედია დეკოდერი."</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"სანდო მტკიცებულებების მართვა"</string>
     <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"აპისთვის ნების დართვა, მოახდინოს CA სერტიფიკატების სანდო მტკიცებულებებად ინსტალაცია და დეინსტალაცია."</string>
+    <!-- no translation found for permlab_bindIdleService (7521398788076342815) -->
+    <skip />
+    <!-- no translation found for permdesc_bindIdleService (3062157929989572890) -->
+    <skip />
     <string name="permlab_diagnostic" msgid="8076743953908000342">"სისტემის დიაგნოსტიკის რესურსებში წაკითხვა/ჩაწერის უფლება"</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"აპს შეეძლება, წაიკითხოს ან ჩაწეროს ნებისმიერ რესურსში, რომელიც დიაგნოსტიკის ჯგუფს ეკუთვნის, მაგალითად, ფაილები /dev-ში. ამან შესაძლოა იმოქმედოს სისტემის სტაბილურობასა და უსაფრთხოებაზე. მისი გამოყენება მხოლოდ მწარმოებლის ან ოპერატორის მიერ ტექნიკის სპეციფიკური დიაგნოსტიკისთვის უნდა მოხდეს."</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"აპის კომპონენტების ჩართვა ან გამორთვა"</string>
diff --git a/core/res/res/values-km-rKH/strings.xml b/core/res/res/values-km-rKH/strings.xml
index 38d518a..867d7af 100644
--- a/core/res/res/values-km-rKH/strings.xml
+++ b/core/res/res/values-km-rKH/strings.xml
@@ -423,6 +423,8 @@
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"ឲ្យ​កម្មវិធី​ប្រើ​កម្មវិធី​ឌិកូដ​មេឌៀ​ដែល​បាន​ដំឡើង ដើម្បី​ឌិកូដ​សម្រាប់​ការ​ចាក់​ឡើងវិញ។"</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"គ្រប់គ្រង​ព័ត៌មាន​សម្ងាត់​ដែល​ទុកចិត្ត"</string>
     <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"អនុញ្ញាត​ឲ្យ​កម្មវិធី​ដំឡើង និង​លុប​វិញ្ញាបនបត្រ CA នៅ​ពេល​មាន​ព័ត៌មាន​សម្ងាត់​ដែល​ទុកចិត្ត។"</string>
+    <string name="permlab_bindIdleService" msgid="7521398788076342815">"ភ្ជាប់​​ទៅ​​សេវាកម្ម​ទំនេរ"</string>
+    <string name="permdesc_bindIdleService" msgid="3062157929989572890">"ឲ្យ​កម្មវិធី​ទាក់ទង​ជា​មួយ​សេវាកម្ម​ទំនេរ​ដែល​បាន​កំណត់​ដោយ​កម្មវិធី។"</string>
     <string name="permlab_diagnostic" msgid="8076743953908000342">"អាន/សរសេរ​ធនធាន​គ្រប់គ្រង​ប្រអប់"</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"ឲ្យ​កម្មវិធី​អាន និង​សរសេរ​ប្រភព​ណាមួយ​ដែល​គ្រប់គ្រង​ដោយ​ក្រុម​អ្នក​វិនិច្ឆ័យ ឧទាហរណ៍ ឯកសារ​នៅ​ក្នុង /dev ។ វា​អាច​ប៉ះពាល់​យ៉ាង​ខ្លាំង​ដល់​ស្ថេរ​ភាព​ និង​សុវត្ថិភាព​ប្រព័ន្ធ។ វា​គួរ​ត្រូវ​បាន​ប្រើ​សម្រាប់​វិនិច្ឆ័យ​ផ្នែក​រឹង​ជាក់​លាក់​ដោយ​ក្រុមហ៊ុន​ផលិត ឬ​ប្រតិបត្តិ​ករ។"</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"បិទ ឬ​បើក​សមាសធាតុ​កម្មវិធី"</string>
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index a51e605..c5e6a4a 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -423,6 +423,8 @@
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"애플리케이션에서 설치된 모든 미디어 디코더를 사용하여 재생하는 데 디코딩할 수 있도록 허용합니다."</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"신뢰할 수 있는 자격증명 관리"</string>
     <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"앱에서 CA 인증서를 신뢰할 수 있는 자격증명으로 설치 및 제거하도록 허용합니다."</string>
+    <string name="permlab_bindIdleService" msgid="7521398788076342815">"유휴 서비스에 연결"</string>
+    <string name="permdesc_bindIdleService" msgid="3062157929989572890">"애플리케이션 정의 유휴 서비스와 앱이 상호작용하도록 허용합니다."</string>
     <string name="permlab_diagnostic" msgid="8076743953908000342">"진단 그룹 소유의 리소스 읽기/쓰기"</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"앱이 진단 그룹 소유의 리소스(예: /dev에 있는 파일)를 읽고 쓸 수 있도록 허용합니다. 이 기능은 시스템 안정성 및 보안에 영향을 미칠 수 있으므로 제조업체 또는 사업자가 하드웨어 관련 진단을 수행하는 경우에만 사용해야 합니다."</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"앱 구성요소 사용 또는 사용 안함"</string>
diff --git a/core/res/res/values-lo-rLA/strings.xml b/core/res/res/values-lo-rLA/strings.xml
index c7aed51..4fca324 100644
--- a/core/res/res/values-lo-rLA/strings.xml
+++ b/core/res/res/values-lo-rLA/strings.xml
@@ -423,6 +423,10 @@
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"ອະນຸຍາດໃຫ້ແອັບຯໃຊ້ທຸກຕົວຖອດລະຫັດສື່ທີ່ຕິດຕັ້ງໄວ້ແລ້ວ ເພື່ອການຖອດລະຫັດການຫຼິ້ນໄຟລ໌ຕ່າງໆ."</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"ຈັດການໜັງສືຮັບຮອງທີ່ເຊື່ອຖືໄດ້."</string>
     <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"ອະ​ນຸ​ຍາດ​ໃຫ້ແອັບຯ ຕິດຕັ້ງ ແລະ ຖອນການຕິດຕັ້ງໃບຢັ້ງຢືນ CA ທີ່ເປັນໃບຮັບຮອງທີ່ເຊື່ອຖືໄດ້."</string>
+    <!-- no translation found for permlab_bindIdleService (7521398788076342815) -->
+    <skip />
+    <!-- no translation found for permdesc_bindIdleService (3062157929989572890) -->
+    <skip />
     <string name="permlab_diagnostic" msgid="8076743953908000342">"ອ່ານ/ຂຽນ ໃສ່ຊັບພະຍາກອນທີ່ເປັນຂອງກຸ່ມວິໄຈ"</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"ອະນຸຍາດໃຫ້ແອັບພລິເຄຊັນອ່ານ ແລະຂຽນ ໃສ່ທຸກຊັບພະຍາກອນທີ່ເປັນຂອງກຸ່ມວິນິໄສ; ຕົວຢ່າງ: ໄຟລ໌ໃນ /dev. ສິ່ງນີ້ອາດສົ່ງຜົນກະທົບຕໍ່ຄວາມສະຖຽນ ແລະຄວາມປອດໄພຂອງລະບົບ. ສິ່ງນີ້ຄວນໃຊ້ສຳຫຼັບການວິເຄາະບັນຫາຈຳເພາະ ຂອງບາງຮາດແວໂດຍຜູ່ຜະລິດ ຫຼືຜູ່ປະຕິບັດການເທົ່ານັ້ນ."</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"ເປີດ ຫຼືປິດນຳໃຊ້ອົງປະກອບຂອງແອັບຯ"</string>
diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml
index 6b5191d..ac893c7 100644
--- a/core/res/res/values-lt/strings.xml
+++ b/core/res/res/values-lt/strings.xml
@@ -423,6 +423,8 @@
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Leidžiama programai naudoti bet kurį įdiegtą medijos dekoderį norint iššifruoti atkūrimą."</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"tvarkyti patikimus prisijungimo duomenis"</string>
     <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Programoje galima įdiegti ir iš jos pašalinti CA sertifikatus kaip patikimus prisijungimo duomenis."</string>
+    <string name="permlab_bindIdleService" msgid="7521398788076342815">"susaistyti su neaktyviomis paslaugomis"</string>
+    <string name="permdesc_bindIdleService" msgid="3062157929989572890">"Programai leidžiama sąveikauti su programoje apibrėžtomis neaktyviomis paslaugomis."</string>
     <string name="permlab_diagnostic" msgid="8076743953908000342">"skaityti / rašyti ištekliuose, priklausančiuose diagnostikai"</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"Leidžiama programai skaityti ir rašyti visuose diagnostikos grupei priklausančiuose ištekliuose, pvz., failuose, esančiuose /dev. Tai gali paveikti sistemos stabilumą ir saugą. Tai turėtų būti naudojama TIK gamintojui ar operatoriui atliekant aparatinės įrangos diagnostiką."</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"įgalinti programos komponentus arba jų neleisti"</string>
diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml
index 74022a9..bdc7d60 100644
--- a/core/res/res/values-lv/strings.xml
+++ b/core/res/res/values-lv/strings.xml
@@ -423,6 +423,8 @@
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Ļauj lietotnei izmantot jebkuru instalētu multivides failu dekodētāju, lai dekodētu failus atskaņošanai."</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"Uzticamo akreditācijas datu pārvaldība"</string>
     <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Ļauj lietotnei instalēt un atinstalēt CA sertifikātus kā uzticamus akreditācijas datus."</string>
+    <string name="permlab_bindIdleService" msgid="7521398788076342815">"saistīšana ar neaktīviem pakalpojumiem"</string>
+    <string name="permdesc_bindIdleService" msgid="3062157929989572890">"Ļauj lietotnei mijiedarboties ar lietojumprogrammā noteiktiem neaktīviem pakalpojumiem."</string>
     <string name="permlab_diagnostic" msgid="8076743953908000342">"lasīt grupas “diag” resursus un rakstīt tajos"</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"Ļauj lietotnei lasīt un rakstīt jebkurā resursā, kas pieder diagnostikas grupai, piemēram, failiem mapē /dev. Tas var ietekmēt sistēmas stabilitāti un drošību. Var izmantot ražotājs vai operators TIKAI konkrētas aparatūras diagnostikai."</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"iespējot vai atspējot lietotnes komponentus"</string>
diff --git a/core/res/res/values-mn-rMN/strings.xml b/core/res/res/values-mn-rMN/strings.xml
index 82cdab6..e0095db 100644
--- a/core/res/res/values-mn-rMN/strings.xml
+++ b/core/res/res/values-mn-rMN/strings.xml
@@ -423,6 +423,8 @@
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Апп нь тоглуулах үедээ код тайлахдаа суулгагдсан ямарч медиа код тайлагчийг ашиглах боломжтой."</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"итгэмжлэгдсэн жуухуудыг удирдах"</string>
     <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Апп-д CA сертификатуудыг итгэмжлэгдсэн жуух байдлаар суулгах болон устгахыг зөвшөөрнө."</string>
+    <string name="permlab_bindIdleService" msgid="7521398788076342815">"идэвхгүй үйлчилгээнүүдтэй холбогдох"</string>
+    <string name="permdesc_bindIdleService" msgid="3062157929989572890">"Аппликешн-р тодорхойлогдох идэвхгүй үйлчилгээнүүдтэй харилцах боломжийг апп-д олгоно."</string>
     <string name="permlab_diagnostic" msgid="8076743953908000342">"оношлох грүпийн эзэмшдэг нөөцрүү унших/бичих"</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"Апп нь оношлох грүпийн эзэмшдэг, жишээ нь /dev доторх файлууд, дурын  нөөцийг унших бичих боломжтой.Энэ нь системийн тогвортой байдал болон аюулгүй байдалд бодитоор нөлөөлнө. Энэ нь үйлдвэрлэгч болон операторын хардверт-зориулсан оношлогоонд ашиглагдана."</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"апп компонентыг идэвхжүүлэх эсвэл идэвхгүй болгох"</string>
diff --git a/core/res/res/values-ms-rMY/strings.xml b/core/res/res/values-ms-rMY/strings.xml
index f9d005d..85706b2 100644
--- a/core/res/res/values-ms-rMY/strings.xml
+++ b/core/res/res/values-ms-rMY/strings.xml
@@ -423,6 +423,10 @@
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Membenarkan apl untuk menggunakan sebarang penyahkod media yang dipasangkan untuk menyahkod main semula."</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"urus bukti kelayakan yang dipercayai"</string>
     <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Membenarkan apl memasang dan menyahpasang sijil CA sebagai bukti kelayakan yang dipercayai."</string>
+    <!-- no translation found for permlab_bindIdleService (7521398788076342815) -->
+    <skip />
+    <!-- no translation found for permdesc_bindIdleService (3062157929989572890) -->
+    <skip />
     <string name="permlab_diagnostic" msgid="8076743953908000342">"baca/tulis ke sumber yang dimiliki oleh diag"</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"Membenarkan apl membaca dan menulis ke sebarang sumber yang dimiliki oleh kumpulan diag; contohnya, fail dalam /dev. Hal ini berpotensi menjejaskan kestabilan dan keselamatan sistem. Perkara ini seharusnya HANYA digunakan untuk diagnosis khusus perkakasan oleh pengilang atau pengendali."</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"dayakan atau lumpuhkan komponen apl"</string>
diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml
index e6b29c2..ab7255b 100644
--- a/core/res/res/values-nb/strings.xml
+++ b/core/res/res/values-nb/strings.xml
@@ -423,6 +423,8 @@
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Lar appen bruke en hvilken som helst installert mediedekoder for å dekode for avspilling."</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"administrer pålitelig legitimasjon"</string>
     <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Lar appen installere og avinstallere CA-sertifikater som pålitelig legitimasjon."</string>
+    <string name="permlab_bindIdleService" msgid="7521398788076342815">"knytt til inaktive tjenester"</string>
+    <string name="permdesc_bindIdleService" msgid="3062157929989572890">"Lar appen samhandle med app-definerte inaktive apptjenester."</string>
     <string name="permlab_diagnostic" msgid="8076743953908000342">"lese/skrive ressurser eid av diag"</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"Lar appen lese og skrive til alle ressurser som eies av gruppen «diag», som for eksempel filer i /dev. Dette kan potensielt påvirke systemets sikkerhet og stabilitet. Dette bør BARE brukes av produsenten eller operatøren til maskinvarespesifikk diagnostikk."</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"aktivere eller deaktivere appkomponenter"</string>
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index 3c0ba73..da2946a 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -423,6 +423,8 @@
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Hiermee kan de app alle geïnstalleerde mediadecoders gebruiken om te decoderen voor het afspelen."</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"vertrouwde inloggegevens beheren"</string>
     <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Hiermee kan de app CA-certificaten installeren en verwijderen als vertrouwde inloggegevens."</string>
+    <string name="permlab_bindIdleService" msgid="7521398788076342815">"koppelen aan inactieve services"</string>
+    <string name="permdesc_bindIdleService" msgid="3062157929989572890">"Staat interactie toe tussen de app en door de app gedefinieerde inactieve services."</string>
     <string name="permlab_diagnostic" msgid="8076743953908000342">"lezen/schrijven naar bronnen van diag"</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"Hiermee kan de app lezen en schrijven naar elke bron die hoort bij de diagnostische groep, zoals bestanden in /dev. Hierdoor kan de systeemstabiliteit en -veiligheid worden beïnvloed. Dit mag ALLEEN worden gebruikt voor hardwarespecifieke diagnostiek door de fabrikant of provider."</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"componenten van apps in- of uitschakelen"</string>
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index 96f3b39..cd08739 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -423,6 +423,8 @@
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Pozwala aplikacji na użycie dowolnego zainstalowanego dekodera multimediów do odtwarzania."</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"zarządzanie zaufanymi danymi uwierzytelniającymi"</string>
     <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Zezwala aplikacji na instalowanie i odinstalowywanie certyfikatów CA jako zaufanych danych uwierzytelniających."</string>
+    <string name="permlab_bindIdleService" msgid="7521398788076342815">"powiązanie z nieaktywnymi usługami"</string>
+    <string name="permdesc_bindIdleService" msgid="3062157929989572890">"Umożliwia aplikacji interakcję ze zdefiniowanymi przez nią nieaktywnymi usługami"</string>
     <string name="permlab_diagnostic" msgid="8076743953908000342">"czytanie/zapisywanie w zasobach należących do diagnostyki"</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"Pozwala aplikacji na czytanie i zapisywanie wszystkich zasobów należących do grupy diagnostyki, na przykład plików w katalogu /dev. Może to potencjalnie wpłynąć na stabilność i bezpieczeństwo systemu. Powinno być wykorzystywane WYŁĄCZNIE do diagnozowania sprzętu przez producenta lub operatora."</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"włączanie lub wyłączanie składników aplikacji"</string>
diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml
index 261525c..bc98392 100644
--- a/core/res/res/values-pt-rPT/strings.xml
+++ b/core/res/res/values-pt-rPT/strings.xml
@@ -423,6 +423,8 @@
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Permite que a aplicação utilize qualquer descodificador de multimédia instalado para descodificar a reprodução."</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"gerir credenciais fidedignas"</string>
     <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Permite que a aplicação instale e desinstale certificados da AC (Autoridade de certificação) como credenciais fidedignas."</string>
+    <string name="permlab_bindIdleService" msgid="7521398788076342815">"associar a serviços inativos"</string>
+    <string name="permdesc_bindIdleService" msgid="3062157929989572890">"Permite que a aplicação interaja com serviços inativos definidos pela aplicação."</string>
     <string name="permlab_diagnostic" msgid="8076743953908000342">"ler/escrever em recursos propriedade de diag"</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"Permite à aplicação ler e escrever em qualquer recurso que seja propriedade do grupo diag; por exemplo, ficheiros em /dev. Isto pode potencialmente afetar a estabilidade e a segurança do sistema e deve ser utilizado APENAS para diagnósticos específicos do hardware pelo fabricante ou pelo operador."</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"ativar ou desativar componentes da aplicação"</string>
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index 6a80a78..1d8b55b 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -423,6 +423,10 @@
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Permite que o aplicativo use qualquer decodificador de mídia instalado para reprodução."</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"gerenciar credenciais confiáveis"</string>
     <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Permite que o aplicativo instale e desinstale certificados CA como credenciais confiáveis."</string>
+    <!-- no translation found for permlab_bindIdleService (7521398788076342815) -->
+    <skip />
+    <!-- no translation found for permdesc_bindIdleService (3062157929989572890) -->
+    <skip />
     <string name="permlab_diagnostic" msgid="8076743953908000342">"ler/gravar em recursos pertencentes ao diag"</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"Permite que um aplicativo leia e grave em qualquer recurso que pertença ao grupo de diagnósticos, por exemplo, arquivos in/dev. Isso pode afetar a estabilidade e a segurança do sistema. Esse recurso deve ser usado APENAS para diagnósticos específicos do hardware realizados pelo fabricante ou pela operadora."</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"ativar ou desativar os componentes do aplicativo"</string>
diff --git a/core/res/res/values-rm/strings.xml b/core/res/res/values-rm/strings.xml
index 8755087..fdd26ca 100644
--- a/core/res/res/values-rm/strings.xml
+++ b/core/res/res/values-rm/strings.xml
@@ -678,6 +678,10 @@
     <skip />
     <!-- no translation found for permdesc_manageCaCertificates (4015644047196937014) -->
     <skip />
+    <!-- no translation found for permlab_bindIdleService (7521398788076342815) -->
+    <skip />
+    <!-- no translation found for permdesc_bindIdleService (3062157929989572890) -->
+    <skip />
     <string name="permlab_diagnostic" msgid="8076743953908000342">"leger/scriver en resursas che appartegnan a diagnostics"</string>
     <!-- no translation found for permdesc_diagnostic (6608295692002452283) -->
     <skip />
diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
index b222103..dc1aeda 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -423,6 +423,10 @@
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Permite aplicaţiei să utilizeze orice decodor media instalat pentru a decodifica redarea."</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"gestionarea acreditărilor de încredere"</string>
     <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Permite aplicației să instaleze și să dezinstaleze certificate CA ca acreditări de încredere."</string>
+    <!-- no translation found for permlab_bindIdleService (7521398788076342815) -->
+    <skip />
+    <!-- no translation found for permdesc_bindIdleService (3062157929989572890) -->
+    <skip />
     <string name="permlab_diagnostic" msgid="8076743953908000342">"citire/scriere în resursele deţinute de diag"</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"Permite aplicaţiei să citească şi să scrie în orice resursă deţinută de grupul diag, de ex., fişierele din /dev. Această permisiune ar putea să afecteze stabilitatea şi securitatea sistemului. Permisiunea trebuie utilizată NUMAI de producător sau de operator pentru diagnostice specifice pentru hardware."</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"activare sau dezactivare a componentelor aplicaţiei"</string>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index c28a019..652dba5 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -423,6 +423,8 @@
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Приложение сможет использовать любой установленный дешифратор."</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"Управление учетными данными"</string>
     <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Приложение сможет устанавливать сертификаты ЦС в качестве надежных учетных данных, а также удалять их."</string>
+    <string name="permlab_bindIdleService" msgid="7521398788076342815">"привязка неактивных сервисов"</string>
+    <string name="permdesc_bindIdleService" msgid="3062157929989572890">"Приложение сможет взаимодействовать с определенными неактивными сервисами."</string>
     <string name="permlab_diagnostic" msgid="8076743953908000342">"Чтение/запись данных в системы диагностики"</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"Приложение сможет считывать и записывать данные системы диагностики (например, файлы в каталоге /dev). Это может повлиять на стабильность и безопасность системы. Это разрешение должно использоваться ТОЛЬКО производителем или оператором для диагностики аппаратного обеспечения."</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"Включение/отключение компонентов приложения"</string>
diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml
index 399eeee..f06e575 100644
--- a/core/res/res/values-sk/strings.xml
+++ b/core/res/res/values-sk/strings.xml
@@ -423,6 +423,8 @@
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Umožňuje aplikácii používať na reprodukciu ľubovoľný nainštalovaný dekódovač na dekódovanie."</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"spravovať dôveryhodné poverenia"</string>
     <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Umožňuje aplikácii inštalovať a odinštalovať certifikáty CA ako dôveryhodné poverenia."</string>
+    <string name="permlab_bindIdleService" msgid="7521398788076342815">"previazať s nečinnými službami"</string>
+    <string name="permdesc_bindIdleService" msgid="3062157929989572890">"Umožňuje aplikácii interakciu s nečinnými službami definovanými aplikáciou."</string>
     <string name="permlab_diagnostic" msgid="8076743953908000342">"čítanie alebo zápis do prostriedkov funkcie diag"</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"Umožňuje aplikácii čítať ľubovoľné prostriedky v skupine diag, napr. súbory v priečinku /dev, a zapisovať do nich. Môže dôjsť k ovplyvneniu stability a bezpečnosti systému. Toto nastavenie by mal používať IBA výrobca či operátor na diagnostiku hardvéru."</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"povoliť alebo zakázať súčasti aplikácie"</string>
@@ -554,7 +556,7 @@
     <string name="permlab_locationUpdates" msgid="7785408253364335740">"ovládanie upozornení na aktualizáciu polohy"</string>
     <string name="permdesc_locationUpdates" msgid="1120741557891438876">"Umožňuje aplikácii povoliť alebo zakázať upozornenia s aktualizáciami polohy z rádia. Bežné aplikácie toto nastavenie nepoužívajú."</string>
     <string name="permlab_checkinProperties" msgid="7855259461268734914">"prístup k vlastnostiam nahlásenia"</string>
-    <string name="permdesc_checkinProperties" msgid="4024526968630194128">"Umožňuje aplikácii čítať a zapisovať vlastnosti odovzdané službou nahlasovania. Bežné aplikácie toto nastavenie nepoužívajú."</string>
+    <string name="permdesc_checkinProperties" msgid="4024526968630194128">"Umožňuje aplikácii čítať a zapisovať vlastnosti nahrané službou nahlasovania. Bežné aplikácie toto nastavenie nepoužívajú."</string>
     <string name="permlab_bindGadget" msgid="776905339015863471">"zvoliť miniaplikácie"</string>
     <string name="permdesc_bindGadget" msgid="8261326938599049290">"Umožňuje aplikácii povedať systému, ktoré aplikácie môžu používať určité miniaplikácie. Aplikácia s týmto povolením môže iným aplikáciám povoliť prístup k osobným údajom. Bežné aplikácie toto nastavenie nepoužívajú."</string>
     <string name="permlab_modifyPhoneState" msgid="8423923777659292228">"zmeny stavu telefónu"</string>
@@ -1491,7 +1493,7 @@
     <string name="wireless_display_route_description" msgid="9070346425023979651">"Bezdrôtový displej"</string>
     <string name="media_route_button_content_description" msgid="5758553567065145276">"Výstup médií"</string>
     <string name="media_route_chooser_title" msgid="1751618554539087622">"Pripojenie k zariadeniu"</string>
-    <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"Odovzdanie obraz. na prehratie v zariad."</string>
+    <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"Nahranie obraz. na prehratie v zariad."</string>
     <string name="media_route_chooser_searching" msgid="4776236202610828706">"Prebieha vyhľadávanie zariadení…"</string>
     <string name="media_route_chooser_extended_settings" msgid="87015534236701604">"Nastavenia"</string>
     <string name="media_route_controller_disconnect" msgid="8966120286374158649">"Odpojiť"</string>
@@ -1505,9 +1507,9 @@
     <string name="display_manager_overlay_display_name" msgid="5142365982271620716">"Prekrytie č. <xliff:g id="ID">%1$d</xliff:g>"</string>
     <string name="display_manager_overlay_display_title" msgid="652124517672257172">"<xliff:g id="NAME">%1$s</xliff:g>: <xliff:g id="WIDTH">%2$d</xliff:g> x <xliff:g id="HEIGHT">%3$d</xliff:g>, <xliff:g id="DPI">%4$d</xliff:g> dpi"</string>
     <string name="display_manager_overlay_display_secure_suffix" msgid="6022119702628572080">", zabezpečené"</string>
-    <string name="wifi_display_notification_connecting_title" msgid="2838646471050359706">"Odovzdávanie obrazovky na prehratie"</string>
+    <string name="wifi_display_notification_connecting_title" msgid="2838646471050359706">"Nahrávanie obrazovky na prehratie"</string>
     <string name="wifi_display_notification_connecting_message" msgid="5837350993752841389">"Prebieha pripájanie k obrazovke <xliff:g id="NAME">%1$s</xliff:g>"</string>
-    <string name="wifi_display_notification_connected_title" msgid="8567308065912676285">"Odovzdávanie obrazovky na prehratie"</string>
+    <string name="wifi_display_notification_connected_title" msgid="8567308065912676285">"Nahrávanie obrazovky na prehratie"</string>
     <string name="wifi_display_notification_connected_message" msgid="2587209325701109715">"Pripojené k obrazovke <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="wifi_display_notification_disconnect" msgid="6183754463561153372">"Odpojiť"</string>
     <string name="kg_emergency_call_label" msgid="684946192523830531">"Tiesňové volanie"</string>
diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml
index 7c0dc63..b56e7b1 100644
--- a/core/res/res/values-sl/strings.xml
+++ b/core/res/res/values-sl/strings.xml
@@ -423,6 +423,8 @@
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Programu omogoča, da uporabi kateri koli dekodirnik večpredstavnosti za predvajanje."</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"upravljanje preverjenih poverilnic"</string>
     <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Aplikaciji dovoli nameščanje in odstranjevanje potrdil overitelja potrdil kot preverjenih poverilnic."</string>
+    <string name="permlab_bindIdleService" msgid="7521398788076342815">"vezanje na nedejavne storitve"</string>
+    <string name="permdesc_bindIdleService" msgid="3062157929989572890">"Aplikaciji omogoča interakcijo z nedejavnimi storitvami, določenimi z aplikacijami."</string>
     <string name="permlab_diagnostic" msgid="8076743953908000342">"branje/pisanje v sredstva, ki so v lasti skupine za diagnostiko"</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"Programu omogoča branje in pisanje na poljuben vir, ki je v lasti skupine za diagnostiko; na primer datoteke v mapi /dev. To lahko vpliva na stabilnost in varnost sistema. To naj uporablja SAMO izdelovalec ali operater za diagnostiko, specifično za strojno opremo."</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"omogočanje ali onemogočanje komponent programa"</string>
diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml
index 5b5f451..af194ce 100644
--- a/core/res/res/values-sr/strings.xml
+++ b/core/res/res/values-sr/strings.xml
@@ -423,6 +423,8 @@
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Омогућава апликацији да користи било који инсталирани декодер медија за декодирање за репродукцију."</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"управљање поузданим акредитивима"</string>
     <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Дозвољава апликацији да инсталира и деинсталира CA сертификате као поуздане акредитиве."</string>
+    <string name="permlab_bindIdleService" msgid="7521398788076342815">"повезивање са неактивним услугама"</string>
+    <string name="permdesc_bindIdleService" msgid="3062157929989572890">"Дозвољава апликацији да остварује интеракцију са неактивним услугама дефинисаним у апликацији."</string>
     <string name="permlab_diagnostic" msgid="8076743953908000342">"читање ресурса у власништву дијагностике и уписивање података у њих"</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"Дозвољава апликацији да чита и уписује податке у било који ресурс у власништву групе за дијагностиковање, на пример, датотеке у директоријуму /dev. То може да угрози стабилност и безбедност система и треба да је користе САМО произвођач или оператер у сврхе дијагностиковањa хардвера."</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"омогућавање или онемогућавање компоненти апликације"</string>
diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml
index bdd8e76..8b449db 100644
--- a/core/res/res/values-sv/strings.xml
+++ b/core/res/res/values-sv/strings.xml
@@ -423,6 +423,8 @@
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Tillåter att appen använder installerade medieavkodare för att avkoda media för uppspelning."</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"hantera betrodda uppgifter"</string>
     <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Tillåter att appen installerar och avinstallerar CA-certifikat som betrodda uppgifter."</string>
+    <string name="permlab_bindIdleService" msgid="7521398788076342815">"knyt till inaktiva tjänster"</string>
+    <string name="permdesc_bindIdleService" msgid="3062157929989572890">"Tillåter att appen interagerar med tjänster som har definierats som inaktiva av appen."</string>
     <string name="permlab_diagnostic" msgid="8076743953908000342">"läsa/skriva till resurser som ägs av diag"</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"Tillåter att appen läser och skriver till en resurs som ägs av diag-gruppen, till exempel filer i /dev. Detta kan eventuellt påverka systemets stabilitet och säkerhet. Detta bör ENDAST användas av tillverkaren eller operatören för maskinvaruspecifik diagnostik."</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"aktivera eller inaktivera appkomponenter"</string>
diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml
index d0fcc09..197f3b3 100644
--- a/core/res/res/values-sw/strings.xml
+++ b/core/res/res/values-sw/strings.xml
@@ -359,8 +359,8 @@
     <string name="permdesc_setAnimationScale" msgid="7690063428924343571">"Huruhusu programu kubadilisha kasi ya uhuishaji kijumla (uhuisho wa haraka zaidi au wa polepole zaidi) wakati wowote."</string>
     <string name="permlab_manageAppTokens" msgid="1286505717050121370">"Dhibiti shuhuda za programu"</string>
     <string name="permdesc_manageAppTokens" msgid="8043431713014395671">"Inaruhusu programu kuunda na kudhibiti shuhuda zake, kukwepa mipangilio yao ya kawaida. Haitahitajika kamwe na programu za kawaida."</string>
-    <string name="permlab_freezeScreen" msgid="4708181184441880175">"lemaza skrini"</string>
-    <string name="permdesc_freezeScreen" msgid="8558923789222670064">"Inaruhusu programu kulemaza kwa muda skrini kwa ajili ya mpito kamili wa skrinimaombi kwa muda kufungia screen kwa ajili ya mpito full-screen."</string>
+    <string name="permlab_freezeScreen" msgid="4708181184441880175">"fanya skrini isisonge"</string>
+    <string name="permdesc_freezeScreen" msgid="8558923789222670064">"Huruhusu programu kufanya skrini isisonge kwa muda ili kuruhusu kubadilisha hadi skrini nzima."</string>
     <string name="permlab_injectEvents" msgid="1378746584023586600">"bonyeza vitufe na vitufe vya kudhibiti"</string>
     <string name="permdesc_injectEvents" product="tablet" msgid="206352565599968632">"Huruhusu programu kuwasilisha matukio yake ya ingizo (mibonyezo ya vitufe, nk.) kwa programu zingine. programu hasidi zinaweza kutumia hii ili kutawala kompyuta kibao."</string>
     <string name="permdesc_injectEvents" product="default" msgid="653128057572326253">"Inaruhusu programu kuwasilisha matukio yake ya ingizo (mibonyezo ya kitufe, nk.)kwa programu zingine.Programu hasidi zinaweza kutumia hii kutawala simu."</string>
@@ -423,6 +423,8 @@
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Huruhusu programu kutumia vyombo vyovyote vya habari vilivyosakinishwa ili kusimbua kwa ajili ya kucheza tena."</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"dhibiti vitambulisho vinavyoaminika"</string>
     <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Huruhusu programu kusakinisha na kusanidua vyeti vya CA kama vitambulisho vinavyoaminika."</string>
+    <string name="permlab_bindIdleService" msgid="7521398788076342815">"funga kwenye huduma zisizofanya kitu"</string>
+    <string name="permdesc_bindIdleService" msgid="3062157929989572890">"Huruhusu programu kuwasiliana na huduma zisizofanya kitu zilizobainishwa na programu."</string>
     <string name="permlab_diagnostic" msgid="8076743953908000342">"soma/andika kwa vyanzo vinavyomilikiwa na diag"</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"Inaruhusu programu kusoma na kuandika kwa chanzo chochote kinachomilikiwa na kikundi cha diag; kwa mfano, faili katika /dev. Hii inaweza kuathiri udhabiti na usalama wa mfumo. Hii inapaswa kutumiwa TU kwa utambuzi mahsusi wa maunzi na mtengenezaji au opareta."</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"wezesha au lemeza vijenzi vya programu"</string>
diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml
index a0b2ee4..c0c85d8 100644
--- a/core/res/res/values-th/strings.xml
+++ b/core/res/res/values-th/strings.xml
@@ -423,6 +423,8 @@
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"อนุญาตให้แอปพลิเคชันใช้ตัวถอดรหัสสื่อใดก็ได้ที่ติดตั้งไว้เพื่อถอดรหัสสำหรับการเล่น"</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"จัดการข้อมูลรับรองที่เชื่อถือได้"</string>
     <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"อนุญาตให้แอปติดตั้งและถอนการติดตั้งใบรับรอง CA ในฐานะข้อมูลรับรองที่เชื่อถือได้"</string>
+    <string name="permlab_bindIdleService" msgid="7521398788076342815">"เชื่อมโยงกับบริการที่ไม่ได้ใช้งาน"</string>
+    <string name="permdesc_bindIdleService" msgid="3062157929989572890">"อนุญาตให้แอปโต้ตอบกับบริการที่แอปพลิเคชันระบุว่าไม่ได้ใช้งาน"</string>
     <string name="permlab_diagnostic" msgid="8076743953908000342">"อ่าน/เขียนไปยังรีซอร์สที่เป็นเจ้าของโดยกลุ่มวินิจฉัย"</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"อนุญาตให้แอปพลิเคชันอ่านและเขียนไปยังทรัพยากรที่เป็นของกลุ่มวินิจฉัย เช่น ไฟล์ใน /dev การทำเช่นนี้อาจส่งผลต่อความเสถียรและความปลอดภัยของระบบ และควรใช้สำหรับการวินิจฉัยเกี่ยวกับฮาร์ดแวร์โดยเฉพาะที่ทำโดยผู้ผลิตหรือผู้ให้บริการเท่านั้น"</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"เปิดหรือปิดใช้งานคอมโพเนนต์ของแอปพลิเคชัน"</string>
@@ -1526,7 +1528,7 @@
     <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"กำลังปลดล็อกซิมการ์ด…"</string>
     <string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"รหัส PIN ไม่ถูกต้อง"</string>
     <string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"พิมพ์ PIN ซึ่งเป็นเลข 4 ถึง 8 หลัก"</string>
-    <string name="kg_invalid_sim_puk_hint" msgid="6025069204539532000">"รหัส PUK ต้องเป็นตัวเลข 8 ตัว"</string>
+    <string name="kg_invalid_sim_puk_hint" msgid="6025069204539532000">"รหัส PUK ต้องเป็นตัวเลข 8 หลัก"</string>
     <string name="kg_invalid_puk" msgid="3638289409676051243">"ใส่รหัส PUK ที่ถูกต้องอีกครั้ง การพยายามซ้ำหลายครั้งจะทำให้ซิมการ์ดถูกปิดใช้งานอย่างถาวร"</string>
     <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"รหัส PIN ไม่ตรง"</string>
     <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"ลองหลายรูปแบบมากเกินไป"</string>
diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml
index af36cee..0b4aa2d 100644
--- a/core/res/res/values-tl/strings.xml
+++ b/core/res/res/values-tl/strings.xml
@@ -423,6 +423,8 @@
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Pinapayagan ang app na gumamit ng anumang naka-install na media decoder upang mag-decode para sa pag-playback."</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"mga pinamamahalaang pinagkakatiwalaang kredensyal"</string>
     <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Pinapayagan ang app na mag-install at mag-uninstall ng mga CA certificate bilang mga pinagkakatiwalaang kredensyal."</string>
+    <string name="permlab_bindIdleService" msgid="7521398788076342815">"sumailalim sa mga idle na serbisyo"</string>
+    <string name="permdesc_bindIdleService" msgid="3062157929989572890">"Pinapayagan ang app na makipag-ugnayan sa mga idle na serbisyong partikular sa application."</string>
     <string name="permlab_diagnostic" msgid="8076743953908000342">"magbasa/magsulat sa mga mapagkukunang pag-aari ng diag"</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"Pinapayagan ang app na magbasa at magsulat sa anumang mapagkukunang pag-aari ng pangkat ng diag; halimbawa, mga file sa /dev. Maaaring potensyal na maapektuhan nito ang katatagan at seguridad ng system. Dapat LAMANG itong gamitin para sa diagnostics na tukoy sa hardware ng tagagawa o operator."</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"paganahin o huwag paganahin ang mga bahagi ng app"</string>
diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
index 99d415a..f583750 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -423,6 +423,8 @@
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Uygulamaya, oynatma kodunu çözmek için herhangi bir yüklü medya kod çözücüyü kullanma izni verir."</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"güvenilen kimlik bilgilerini yönetme"</string>
     <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Uygulamaya, güvenilir kimlik bilgileri olarak CA sertifikaları yükleme veya sertifikaların yüklemelerini kaldırma izni verir."</string>
+    <string name="permlab_bindIdleService" msgid="7521398788076342815">"boşta kalma hizmetlerine bağlan"</string>
+    <string name="permdesc_bindIdleService" msgid="3062157929989572890">"Uygulamaya, uygulama tanımlı boşta kalma hizmetleriyle etkileşim kurma izni verir."</string>
     <string name="permlab_diagnostic" msgid="8076743953908000342">"sahibi tanılama olan kaynakları oku/bunlara yaz"</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"Uygulamaya, tanılama grubunun sahip olduğu tüm kaynaklara (örneğin /dev içindeki dosyalar) okuma ve yazma izni verir. Bu işlevin sistem kararlılığını ve güvenliğini olumsuz etkileme olasılığı vardır. Üretici veya operatör tarafından YALNIZCA donanıma özgü tanılama için kullanılmalıdır."</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"uygulama bileşenlerini etkinleştir veya devre dışı bırak"</string>
diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml
index da50f73..a910a97 100644
--- a/core/res/res/values-uk/strings.xml
+++ b/core/res/res/values-uk/strings.xml
@@ -423,6 +423,8 @@
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Дозволяє програмі використовувати будь-який установлений медіа-декодер для декодування з метою відтворення."</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"керувати захищеними обліковими даними"</string>
     <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Дозволяє програмі встановлювати та видаляти сертифікати центру сертифікації (CA) як захищені облікові дані."</string>
+    <string name="permlab_bindIdleService" msgid="7521398788076342815">"взаємодіяти з неактивними службами"</string>
+    <string name="permdesc_bindIdleService" msgid="3062157929989572890">"Дозволяє програмі взаємодіяти з неактивними службами програми."</string>
     <string name="permlab_diagnostic" msgid="8076743953908000342">"чит./зап. на ресури., якими вол. діаг."</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"Дозволяє програмі читати та писати на будь-який ресурс, яким володіє діагностична група; наприклад, у файли в папці /dev. Це потенційно може вплинути на стабільність і безпеку системи. Потрібно використовувати ЛИШЕ для певної діагностики обладнання, яку виконує виробник чи оператор."</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"вмикати чи вимикати компоненти програми"</string>
diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml
index 0cabb12..eb04530 100644
--- a/core/res/res/values-vi/strings.xml
+++ b/core/res/res/values-vi/strings.xml
@@ -423,6 +423,8 @@
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Cho phép ứng dụng sử dụng bất kỳ trình giải mã phương tiện nào đã cài đặt nhằm giải mã để phát lại."</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"quản lý thông tin xác thực đáng tin cậy"</string>
     <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Cho phép ứng dụng cài đặt và gỡ cài đặt chứng chỉ CA dưới dạng thông tin xác thực đáng tin cậy."</string>
+    <string name="permlab_bindIdleService" msgid="7521398788076342815">"liên kết với dịch vụ không dùng đến"</string>
+    <string name="permdesc_bindIdleService" msgid="3062157929989572890">"Cho phép ứng dụng tương tác với dịch vụ không dùng đến được xác định cho ứng dụng."</string>
     <string name="permlab_diagnostic" msgid="8076743953908000342">"đọc/ghi vào tài nguyên do chẩn đoán sở hữu"</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"Cho phép ứng dụng đọc và ghi vào bất kỳ tài nguyên nào do nhóm chẩn đoán sở hữu; ví dụ: các tệp trong /dev. Quyền này có thể ảnh hưởng đến sự ổn định và tính bảo mật của hệ thống. CHỈ nên sử dụng quyền này cho các chẩn đoán phần cứng cụ thể của nhà sản xuất hoặc nhà cung cấp."</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"bật hoặc tắt cấu phần ứng dụng"</string>
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index 507b29b..de5c778 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -423,6 +423,8 @@
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"允许该应用使用任何已安装的媒体解码器进行解码,以便播放媒体。"</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"管理受信任的凭据"</string>
     <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"允许应用安装和卸载 CA 证书(作为受信任的凭据)。"</string>
+    <string name="permlab_bindIdleService" msgid="7521398788076342815">"绑定到闲置服务"</string>
+    <string name="permdesc_bindIdleService" msgid="3062157929989572890">"允许该应用与应用定义的闲置服务互动。"</string>
     <string name="permlab_diagnostic" msgid="8076743953908000342">"读取/写入诊断所拥有的资源"</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"允许应用读取/写入诊断组拥有的所有资源(例如 /dev 中的文件)。这可能会影响系统的稳定性和安全性。此权限仅供制造商或运营商诊断硬件方面的问题时使用。"</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"启用或停用应用组件"</string>
diff --git a/core/res/res/values-zh-rHK/strings.xml b/core/res/res/values-zh-rHK/strings.xml
index e5441a2..0471d4a 100644
--- a/core/res/res/values-zh-rHK/strings.xml
+++ b/core/res/res/values-zh-rHK/strings.xml
@@ -423,6 +423,8 @@
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"允許應用程式使用任何已安裝的媒體解碼器為播放解碼。"</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"管理信任的憑證"</string>
     <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"允許應用程式安裝 CA 憑證為信任的憑證及解除安裝 CA 憑證。"</string>
+    <string name="permlab_bindIdleService" msgid="7521398788076342815">"繫結至閒置服務"</string>
+    <string name="permdesc_bindIdleService" msgid="3062157929989572890">"允許應用程式與由應用程式定義的閒置服務進行互動。"</string>
     <string name="permlab_diagnostic" msgid="8076743953908000342">"讀取/寫入由診斷應用程式擁有的資源"</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"允許應用程式讀取及寫入診斷群組所擁有的任何資源 (例如:位於 /dev 中的檔案)。這可能會影響系統的穩定性及安全性,只應對製造商或網絡供應商所使用的硬件專用診斷程式開放這項權限。"</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"啟用或停用應用程式元件"</string>
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index 153f85f..6cbeedf 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -423,6 +423,8 @@
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"允許應用程式使用任何已安裝的媒體解碼器進行解碼以播放影片。"</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"管理信任的憑證"</string>
     <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"允許應用程式安裝 CA 憑證 (做為信任的憑證) 及解除安裝 CA 憑證。"</string>
+    <string name="permlab_bindIdleService" msgid="7521398788076342815">"繫結至閒置的服務"</string>
+    <string name="permdesc_bindIdleService" msgid="3062157929989572890">"允許應用程式與由應用程式定義的閒置服務進行互動。"</string>
     <string name="permlab_diagnostic" msgid="8076743953908000342">"讀寫 diag 擁有的資源"</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"允許應用程式讀取或寫入診斷群組擁有的任何資源,例如 /dev 底下的檔案。這可能會影響系統的穩定性和安全性,因此應由製造商或電信業者操作,且只用在特定硬體診斷。"</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"啟用或停用應用程式元件"</string>
diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml
index 2687603..20fe57e 100644
--- a/core/res/res/values-zu/strings.xml
+++ b/core/res/res/values-zu/strings.xml
@@ -423,6 +423,8 @@
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Ivumela uhlelo lokusebenza ukusebenzisa noma isiphi isiqophi semidiya esifakiwe ukuqopha ukudlala."</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"phatha ukuqinisekisa okuthenjiwe"</string>
     <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Ivumela uhlelo lokusebenza ukuthi lifake liphinde likhiphe izitifiketi ze-CA njengokuqinisekiswa okuthenjiwe."</string>
+    <string name="permlab_bindIdleService" msgid="7521398788076342815">"bophezela kumasevisi angenzi lutho"</string>
+    <string name="permdesc_bindIdleService" msgid="3062157929989572890">"Ivumela uhlelo lokusebenza ukuthi luhlanganyele nohlelo lokusebenza oluchaziwe lwamasevisi angenzi lutho."</string>
     <string name="permlab_diagnostic" msgid="8076743953908000342">"funda/bhalela emithombweni ephethwe idayegi"</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"Ivumela uhlelo lokusebenza ukufunda nokubhala kunoma yimuphi umthombo weqembu ledayegi; ngokwesibonelo, amafayela akwi/dev. Lokhu kungase kuthinte kakhulu ukuba nokuphepha kohlelo. Lokhu kumele kusebenziselwe KUPHELA ukuhlola ihadiwe okucacile ngumkhiqizi noma u-opheretha."</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"vumela noma vimbela izingxenye zensiza"</string>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index ee68199..d70ce0a 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -1178,7 +1178,7 @@
     <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_bindIdleService">bind to idle services</string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_bindIdleService">Allows the app to interact with application-defined idle services.</string>
+    <string name="permdesc_bindIdleService">This permission allows the Android system to bind to an application\'s idle services.</string>
 
     <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_diagnostic">read/write to resources owned by diag</string>
diff --git a/core/tests/hosttests/test-apps/DownloadManagerTestApp/src/com/android/frameworks/downloadmanagertests/DownloadManagerTestApp.java b/core/tests/hosttests/test-apps/DownloadManagerTestApp/src/com/android/frameworks/downloadmanagertests/DownloadManagerTestApp.java
index 0518e64..06c6c34 100644
--- a/core/tests/hosttests/test-apps/DownloadManagerTestApp/src/com/android/frameworks/downloadmanagertests/DownloadManagerTestApp.java
+++ b/core/tests/hosttests/test-apps/DownloadManagerTestApp/src/com/android/frameworks/downloadmanagertests/DownloadManagerTestApp.java
@@ -23,6 +23,9 @@
 import android.os.ParcelFileDescriptor;
 import android.util.Log;
 
+import com.android.frameworks.downloadmanagertests.DownloadManagerBaseTest;
+import com.android.frameworks.downloadmanagertests.DownloadManagerTestRunner;
+
 import java.io.DataInputStream;
 import java.io.DataOutputStream;
 import java.io.File;
@@ -38,14 +41,8 @@
     protected static String LOG_TAG =
             "com.android.frameworks.downloadmanagertests.DownloadManagerTestApp";
 
-    protected static String DOWNLOAD_500K_FILENAME = "External541kb.apk";
-    protected static long DOWNLOAD_500K_FILESIZE = 570927;
-    protected static String DOWNLOAD_1MB_FILENAME = "External1mb.apk";
-    protected static long DOWNLOAD_1MB_FILESIZE = 1041262;
-    protected static String DOWNLOAD_5MB_FILENAME = "External5mb.apk";
-    protected static long DOWNLOAD_5MB_FILESIZE = 5138700;
-    protected static String DOWNLOAD_10MB_FILENAME = "External10mb.apk";
-    protected static long DOWNLOAD_10MB_FILESIZE = 10258741;
+    protected static final String DOWNLOAD_FILENAME = "External93mb.apk";
+    protected static final long DOWNLOAD_FILESIZE = 95251708;
 
     private static final String FILE_CONCURRENT_DOWNLOAD_FILE_PREFIX = "file";
     private static final String FILE_CONCURRENT_DOWNLOAD_FILE_EXTENSION = ".bin";
@@ -126,7 +123,7 @@
      * @throws Exception if unsuccessful
      */
     public void initiateDownload() throws Exception {
-        String filename = DOWNLOAD_5MB_FILENAME;
+        String filename = DOWNLOAD_FILENAME;
         mContext.deleteFile(DOWNLOAD_STARTED_FLAG);
         FileOutputStream fileOutput = mContext.openFileOutput(DOWNLOAD_STARTED_FLAG, 0);
         DataOutputStream outputFile = null;
@@ -162,8 +159,8 @@
      * @throws Exception if unsuccessful
      */
     public void verifyFileDownloadSucceeded() throws Exception {
-        String filename = DOWNLOAD_5MB_FILENAME;
-        long filesize = DOWNLOAD_5MB_FILESIZE;
+        String filename = DOWNLOAD_FILENAME;
+        long filesize = DOWNLOAD_FILESIZE;
         long dlRequest = -1;
         boolean rebootMarkerValid = false;
         DataInputStream dataInputFile = null;
@@ -223,8 +220,8 @@
      * @throws Exception if unsuccessful
      */
     public void runLargeDownloadOverWiFi() throws Exception {
-        String filename = DOWNLOAD_10MB_FILENAME;
-        long filesize = DOWNLOAD_10MB_FILESIZE;
+        String filename = DOWNLOAD_FILENAME;
+        long filesize = DOWNLOAD_FILESIZE;
         long dlRequest = -1;
         doCommonDownloadSetup();
 
@@ -265,8 +262,8 @@
      * @throws Exception if unsuccessful
      */
     public void runDownloadMultipleSwitching() throws Exception {
-        String filename = DOWNLOAD_5MB_FILENAME;
-        long filesize = DOWNLOAD_5MB_FILESIZE;
+        String filename = DOWNLOAD_FILENAME;
+        long filesize = DOWNLOAD_FILESIZE;
         doCommonDownloadSetup();
 
         String localDownloadDirectory = Environment.getExternalStorageDirectory().getPath();
@@ -340,8 +337,8 @@
      * @throws Exception if unsuccessful
      */
     public void runDownloadMultipleWiFiEnableDisable() throws Exception {
-        String filename = DOWNLOAD_5MB_FILENAME;
-        long filesize = DOWNLOAD_5MB_FILESIZE;
+        String filename = DOWNLOAD_FILENAME;
+        long filesize = DOWNLOAD_FILESIZE;
         doCommonDownloadSetup();
 
         String localDownloadDirectory = Environment.getExternalStorageDirectory().getPath();
@@ -409,8 +406,8 @@
      * @throws Exception if unsuccessful
      */
     public void runDownloadMultipleAirplaneModeEnableDisable() throws Exception {
-        String filename = DOWNLOAD_5MB_FILENAME;
-        long filesize = DOWNLOAD_5MB_FILESIZE;
+        String filename = DOWNLOAD_FILENAME;
+        long filesize = DOWNLOAD_FILESIZE;
         // make sure WiFi is enabled, and airplane mode is not on
         doCommonDownloadSetup();
 
diff --git a/graphics/java/android/graphics/drawable/Drawable.java b/graphics/java/android/graphics/drawable/Drawable.java
index b8365aa..b81e1c0 100644
--- a/graphics/java/android/graphics/drawable/Drawable.java
+++ b/graphics/java/android/graphics/drawable/Drawable.java
@@ -228,6 +228,20 @@
     }
 
     /**
+     * Return the drawable's dirty bounds Rect. Note: for efficiency, the
+     * returned object may be the same object stored in the drawable (though
+     * this is not guaranteed).
+     * <p>
+     * By default, this returns the full drawable bounds. Custom drawables may
+     * override this method to perform more precise invalidation.
+     *
+     * @hide
+     */
+    public Rect getDirtyBounds() {
+        return getBounds();
+    }
+
+    /**
      * Set a mask of the configuration parameters for which this drawable
      * may change, requiring that it be re-created.
      *
@@ -508,6 +522,15 @@
     public void clearHotspots() {}
 
     /**
+     * Whether this drawable requests projection.
+     *
+     * @hide
+     */
+    public boolean isProjected() {
+        return false;
+    }
+
+    /**
      * Indicates whether this view will change its appearance based on state.
      * Clients can use this to determine whether it is necessary to calculate
      * their state and call setState.
@@ -962,6 +985,8 @@
             drawable = new TransitionDrawable();
         } else if (name.equals("reveal")) {
             drawable = new RevealDrawable();
+        } else if (name.equals("touch-feedback")) {
+            drawable = new TouchFeedbackDrawable();
         } else if (name.equals("color")) {
             drawable = new ColorDrawable();
         } else if (name.equals("shape")) {
diff --git a/graphics/java/android/graphics/drawable/InsetDrawable.java b/graphics/java/android/graphics/drawable/InsetDrawable.java
index 8188782..f841d6a 100644
--- a/graphics/java/android/graphics/drawable/InsetDrawable.java
+++ b/graphics/java/android/graphics/drawable/InsetDrawable.java
@@ -182,6 +182,38 @@
         }
     }
 
+    /**
+     * @hide
+     */
+    @Override
+    public boolean supportsHotspots() {
+        return mInsetState.mDrawable.supportsHotspots();
+    }
+
+    /**
+     * @hide
+     */
+    @Override
+    public void setHotspot(int id, float x, float y) {
+        mInsetState.mDrawable.setHotspot(id, x, y);
+    }
+
+    /**
+     * @hide
+     */
+    @Override
+    public void removeHotspot(int id) {
+        mInsetState.mDrawable.removeHotspot(id);
+    }
+
+    /**
+     * @hide
+     */
+    @Override
+    public void clearHotspots() {
+        mInsetState.mDrawable.clearHotspots();
+    }
+
     @Override
     public boolean setVisible(boolean visible, boolean restart) {
         mInsetState.mDrawable.setVisible(visible, restart);
diff --git a/graphics/java/android/graphics/drawable/LayerDrawable.java b/graphics/java/android/graphics/drawable/LayerDrawable.java
index e8b3f64..2e098a0 100644
--- a/graphics/java/android/graphics/drawable/LayerDrawable.java
+++ b/graphics/java/android/graphics/drawable/LayerDrawable.java
@@ -423,6 +423,58 @@
         }
     }
 
+    /**
+     * @hide
+     */
+    @Override
+    public boolean supportsHotspots() {
+        final ChildDrawable[] array = mLayerState.mChildren;
+        final int N = mLayerState.mNum;
+        for (int i = 0; i < N; i++) {
+            if (array[i].mDrawable.supportsHotspots()) {
+                return true;
+            }
+        }
+
+        return false;
+    }
+
+    /**
+     * @hide
+     */
+    @Override
+    public void setHotspot(int id, float x, float y) {
+        final ChildDrawable[] array = mLayerState.mChildren;
+        final int N = mLayerState.mNum;
+        for (int i = 0; i < N; i++) {
+            array[i].mDrawable.setHotspot(id, x, y);
+        }
+    }
+
+    /**
+     * @hide
+     */
+    @Override
+    public void removeHotspot(int id) {
+        final ChildDrawable[] array = mLayerState.mChildren;
+        final int N = mLayerState.mNum;
+        for (int i = 0; i < N; i++) {
+            array[i].mDrawable.removeHotspot(id);
+        }
+    }
+
+    /**
+     * @hide
+     */
+    @Override
+    public void clearHotspots() {
+        final ChildDrawable[] array = mLayerState.mChildren;
+        final int N = mLayerState.mNum;
+        for (int i = 0; i < N; i++) {
+            array[i].mDrawable.clearHotspots();
+        }
+    }
+
     private void computeStackedPadding(Rect padding) {
         padding.left = 0;
         padding.top = 0;
diff --git a/graphics/java/android/graphics/drawable/Ripple.java b/graphics/java/android/graphics/drawable/Ripple.java
index 543d2a6..cbe20dc 100644
--- a/graphics/java/android/graphics/drawable/Ripple.java
+++ b/graphics/java/android/graphics/drawable/Ripple.java
@@ -251,4 +251,13 @@
 
         return false;
     }
+
+    public void getBounds(Rect bounds) {
+        final int x = (int) mX;
+        final int y = (int) mY;
+        final int dX = Math.max(x, mBounds.right - x);
+        final int dY = Math.max(x, mBounds.bottom - y);
+        final int maxRadius = (int) Math.ceil(Math.sqrt(dX * dX + dY * dY));
+        bounds.set(x - maxRadius, y - maxRadius, x + maxRadius, y + maxRadius);
+    }
 }
diff --git a/graphics/java/android/graphics/drawable/TouchFeedbackDrawable.java b/graphics/java/android/graphics/drawable/TouchFeedbackDrawable.java
new file mode 100644
index 0000000..1bfdc4d
--- /dev/null
+++ b/graphics/java/android/graphics/drawable/TouchFeedbackDrawable.java
@@ -0,0 +1,371 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.graphics.drawable;
+
+import android.content.res.ColorStateList;
+import android.content.res.Resources;
+import android.content.res.TypedArray;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.ColorFilter;
+import android.graphics.Paint;
+import android.graphics.PixelFormat;
+import android.graphics.Rect;
+import android.graphics.Xfermode;
+import android.os.SystemClock;
+import android.util.AttributeSet;
+import android.util.DisplayMetrics;
+import android.util.SparseArray;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.IOException;
+import java.util.ArrayList;
+
+/**
+ * An extension of LayerDrawable that is intended to react to touch hotspots
+ * and reveal the second layer atop the first.
+ * <p>
+ * It can be defined in an XML file with the <code>&lt;reveal&gt;</code> element.
+ * Each Drawable in the transition is defined in a nested <code>&lt;item&gt;</code>.
+ * For more information, see the guide to <a href="{@docRoot}
+ * guide/topics/resources/drawable-resource.html">Drawable Resources</a>.
+ *
+ * @attr ref android.R.styleable#LayerDrawableItem_left
+ * @attr ref android.R.styleable#LayerDrawableItem_top
+ * @attr ref android.R.styleable#LayerDrawableItem_right
+ * @attr ref android.R.styleable#LayerDrawableItem_bottom
+ * @attr ref android.R.styleable#LayerDrawableItem_drawable
+ * @attr ref android.R.styleable#LayerDrawableItem_id
+ * @hide
+ */
+public class TouchFeedbackDrawable extends Drawable {
+    private final Rect mTempRect = new Rect();
+    private final Rect mPaddingRect = new Rect();
+
+    /** Current drawing bounds, used to compute dirty region. */
+    private final Rect mDrawingBounds = new Rect();
+
+    /** Current dirty bounds, union of current and previous drawing bounds. */
+    private final Rect mDirtyBounds = new Rect();
+
+    private final TouchFeedbackState mState;
+
+    /** Lazily-created map of touch hotspot IDs to ripples. */
+    private SparseArray<Ripple> mTouchedRipples;
+
+    /** Lazily-created list of actively animating ripples. */
+    private ArrayList<Ripple> mActiveRipples;
+
+    /** Lazily-created runnable for scheduling invalidation. */
+    private Runnable mAnimationRunnable;
+
+    /** Paint used to control appearance of ripples. */
+    private Paint mRipplePaint;
+
+    /** Target density of the display into which ripples are drawn. */
+    private int mTargetDensity;
+
+    /** Whether the animation runnable has been posted. */
+    private boolean mAnimating;
+
+    TouchFeedbackDrawable() {
+        this(new TouchFeedbackState(null), null);
+    }
+
+    TouchFeedbackDrawable(TouchFeedbackState state, Resources res) {
+        if (res != null) {
+            mTargetDensity = res.getDisplayMetrics().densityDpi;
+        } else if (state != null) {
+            mTargetDensity = state.mTargetDensity;
+        }
+
+        mState = state;
+    }
+
+    @Override
+    public void setColorFilter(ColorFilter cf) {
+        // Not supported.
+    }
+
+    @Override
+    public void setAlpha(int alpha) {
+        // Not supported.
+    }
+
+    @Override
+    public int getOpacity() {
+        return mActiveRipples != null && !mActiveRipples.isEmpty() ?
+                PixelFormat.TRANSLUCENT : PixelFormat.TRANSPARENT;
+    }
+
+    @Override
+    public boolean onStateChange(int[] stateSet) {
+        final ColorStateList stateList = mState.mColorStateList;
+        if (stateList != null && mRipplePaint != null) {
+            final int newColor = stateList.getColorForState(stateSet, 0);
+            final int oldColor = mRipplePaint.getColor();
+            if (oldColor != newColor) {
+                mRipplePaint.setColor(newColor);
+                invalidateSelf();
+                return true;
+            }
+        }
+
+        return false;
+    }
+
+    /**
+     * @hide
+     */
+    @Override
+    public boolean isProjected() {
+        return true;
+    }
+
+    @Override
+    public boolean isStateful() {
+        return mState.mColorStateList != null && mState.mColorStateList.isStateful();
+    }
+
+    /**
+     * Set the density at which this drawable will be rendered.
+     *
+     * @param density The density scale for this drawable.
+     */
+    public void setTargetDensity(int density) {
+        if (mTargetDensity != density) {
+            mTargetDensity = density == 0 ? DisplayMetrics.DENSITY_DEFAULT : density;
+            // TODO: Update density in ripples?
+            invalidateSelf();
+        }
+    }
+
+    @Override
+    public void inflate(Resources r, XmlPullParser parser, AttributeSet attrs)
+            throws XmlPullParserException, IOException {
+        super.inflate(r, parser, attrs);
+
+        final TypedArray a = r.obtainAttributes(attrs,
+                com.android.internal.R.styleable.ColorDrawable);
+        mState.mColorStateList = a.getColorStateList(
+                com.android.internal.R.styleable.ColorDrawable_color);
+        a.recycle();
+
+        mState.mXfermode = null; //new PorterDuffXfermode(Mode.SRC_ATOP);
+        mState.mProjected = false;
+    }
+
+    /**
+     * @hide until hotspot APIs are finalized
+     */
+    @Override
+    public boolean supportsHotspots() {
+        return true;
+    }
+
+    /**
+     * @hide until hotspot APIs are finalized
+     */
+    @Override
+    public void setHotspot(int id, float x, float y) {
+        if (mTouchedRipples == null) {
+            mTouchedRipples = new SparseArray<Ripple>();
+            mActiveRipples = new ArrayList<Ripple>();
+        }
+
+        final Ripple ripple = mTouchedRipples.get(id);
+        if (ripple == null) {
+            final Rect padding = mPaddingRect;
+            getPadding(padding);
+
+            final Rect bounds = getBounds();
+            final Ripple newRipple = new Ripple(bounds, padding, bounds.exactCenterX(),
+                    bounds.exactCenterY(), mTargetDensity);
+            newRipple.enter();
+
+            mActiveRipples.add(newRipple);
+            mTouchedRipples.put(id, newRipple);
+        } else {
+            //ripple.move(x, y);
+        }
+
+        scheduleAnimation();
+    }
+
+    /**
+     * @hide until hotspot APIs are finalized
+     */
+    @Override
+    public void removeHotspot(int id) {
+        if (mTouchedRipples == null) {
+            return;
+        }
+
+        final Ripple ripple = mTouchedRipples.get(id);
+        if (ripple != null) {
+            ripple.exit();
+
+            mTouchedRipples.remove(id);
+            scheduleAnimation();
+        }
+    }
+
+    /**
+     * @hide until hotspot APIs are finalized
+     */
+    @Override
+    public void clearHotspots() {
+        if (mTouchedRipples == null) {
+            return;
+        }
+
+        final int n = mTouchedRipples.size();
+        for (int i = 0; i < n; i++) {
+            final Ripple ripple = mTouchedRipples.valueAt(i);
+            ripple.exit();
+        }
+
+        if (n > 0) {
+            mTouchedRipples.clear();
+            scheduleAnimation();
+        }
+    }
+
+    /**
+     * Schedules the next animation, if necessary.
+     */
+    private void scheduleAnimation() {
+        if (mActiveRipples == null || mActiveRipples.isEmpty()) {
+            mAnimating = false;
+        } else if (!mAnimating) {
+            mAnimating = true;
+
+            if (mAnimationRunnable == null) {
+                mAnimationRunnable = new Runnable() {
+                    @Override
+                    public void run() {
+                        mAnimating = false;
+                        scheduleAnimation();
+                        invalidateSelf();
+                    }
+                };
+            }
+
+            scheduleSelf(mAnimationRunnable, SystemClock.uptimeMillis() + 1000 / 60);
+        }
+    }
+
+    @Override
+    public void draw(Canvas canvas) {
+        final ArrayList<Ripple> activeRipples = mActiveRipples;
+        if (activeRipples == null || activeRipples.isEmpty()) {
+            // Nothing to draw, we're done here.
+            return;
+        }
+
+        final ColorStateList stateList = mState.mColorStateList;
+        if (stateList == null) {
+            // No color, we're done here.
+            return;
+        }
+
+        final int color = stateList.getColorForState(getState(), Color.TRANSPARENT);
+        if (color == Color.TRANSPARENT) {
+            // No color, we're done here.
+            return;
+        }
+
+        if (mRipplePaint == null) {
+            mRipplePaint = new Paint();
+            mRipplePaint.setAntiAlias(true);
+        }
+
+        mRipplePaint.setXfermode(mState.mXfermode);
+        mRipplePaint.setColor(color);
+
+        final int restoreCount = canvas.save();
+
+        // Draw ripples directly onto the canvas.
+        int n = activeRipples.size();
+        for (int i = 0; i < n; i++) {
+            final Ripple ripple = activeRipples.get(i);
+            if (!ripple.active()) {
+                activeRipples.remove(i);
+                i--;
+                n--;
+            } else {
+                ripple.draw(canvas, mRipplePaint);
+            }
+        }
+
+        canvas.restoreToCount(restoreCount);
+    }
+
+    @Override
+    public Rect getDirtyBounds() {
+        final Rect dirtyBounds = mDirtyBounds;
+        final Rect drawingBounds = mDrawingBounds;
+        dirtyBounds.set(drawingBounds);
+        drawingBounds.setEmpty();
+
+        final Rect rippleBounds = mTempRect;
+        final ArrayList<Ripple> activeRipples = mActiveRipples;
+        if (activeRipples != null) {
+           final int N = activeRipples.size();
+           for (int i = 0; i < N; i++) {
+               activeRipples.get(i).getBounds(rippleBounds);
+               drawingBounds.union(rippleBounds);
+           }
+        }
+
+        dirtyBounds.union(drawingBounds);
+        return dirtyBounds;
+    }
+
+    private static class TouchFeedbackState extends ConstantState {
+        private ColorStateList mColorStateList;
+        private Xfermode mXfermode;
+        private int mTargetDensity;
+        private boolean mProjected;
+
+        public TouchFeedbackState(TouchFeedbackState orig) {
+            if (orig != null) {
+                mColorStateList = orig.mColorStateList;
+                mXfermode = orig.mXfermode;
+                mTargetDensity = orig.mTargetDensity;
+                mProjected = orig.mProjected;
+            }
+        }
+
+        @Override
+        public int getChangingConfigurations() {
+            return 0;
+        }
+
+        @Override
+        public Drawable newDrawable() {
+            return newDrawable(null);
+        }
+
+        @Override
+        public Drawable newDrawable(Resources res) {
+            return new TouchFeedbackDrawable(this, res);
+        }
+    }
+}
diff --git a/libs/hwui/font/Font.cpp b/libs/hwui/font/Font.cpp
index b0945c6..5187f8f 100644
--- a/libs/hwui/font/Font.cpp
+++ b/libs/hwui/font/Font.cpp
@@ -405,10 +405,10 @@
         // If it's still not valid, we couldn't cache it, so we shouldn't
         // draw garbage; also skip empty glyphs (spaces)
         if (cachedGlyph->mIsValid && cachedGlyph->mCacheTexture) {
-            float penX = x + positions[(glyphsCount << 1)];
-            float penY = y + positions[(glyphsCount << 1) + 1];
+            int penX = x + (int) roundf(positions[(glyphsCount << 1)]);
+            int penY = y + (int) roundf(positions[(glyphsCount << 1) + 1]);
 
-            (*this.*render)(cachedGlyph, roundf(penX), roundf(penY),
+            (*this.*render)(cachedGlyph, penX, penY,
                     bitmap, bitmapW, bitmapH, bounds, positions);
         }
 
diff --git a/media/jni/android_media_MediaMuxer.cpp b/media/jni/android_media_MediaMuxer.cpp
index 2c16a05..ea890c2 100644
--- a/media/jni/android_media_MediaMuxer.cpp
+++ b/media/jni/android_media_MediaMuxer.cpp
@@ -164,7 +164,7 @@
 }
 
 static void android_media_MediaMuxer_setLocation(
-        JNIEnv *env, jclass clazz, jint nativeObject, jint latitude, jint longitude) {
+        JNIEnv *env, jclass clazz, jlong nativeObject, jint latitude, jint longitude) {
     MediaMuxer* muxer = reinterpret_cast<MediaMuxer *>(nativeObject);
 
     status_t res = muxer->setLocation(latitude, longitude);
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaNames.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaNames.java
index ee867ff..d01f4ec 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaNames.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaNames.java
@@ -137,6 +137,8 @@
     public static final String INVALD_VIDEO_PATH =
             "/sdcard/media_api/filepathdoesnotexist" + "/filepathdoesnotexist/temp.3gp";
 
+    public static final String RECORDED_SURFACE_3GP = "/sdcard/surface.3gp";
+
     public static final long RECORDED_TIME = 5000;
     public static final long VALID_VIDEO_DURATION = 2000;
 
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaProfileReader.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaProfileReader.java
index abe8b8c..54c8add 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaProfileReader.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaProfileReader.java
@@ -88,7 +88,8 @@
         if (audioEncoder != MediaRecorder.AudioEncoder.AMR_NB &&
             audioEncoder != MediaRecorder.AudioEncoder.AMR_WB &&
             audioEncoder != MediaRecorder.AudioEncoder.AAC &&
-            audioEncoder != MediaRecorder.AudioEncoder.HE_AAC) {
+            audioEncoder != MediaRecorder.AudioEncoder.HE_AAC &&
+            audioEncoder != MediaRecorder.AudioEncoder.AAC_ELD) {
             throw new IllegalArgumentException("Unsupported audio encodeer " + audioEncoder);
         }
         return audioEncoderMap.get(audioEncoder);
@@ -128,5 +129,6 @@
         audioEncoderMap.put(MediaRecorder.AudioEncoder.AMR_WB, "amrwb");
         audioEncoderMap.put(MediaRecorder.AudioEncoder.AAC, "aac");
         audioEncoderMap.put(MediaRecorder.AudioEncoder.HE_AAC, "heaac");
+        audioEncoderMap.put(MediaRecorder.AudioEncoder.AAC_ELD, "aaceld");
     }
 }
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/mediarecorder/MediaRecorderTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/mediarecorder/MediaRecorderTest.java
index 8e6d5cb..599522b 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/mediarecorder/MediaRecorderTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/mediarecorder/MediaRecorderTest.java
@@ -22,6 +22,10 @@
 import java.io.*;
 
 import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.graphics.Typeface;
 import android.hardware.Camera;
 import android.media.MediaPlayer;
 import android.media.MediaRecorder;
@@ -30,6 +34,7 @@
 import android.media.EncoderCapabilities.AudioEncoderCap;
 import android.test.ActivityInstrumentationTestCase2;
 import android.util.Log;
+import android.view.Surface;
 import android.view.SurfaceHolder;
 import android.view.SurfaceView;
 import com.android.mediaframeworktest.MediaProfileReader;
@@ -41,14 +46,14 @@
 
 
 /**
- * Junit / Instrumentation test case for the media recorder api 
- */  
+ * Junit / Instrumentation test case for the media recorder api
+ */
 public class MediaRecorderTest extends ActivityInstrumentationTestCase2<MediaFrameworkTest> {
     private String TAG = "MediaRecorderTest";
     private int mOutputDuration =0;
     private int mOutputVideoWidth = 0;
     private int mOutputVideoHeight= 0 ;
-    
+
     private SurfaceHolder mSurfaceHolder = null;
     private MediaRecorder mRecorder;
 
@@ -58,10 +63,10 @@
 
     Context mContext;
     Camera mCamera;
-  
+
     public MediaRecorderTest() {
-        super("com.android.mediaframeworktest", MediaFrameworkTest.class);
-       
+        super(MediaFrameworkTest.class);
+
     }
 
     protected void setUp() throws Exception {
@@ -69,8 +74,8 @@
         mRecorder = new MediaRecorder();
         super.setUp();
     }
- 
-    private void recordVideo(int frameRate, int width, int height, 
+
+    private void recordVideo(int frameRate, int width, int height,
             int videoFormat, int outFormat, String outFile, boolean videoOnly) {
         Log.v(TAG,"startPreviewAndPrepareRecording");
         try {
@@ -80,7 +85,7 @@
             }
             mRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
             mRecorder.setOutputFormat(outFormat);
-            Log.v(TAG, "output format " + outFormat);          
+            Log.v(TAG, "output format " + outFormat);
             mRecorder.setOutputFile(outFile);
             mRecorder.setVideoFrameRate(frameRate);
             mRecorder.setVideoSize(width, height);
@@ -105,7 +110,180 @@
             mRecorder.release();
         }
     }
-    
+
+    private boolean validateGetSurface(boolean useSurface) {
+        Log.v(TAG,"validateGetSurface, useSurface=" + useSurface);
+        MediaRecorder recorder = new MediaRecorder();
+        Surface surface;
+        boolean success = true;
+        try {
+            /* initialization */
+            if (!useSurface) {
+                mCamera = Camera.open(CAMERA_ID);
+                Camera.Parameters parameters = mCamera.getParameters();
+                parameters.setPreviewSize(352, 288);
+                parameters.set("orientation", "portrait");
+                mCamera.setParameters(parameters);
+                mCamera.unlock();
+                recorder.setCamera(mCamera);
+                mSurfaceHolder = MediaFrameworkTest.mSurfaceView.getHolder();
+                recorder.setPreviewDisplay(mSurfaceHolder.getSurface());
+            }
+
+            recorder.setAudioSource(MediaRecorder.AudioSource.MIC);
+            int videoSource = useSurface ?
+                    MediaRecorder.VideoSource.SURFACE :
+                    MediaRecorder.VideoSource.CAMERA;
+            recorder.setVideoSource(videoSource);
+            recorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
+            recorder.setOutputFile(MediaNames.RECORDED_SURFACE_3GP);
+            recorder.setVideoFrameRate(30);
+            recorder.setVideoSize(352, 288);
+            recorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264);
+            recorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
+
+            /* Test: getSurface() before prepare()
+             * should throw IllegalStateException
+             */
+            try {
+                surface = recorder.getSurface();
+                throw new Exception("getSurface failed to throw IllegalStateException");
+            } catch (IllegalStateException e) {
+                // OK
+            }
+
+            recorder.prepare();
+
+            /* Test: getSurface() after prepare()
+             * should succeed for surface source
+             * should fail for camera source
+             */
+            try {
+                surface = recorder.getSurface();
+                if (!useSurface) {
+                    throw new Exception("getSurface failed to throw IllegalStateException");
+                }
+            } catch (IllegalStateException e) {
+                if (useSurface) {
+                    throw new Exception("getSurface failed to throw IllegalStateException");
+                }
+            }
+
+            recorder.start();
+
+            /* Test: getSurface() after start()
+             * should succeed for surface source
+             * should fail for camera source
+             */
+            try {
+                surface = recorder.getSurface();
+                if (!useSurface) {
+                    throw new Exception("getSurface failed to throw IllegalStateException");
+                }
+            } catch (IllegalStateException e) {
+                if (useSurface) {
+                    throw new Exception("getSurface failed to throw IllegalStateException");
+                }
+            }
+
+            try {
+                recorder.stop();
+            } catch (Exception e) {
+                // stop() could fail if the recording is empty, as we didn't render anything.
+                // ignore any failure in stop, we just want it stopped.
+            }
+
+            /* Test: getSurface() after stop()
+             * should throw IllegalStateException
+             */
+            try {
+                surface = recorder.getSurface();
+                throw new Exception("getSurface failed to throw IllegalStateException");
+            } catch (IllegalStateException e) {
+                // OK
+            }
+        } catch (Exception e) {
+            // fail
+            success = false;
+        }
+
+        try {
+            if (mCamera != null) {
+                mCamera.lock();
+                mCamera.release();
+                mCamera = null;
+            }
+            recorder.release();
+        } catch (Exception e) {
+            success = false;
+        }
+
+        return success;
+    }
+
+    private boolean recordVideoFromSurface(int frameRate, int width, int height,
+            int videoFormat, int outFormat, String outFile, boolean videoOnly) {
+        Log.v(TAG,"recordVideoFromSurface");
+        MediaRecorder recorder = new MediaRecorder();
+        try {
+            if (!videoOnly) {
+                recorder.setAudioSource(MediaRecorder.AudioSource.MIC);
+            }
+            recorder.setVideoSource(MediaRecorder.VideoSource.SURFACE);
+            recorder.setOutputFormat(outFormat);
+            recorder.setOutputFile(outFile);
+            recorder.setVideoFrameRate(frameRate);
+            recorder.setVideoSize(width, height);
+            recorder.setVideoEncoder(videoFormat);
+            if (!videoOnly) {
+                recorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
+            }
+            recorder.prepare();
+            Surface surface = recorder.getSurface();
+
+            Paint paint = new Paint();
+            paint.setTextSize(16);
+            paint.setColor(Color.RED);
+            int i;
+
+            /* Test: draw 10 frames at 30fps before start
+             * these should be dropped and not causing malformed stream.
+             */
+            for(i = 0; i < 10; i++) {
+                Canvas canvas = surface.lockCanvas(null);
+                int background = (i * 255 / 99);
+                canvas.drawARGB(255, background, background, background);
+                String text = "Frame #" + i;
+                canvas.drawText(text, 100, 100, paint);
+                surface.unlockCanvasAndPost(canvas);
+                Thread.sleep(33);
+            }
+
+            Log.v(TAG, "start");
+            recorder.start();
+
+            /* Test: draw another 90 frames at 30fps after start */
+            for(i = 10; i < 100; i++) {
+                Canvas canvas = surface.lockCanvas(null);
+                int background = (i * 255 / 99);
+                canvas.drawARGB(255, background, background, background);
+                String text = "Frame #" + i;
+                canvas.drawText(text, 100, 100, paint);
+                surface.unlockCanvasAndPost(canvas);
+                Thread.sleep(33);
+            }
+
+            Log.v(TAG, "stop");
+            recorder.stop();
+            recorder.release();
+        } catch (Exception e) {
+            Log.v("record video failed ", e.toString());
+            recorder.release();
+            return false;
+        }
+        return true;
+    }
+
     private boolean recordVideoWithPara(VideoEncoderCap videoCap, AudioEncoderCap audioCap, boolean highQuality){
         boolean recordSuccess = false;
         int videoEncoder = videoCap.mCodec;
@@ -171,7 +349,7 @@
         return recordSuccess;
     }
 
-    private boolean invalidRecordSetting(int frameRate, int width, int height, 
+    private boolean invalidRecordSetting(int frameRate, int width, int height,
             int videoFormat, int outFormat, String outFile, boolean videoOnly) {
         try {
             if (!videoOnly) {
@@ -180,7 +358,7 @@
             }
             mRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
             mRecorder.setOutputFormat(outFormat);
-            Log.v(TAG, "output format " + outFormat);          
+            Log.v(TAG, "output format " + outFormat);
             mRecorder.setOutputFile(outFile);
             mRecorder.setVideoFrameRate(frameRate);
             mRecorder.setVideoSize(width, height);
@@ -208,7 +386,7 @@
         }
         return false;
     }
-    
+
     private void getOutputVideoProperty(String outputFilePath) {
         MediaPlayer mediaPlayer = new MediaPlayer();
         try {
@@ -223,13 +401,13 @@
             Thread.sleep(1000);
             mOutputVideoHeight = mediaPlayer.getVideoHeight();
             mOutputVideoWidth = mediaPlayer.getVideoWidth();
-            mediaPlayer.release();    
+            mediaPlayer.release();
         } catch (Exception e) {
             Log.v(TAG, e.toString());
             mediaPlayer.release();
-        }       
+        }
     }
-    
+
     private boolean validateVideo(String filePath, int width, int height) {
         boolean validVideo = false;
         getOutputVideoProperty(filePath);
@@ -260,7 +438,7 @@
             int codec = MediaRecorder.VideoEncoder.H263;
             int frameRate = MediaProfileReader.getMaxFrameRateForCodec(codec);
             recordVideo(frameRate, 352, 288, codec,
-                    MediaRecorder.OutputFormat.THREE_GPP, 
+                    MediaRecorder.OutputFormat.THREE_GPP,
                     MediaNames.RECORDED_PORTRAIT_H263, true);
             mCamera.lock();
             mCamera.release();
@@ -271,15 +449,15 @@
         }
         assertTrue("PortraitH263", videoRecordedResult);
     }
-    
+
     @LargeTest
-    public void testInvalidVideoPath() throws Exception {       
+    public void testInvalidVideoPath() throws Exception {
         boolean isTestInvalidVideoPathSuccessful = false;
-        isTestInvalidVideoPathSuccessful = invalidRecordSetting(15, 176, 144, MediaRecorder.VideoEncoder.H263, 
-               MediaRecorder.OutputFormat.THREE_GPP, MediaNames.INVALD_VIDEO_PATH, false);      
+        isTestInvalidVideoPathSuccessful = invalidRecordSetting(15, 176, 144, MediaRecorder.VideoEncoder.H263,
+               MediaRecorder.OutputFormat.THREE_GPP, MediaNames.INVALD_VIDEO_PATH, false);
         assertTrue("Invalid outputFile Path", isTestInvalidVideoPathSuccessful);
     }
-    
+
     @LargeTest
     //test cases for the new codec
     public void testDeviceSpecificCodec() throws Exception {
@@ -309,4 +487,49 @@
             assertTrue("testDeviceSpecificCodec", false);
         }
     }
+
+    // Test MediaRecorder.getSurface() api with surface or camera source
+    public void testGetSurfaceApi() {
+        boolean success = false;
+        int noOfFailure = 0;
+        try {
+            for (int k = 0; k < 2; k++) {
+                success = validateGetSurface(
+                        k == 0 ? true : false /* useSurface */);
+                if (!success) {
+                    noOfFailure++;
+                }
+            }
+        } catch (Exception e) {
+            Log.v(TAG, e.toString());
+        }
+        assertTrue("testGetSurfaceApi", noOfFailure == 0);
+    }
+
+    // Test recording from surface source with/without audio
+    public void testSurfaceRecording() {
+        boolean success = false;
+        int noOfFailure = 0;
+        try {
+            int codec = MediaRecorder.VideoEncoder.H264;
+            int frameRate = MediaProfileReader.getMaxFrameRateForCodec(codec);
+            for (int k = 0; k < 2; k++) {
+                String filename = "/sdcard/surface_" +
+                            (k==0?"video_only":"with_audio") + ".3gp";
+
+                success = recordVideoFromSurface(frameRate, 352, 288, codec,
+                        MediaRecorder.OutputFormat.THREE_GPP, filename,
+                        k == 0 ? true : false /* videoOnly */);
+                if (success) {
+                    success = validateVideo(filename, 352, 288);
+                }
+                if (!success) {
+                    noOfFailure++;
+                }
+            }
+        } catch (Exception e) {
+            Log.v(TAG, e.toString());
+        }
+        assertTrue("testSurfaceRecording", noOfFailure == 0);
+    }
 }
diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml
index 70b30e6..d407a2c 100644
--- a/packages/SystemUI/res/values-fr/strings.xml
+++ b/packages/SystemUI/res/values-fr/strings.xml
@@ -192,7 +192,7 @@
     <string name="quick_settings_location_off_label" msgid="7464544086507331459">"Localisation désactivée"</string>
     <string name="quick_settings_media_device_label" msgid="1302906836372603762">"Appareil multimédia"</string>
     <string name="quick_settings_rssi_label" msgid="7725671335550695589">"RSSI"</string>
-    <string name="quick_settings_rssi_emergency_only" msgid="2713774041672886750">"Appels d\'urgence uniquement"</string>
+    <string name="quick_settings_rssi_emergency_only" msgid="2713774041672886750">"Appels d\'urgence"</string>
     <string name="quick_settings_settings_label" msgid="5326556592578065401">"Paramètres"</string>
     <string name="quick_settings_time_label" msgid="4635969182239736408">"Heure"</string>
     <string name="quick_settings_user_label" msgid="5238995632130897840">"Moi"</string>
@@ -200,7 +200,7 @@
     <string name="quick_settings_wifi_not_connected" msgid="7171904845345573431">"Non connecté"</string>
     <string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"Aucun réseau"</string>
     <string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi désactivé"</string>
-    <string name="quick_settings_remote_display_no_connection_label" msgid="372107699274391290">"Écran sur lequel l\'affichage est diffusé"</string>
+    <string name="quick_settings_remote_display_no_connection_label" msgid="372107699274391290">"Diffuser l\'écran"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Luminosité"</string>
     <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTOMATIQUE"</string>
     <string name="quick_settings_inversion_label" msgid="1666358784283020762">"Mode d\'inversion des couleurs"</string>
diff --git a/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java b/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
index 5579e19..eb2c44a 100755
--- a/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
+++ b/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
@@ -68,6 +68,7 @@
 
     private final Path mShapePath = new Path();
     private final Path mClipPath = new Path();
+    private final Path mTextPath = new Path();
 
     private class BatteryTracker extends BroadcastReceiver {
         public static final int UNKNOWN_LEVEL = -1;
@@ -190,9 +191,6 @@
         colors.recycle();
         mShowPercent = ENABLE_PERCENT && 0 != Settings.System.getInt(
                 context.getContentResolver(), "status_bar_show_battery_percent", 0);
-        if (mShowPercent) {
-            setLayerType(View.LAYER_TYPE_SOFTWARE, null);
-        }
         mWarningString = context.getString(R.string.battery_meter_very_low_overlay_symbol);
 
         mFramePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
@@ -353,6 +351,29 @@
             }
         }
 
+        // compute percentage text
+        boolean pctOpaque = false;
+        float pctX = 0, pctY = 0;
+        String pctText = null;
+        if (!tracker.plugged && level > EMPTY && mShowPercent
+                && !(tracker.level == 100 && !SHOW_100_PERCENT)) {
+            mTextPaint.setColor(getColorForLevel(level));
+            mTextPaint.setTextSize(height *
+                    (SINGLE_DIGIT_PERCENT ? 0.75f
+                            : (tracker.level == 100 ? 0.38f : 0.5f)));
+            mTextHeight = -mTextPaint.getFontMetrics().ascent;
+            pctText = String.valueOf(SINGLE_DIGIT_PERCENT ? (level/10) : level);
+            pctX = mWidth * 0.5f;
+            pctY = (mHeight + mTextHeight) * 0.47f;
+            pctOpaque = levelTop > pctY;
+            if (!pctOpaque) {
+                mTextPath.reset();
+                mTextPaint.getTextPath(pctText, 0, pctText.length(), pctX, pctY, mTextPath);
+                // cut the percentage text out of the overall shape
+                mShapePath.op(mTextPath, Path.Op.DIFFERENCE);
+            }
+        }
+
         // draw the battery shape background
         c.drawPath(mShapePath, mFramePaint);
 
@@ -369,29 +390,9 @@
                 final float x = mWidth * 0.5f;
                 final float y = (mHeight + mWarningTextHeight) * 0.48f;
                 c.drawText(mWarningString, x, y, mWarningTextPaint);
-            } else if (mShowPercent && !(tracker.level == 100 && !SHOW_100_PERCENT)) {
+            } else if (pctOpaque) {
                 // draw the percentage text
-                mTextPaint.setColor(getColorForLevel(level));
-                mTextPaint.setTextSize(height *
-                        (SINGLE_DIGIT_PERCENT ? 0.75f
-                                : (tracker.level == 100 ? 0.38f : 0.5f)));
-                mTextHeight = -mTextPaint.getFontMetrics().ascent;
-
-                final String str = String.valueOf(SINGLE_DIGIT_PERCENT ? (level/10) : level);
-                final float x = mWidth * 0.5f;
-                final float y = (mHeight + mTextHeight) * 0.47f;
-
-                boolean opaque = levelTop > y;
-                if (opaque) {
-                    mTextPaint.setXfermode(null);
-                } else {
-                    mTextPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT));
-                }
-
-                c.drawText(str,
-                        x,
-                        y,
-                        mTextPaint);
+                c.drawText(pctText, pctX, pctY, mTextPaint);
             }
         }
     }
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 b72c25d..44e7dac 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -1914,7 +1914,7 @@
             }
             if (sbModeChanged || nbModeChanged) {
                 // update transient bar autohide
-                if (sbMode == MODE_SEMI_TRANSPARENT || nbMode == MODE_SEMI_TRANSPARENT) {
+                if (mStatusBarMode == MODE_SEMI_TRANSPARENT || mNavigationBarMode == MODE_SEMI_TRANSPARENT) {
                     scheduleAutohide();
                 } else {
                     cancelAutohide();
diff --git a/policy/src/com/android/internal/policy/impl/BarController.java b/policy/src/com/android/internal/policy/impl/BarController.java
index 0ce4b12..fc49a569 100644
--- a/policy/src/com/android/internal/policy/impl/BarController.java
+++ b/policy/src/com/android/internal/policy/impl/BarController.java
@@ -108,7 +108,7 @@
         if (mWin != null) {
             if (win != null && (win.getAttrs().privateFlags
                     & WindowManager.LayoutParams.PRIVATE_FLAG_INHERIT_TRANSLUCENT_DECOR) == 0) {
-                if ((win.getAttrs().flags & mTranslucentWmFlag) != 0) {
+                if ((PolicyControl.getWindowFlags(win, null) & mTranslucentWmFlag) != 0) {
                     vis |= mTranslucentFlag;
                 } else {
                     vis &= ~mTranslucentFlag;
diff --git a/policy/src/com/android/internal/policy/impl/ImmersiveModeConfirmation.java b/policy/src/com/android/internal/policy/impl/ImmersiveModeConfirmation.java
index b734c41..507d385 100644
--- a/policy/src/com/android/internal/policy/impl/ImmersiveModeConfirmation.java
+++ b/policy/src/com/android/internal/policy/impl/ImmersiveModeConfirmation.java
@@ -117,7 +117,7 @@
     }
 
     public void immersiveModeChanged(String pkg, boolean isImmersiveMode) {
-        if (pkg == null) {
+        if (pkg == null || PolicyControl.disableImmersiveConfirmation(pkg)) {
             return;
         }
         mHandler.removeMessages(H.SHOW);
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
index ce6166a..b6a4052 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
@@ -526,6 +526,9 @@
             resolver.registerContentObserver(Settings.System.getUriFor(
                     Settings.Secure.IMMERSIVE_MODE_CONFIRMATIONS), false, this,
                     UserHandle.USER_ALL);
+            resolver.registerContentObserver(Settings.Global.getUriFor(
+                    Settings.Global.POLICY_CONTROL), false, this,
+                    UserHandle.USER_ALL);
             updateSettings();
         }
 
@@ -1167,6 +1170,7 @@
             if (mImmersiveModeConfirmation != null) {
                 mImmersiveModeConfirmation.loadSetting();
             }
+            PolicyControl.reloadFromSetting(mContext);
         }
         if (updateRotation) {
             updateRotation(true);
@@ -2564,7 +2568,7 @@
 
     @Override
     public void getContentInsetHintLw(WindowManager.LayoutParams attrs, Rect contentInset) {
-        final int fl = attrs.flags;
+        final int fl = PolicyControl.getWindowFlags(null, attrs);
         final int systemUiVisibility = (attrs.systemUiVisibility|attrs.subtreeSystemUiVisibility);
 
         if ((fl & (FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR))
@@ -2737,7 +2741,8 @@
                         // We currently want to hide the navigation UI.
                         mNavigationBarController.setBarShowingLw(false);
                     }
-                    if (navVisible && !navTranslucent && !mNavigationBar.isAnimatingLw()
+                    if (navVisible && !navTranslucent && !navAllowedHidden
+                            && !mNavigationBar.isAnimatingLw()
                             && !mNavigationBarController.wasRecentlyTranslucent()) {
                         // If the opaque nav bar is currently requested to be visible,
                         // and not in the process of animating on or off, then
@@ -2946,9 +2951,9 @@
             offsetInputMethodWindowLw(mLastInputMethodWindow);
         }
 
-        final int fl = attrs.flags;
+        final int fl = PolicyControl.getWindowFlags(win, attrs);
         final int sim = attrs.softInputMode;
-        final int sysUiFl = win.getSystemUiVisibility();
+        final int sysUiFl = PolicyControl.getSystemUiVisibility(win);
 
         final Rect pf = mTmpParentFrame;
         final Rect df = mTmpDisplayFrame;
@@ -3366,6 +3371,7 @@
                                 WindowManager.LayoutParams attrs) {
         if (DEBUG_LAYOUT) Slog.i(TAG, "Win " + win + ": isVisibleOrBehindKeyguardLw="
                 + win.isVisibleOrBehindKeyguardLw());
+        final int fl = PolicyControl.getWindowFlags(win, attrs);
         if (mTopFullscreenOpaqueWindowState == null
                 && win.isVisibleLw() && attrs.type == TYPE_INPUT_METHOD) {
             mForcingShowNavBar = true;
@@ -3373,7 +3379,7 @@
         }
         if (mTopFullscreenOpaqueWindowState == null &&
                 win.isVisibleOrBehindKeyguardLw() && !win.isGoneForLayoutLw()) {
-            if ((attrs.flags & FLAG_FORCE_NOT_FULLSCREEN) != 0) {
+            if ((fl & FLAG_FORCE_NOT_FULLSCREEN) != 0) {
                 if (attrs.type == TYPE_KEYGUARD) {
                     mForceStatusBarFromKeyguard = true;
                 } else {
@@ -3400,12 +3406,12 @@
                     && attrs.height == WindowManager.LayoutParams.MATCH_PARENT) {
                 if (DEBUG_LAYOUT) Slog.v(TAG, "Fullscreen window: " + win);
                 mTopFullscreenOpaqueWindowState = win;
-                if ((attrs.flags & FLAG_SHOW_WHEN_LOCKED) != 0) {
+                if ((fl & FLAG_SHOW_WHEN_LOCKED) != 0) {
                     if (DEBUG_LAYOUT) Slog.v(TAG, "Setting mHideLockScreen to true by win " + win);
                     mHideLockScreen = true;
                     mForceStatusBarFromKeyguard = false;
                 }
-                if ((attrs.flags & FLAG_DISMISS_KEYGUARD) != 0
+                if ((fl & FLAG_DISMISS_KEYGUARD) != 0
                         && mDismissKeyguard == DISMISS_KEYGUARD_NONE) {
                     if (DEBUG_LAYOUT) Slog.v(TAG, "Setting mDismissKeyguard true by win " + win);
                     mDismissKeyguard = mWinDismissingKeyguard == win ?
@@ -3413,7 +3419,7 @@
                     mWinDismissingKeyguard = win;
                     mForceStatusBarFromKeyguard = mShowingLockscreen && isKeyguardSecure();
                 }
-                if ((attrs.flags & FLAG_ALLOW_LOCK_WHILE_SCREEN_ON) != 0) {
+                if ((fl & FLAG_ALLOW_LOCK_WHILE_SCREEN_ON) != 0) {
                     mAllowLockscreenWhenOn = true;
                 }
             }
@@ -3455,13 +3461,14 @@
                             mLastSystemUiFlags, mLastSystemUiFlags);
                 }
             } else if (mTopFullscreenOpaqueWindowState != null) {
+                final int fl = PolicyControl.getWindowFlags(null, lp);
                 if (localLOGV) {
                     Slog.d(TAG, "frame: " + mTopFullscreenOpaqueWindowState.getFrameLw()
                             + " shown frame: " + mTopFullscreenOpaqueWindowState.getShownFrameLw());
                     Slog.d(TAG, "attr: " + mTopFullscreenOpaqueWindowState.getAttrs()
-                            + " lp.flags=0x" + Integer.toHexString(lp.flags));
+                            + " lp.flags=0x" + Integer.toHexString(fl));
                 }
-                topIsFullscreen = (lp.flags & WindowManager.LayoutParams.FLAG_FULLSCREEN) != 0
+                topIsFullscreen = (fl & WindowManager.LayoutParams.FLAG_FULLSCREEN) != 0
                         || (mLastSystemUiFlags & View.SYSTEM_UI_FLAG_FULLSCREEN) != 0;
                 // The subtle difference between the window for mTopFullscreenOpaqueWindowState
                 // and mTopIsFullscreen is that that mTopIsFullscreen is set only if the window
@@ -5061,11 +5068,11 @@
             return 0;
         }
 
-        int tmpVisibility = win.getSystemUiVisibility()
+        int tmpVisibility = PolicyControl.getSystemUiVisibility(win)
                 & ~mResettingSystemUiFlags
                 & ~mForceClearedSystemUiFlags;
         if (mForcingShowNavBar && win.getSurfaceLayer() < mForcingShowNavBarLayer) {
-            tmpVisibility &= ~View.SYSTEM_UI_CLEARABLE_FLAGS;
+            tmpVisibility &= ~PolicyControl.adjustClearableFlags(win, View.SYSTEM_UI_CLEARABLE_FLAGS);
         }
         final int visibility = updateSystemBarsLw(win, mLastSystemUiFlags, tmpVisibility);
         final int diff = visibility ^ mLastSystemUiFlags;
@@ -5124,7 +5131,7 @@
                 (vis & View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY) != 0;
         boolean hideStatusBarWM =
                 mTopFullscreenOpaqueWindowState != null &&
-                (mTopFullscreenOpaqueWindowState.getAttrs().flags
+                (PolicyControl.getWindowFlags(mTopFullscreenOpaqueWindowState, null)
                         & WindowManager.LayoutParams.FLAG_FULLSCREEN) != 0;
         boolean hideStatusBarSysui =
                 (vis & View.SYSTEM_UI_FLAG_FULLSCREEN) != 0;
@@ -5412,5 +5419,6 @@
         pw.print(prefix); pw.print("mUndockedHdmiRotation="); pw.println(mUndockedHdmiRotation);
         mStatusBarController.dump(pw, prefix);
         mNavigationBarController.dump(pw, prefix);
+        PolicyControl.dump(prefix, pw);
     }
 }
diff --git a/policy/src/com/android/internal/policy/impl/PolicyControl.java b/policy/src/com/android/internal/policy/impl/PolicyControl.java
new file mode 100644
index 0000000..e6a7d76
--- /dev/null
+++ b/policy/src/com/android/internal/policy/impl/PolicyControl.java
@@ -0,0 +1,253 @@
+/*
+ * 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.
+ */
+
+package com.android.internal.policy.impl;
+
+import android.content.Context;
+import android.os.UserHandle;
+import android.provider.Settings;
+import android.util.ArraySet;
+import android.util.Slog;
+import android.view.View;
+import android.view.WindowManager;
+import android.view.WindowManager.LayoutParams;
+import android.view.WindowManagerPolicy.WindowState;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+
+/**
+ * Runtime adjustments applied to the global window policy.
+ *
+ * This includes forcing immersive mode behavior for one or both system bars (based on a package
+ * list) and permanently disabling immersive mode confirmations for specific packages.
+ *
+ * Control by setting {@link Settings.Global.POLICY_CONTROL} to one or more name-value pairs.
+ * e.g.
+ *   to force immersive mode everywhere:
+ *     "immersive.full=*"
+ *   to force transient status for all apps except a specific package:
+ *     "immersive.status=apps,-com.package"
+ *   to disable the immersive mode confirmations for specific packages:
+ *     "immersive.preconfirms=com.package.one,com.package.two"
+ *
+ * Separate multiple name-value pairs with ':'
+ *   e.g. "immersive.status=apps:immersive.preconfirms=*"
+ */
+public class PolicyControl {
+    private static String TAG = "PolicyControl";
+    private static boolean DEBUG = false;
+
+    private static final String NAME_IMMERSIVE_FULL = "immersive.full";
+    private static final String NAME_IMMERSIVE_STATUS = "immersive.status";
+    private static final String NAME_IMMERSIVE_NAVIGATION = "immersive.navigation";
+    private static final String NAME_IMMERSIVE_PRECONFIRMATIONS = "immersive.preconfirms";
+
+    private static String sSettingValue;
+    private static Filter sImmersivePreconfirmationsFilter;
+    private static Filter sImmersiveStatusFilter;
+    private static Filter sImmersiveNavigationFilter;
+
+    public static int getSystemUiVisibility(WindowState win) {
+        int vis = win.getSystemUiVisibility();
+        if (sImmersiveStatusFilter != null && sImmersiveStatusFilter.matches(win)) {
+            vis |= View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
+                    | View.SYSTEM_UI_FLAG_FULLSCREEN
+                    | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
+            vis &= ~(View.SYSTEM_UI_FLAG_LAYOUT_STABLE
+                    | View.STATUS_BAR_TRANSLUCENT);
+        }
+        if (sImmersiveNavigationFilter != null && sImmersiveNavigationFilter.matches(win)) {
+            vis |= View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
+                    | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
+                    | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION;
+            vis &= ~(View.SYSTEM_UI_FLAG_LAYOUT_STABLE
+                    | View.NAVIGATION_BAR_TRANSLUCENT);
+        }
+        return vis;
+    }
+
+    public static int getWindowFlags(WindowState win, LayoutParams attrs) {
+        int flags = (attrs != null ? attrs : win.getAttrs()).flags;
+        if (sImmersiveStatusFilter != null && sImmersiveStatusFilter.matches(win)) {
+            flags |= WindowManager.LayoutParams.FLAG_FULLSCREEN;
+            flags &= ~(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS
+                    | WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN);
+        }
+        if (sImmersiveNavigationFilter != null && sImmersiveNavigationFilter.matches(win)) {
+            flags &= ~WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION;
+        }
+        return flags;
+    }
+
+    public static int adjustClearableFlags(WindowState win, int clearableFlags) {
+        if (sImmersiveStatusFilter != null && sImmersiveStatusFilter.matches(win)) {
+            clearableFlags &= ~View.SYSTEM_UI_FLAG_FULLSCREEN;
+        }
+        return clearableFlags;
+    }
+
+    public static boolean disableImmersiveConfirmation(String pkg) {
+        return sImmersivePreconfirmationsFilter != null
+                && sImmersivePreconfirmationsFilter.matches(pkg);
+    }
+
+    public static void reloadFromSetting(Context context) {
+        if (DEBUG) Slog.d(TAG, "reloadFromSetting()");
+        String value = null;
+        try {
+            value = Settings.Global.getStringForUser(context.getContentResolver(),
+                    Settings.Global.POLICY_CONTROL,
+                    UserHandle.USER_CURRENT);
+            if (sSettingValue != null && sSettingValue.equals(value)) return;
+            setFilters(value);
+            sSettingValue = value;
+        } catch (Throwable t) {
+            Slog.w(TAG, "Error loading policy control, value=" + value, t);
+        }
+    }
+
+    public static void dump(String prefix, PrintWriter pw) {
+        dump("sImmersiveStatusFilter", sImmersiveStatusFilter, prefix, pw);
+        dump("sImmersiveNavigationFilter", sImmersiveNavigationFilter, prefix, pw);
+        dump("sImmersivePreconfirmationsFilter", sImmersivePreconfirmationsFilter, prefix, pw);
+    }
+
+    private static void dump(String name, Filter filter, String prefix, PrintWriter pw) {
+        pw.print(prefix); pw.print("PolicyControl."); pw.print(name); pw.print('=');
+        if (filter == null) {
+            pw.println("null");
+        } else {
+            filter.dump(pw); pw.println();
+        }
+    }
+
+    private static void setFilters(String value) {
+        if (DEBUG) Slog.d(TAG, "setFilters: " + value);
+        sImmersiveStatusFilter = null;
+        sImmersiveNavigationFilter = null;
+        sImmersivePreconfirmationsFilter = null;
+        String[] nvps = value.split(":");
+        for (String nvp : nvps) {
+            int i = nvp.indexOf('=');
+            if (i == -1) continue;
+            String n = nvp.substring(0, i);
+            String v = nvp.substring(i + 1);
+            if (n.equals(NAME_IMMERSIVE_FULL)) {
+                Filter f = Filter.parse(v);
+                sImmersiveStatusFilter = sImmersiveNavigationFilter = f;
+                if (sImmersivePreconfirmationsFilter == null) {
+                    sImmersivePreconfirmationsFilter = f;
+                }
+            } else if (n.equals(NAME_IMMERSIVE_STATUS)) {
+                Filter f = Filter.parse(v);
+                sImmersiveStatusFilter = f;
+            } else if (n.equals(NAME_IMMERSIVE_NAVIGATION)) {
+                Filter f = Filter.parse(v);
+                sImmersiveNavigationFilter = f;
+                if (sImmersivePreconfirmationsFilter == null) {
+                    sImmersivePreconfirmationsFilter = f;
+                }
+            } else if (n.equals(NAME_IMMERSIVE_PRECONFIRMATIONS)) {
+                Filter f = Filter.parse(v);
+                sImmersivePreconfirmationsFilter = f;
+            }
+        }
+        if (DEBUG) {
+            Slog.d(TAG, "immersiveStatusFilter: " + sImmersiveStatusFilter);
+            Slog.d(TAG, "immersiveNavigationFilter: " + sImmersiveNavigationFilter);
+            Slog.d(TAG, "immersivePreconfirmationsFilter: " + sImmersivePreconfirmationsFilter);
+        }
+    }
+
+    private static class Filter {
+        private static final String ALL = "*";
+        private static final String APPS = "apps";
+
+        private final ArraySet<String> mWhitelist;
+        private final ArraySet<String> mBlacklist;
+
+        private Filter(ArraySet<String> whitelist, ArraySet<String> blacklist) {
+            mWhitelist = whitelist;
+            mBlacklist = blacklist;
+        }
+
+        boolean matches(WindowState win) {
+            if (win == null) return false;
+            LayoutParams attrs = win.getAttrs();
+            if (attrs == null) return false;
+            boolean isApp = attrs.type >= WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW
+                    && attrs.type <= WindowManager.LayoutParams.LAST_APPLICATION_WINDOW;
+            if (isApp && mBlacklist.contains(APPS)) return false;
+            if (onBlacklist(attrs.packageName)) return false;
+            if (isApp && mWhitelist.contains(APPS)) return true;
+            return onWhitelist(attrs.packageName);
+        }
+
+        boolean matches(String packageName) {
+            return !onBlacklist(packageName) && onWhitelist(packageName);
+        }
+
+        private boolean onBlacklist(String packageName) {
+            return mBlacklist.contains(packageName) || mBlacklist.contains(ALL);
+        }
+
+        private boolean onWhitelist(String packageName) {
+            return mWhitelist.contains(ALL) || mWhitelist.contains(packageName);
+        }
+
+        void dump(PrintWriter pw) {
+            pw.print("Filter[");
+            dump("whitelist", mWhitelist, pw); pw.print(',');
+            dump("blacklist", mBlacklist, pw); pw.print(']');
+        }
+
+        private void dump(String name, ArraySet<String> set, PrintWriter pw) {
+            pw.print(name); pw.print("=(");
+            final int n = set.size();
+            for (int i = 0; i < n; i++) {
+                if (i > 0) pw.print(',');
+                pw.print(set.valueAt(i));
+            }
+            pw.print(')');
+        }
+
+        @Override
+        public String toString() {
+            StringWriter sw = new StringWriter();
+            dump(new PrintWriter(sw, true));
+            return sw.toString();
+        }
+
+        // value = comma-delimited list of tokens, where token = (package name|apps|*)
+        // e.g. "com.package1", or "apps, com.android.keyguard" or "*"
+        static Filter parse(String value) {
+            if (value == null) return null;
+            ArraySet<String> whitelist = new ArraySet<String>();
+            ArraySet<String> blacklist = new ArraySet<String>();
+            for (String token : value.split(",")) {
+                token = token.trim();
+                if (token.startsWith("-") && token.length() > 1) {
+                    token = token.substring(1);
+                    blacklist.add(token);
+                } else {
+                    whitelist.add(token);
+                }
+            }
+            return new Filter(whitelist, blacklist);
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/AlarmManagerService.java b/services/core/java/com/android/server/AlarmManagerService.java
index cb5ae96..eb347bb 100644
--- a/services/core/java/com/android/server/AlarmManagerService.java
+++ b/services/core/java/com/android/server/AlarmManagerService.java
@@ -39,8 +39,10 @@
 import android.os.UserHandle;
 import android.os.WorkSource;
 import android.text.TextUtils;
+import android.util.ArrayMap;
 import android.util.Pair;
 import android.util.Slog;
+import android.util.SparseArray;
 import android.util.TimeUtils;
 
 import java.io.ByteArrayOutputStream;
@@ -53,9 +55,7 @@
 import java.util.Collections;
 import java.util.Comparator;
 import java.util.Date;
-import java.util.HashMap;
 import java.util.LinkedList;
-import java.util.Map;
 import java.util.TimeZone;
 
 import static android.app.AlarmManager.RTC_WAKEUP;
@@ -313,7 +313,22 @@
             return 0;
         }
     }
-    
+
+    final Comparator<Alarm> mAlarmDispatchComparator = new Comparator<Alarm>() {
+        @Override
+        public int compare(Alarm lhs, Alarm rhs) {
+            if (lhs.wakeup != rhs.wakeup) {
+                return lhs.wakeup ? -1 : 1;
+            }
+            if (lhs.whenElapsed < rhs.whenElapsed) {
+                return -1;
+            } else if (lhs.whenElapsed > rhs.whenElapsed) {
+                return 1;
+            }
+            return 0;
+        }
+    };
+
     // minimum recurrence period or alarm futurity for us to be able to fuzz it
     static final long MIN_FUZZABLE_INTERVAL = 10000;
     static final BatchTimeOrder sBatchOrder = new BatchTimeOrder();
@@ -442,6 +457,7 @@
     }
     
     static final class BroadcastStats {
+        final int mUid;
         final String mPackageName;
 
         long aggregateTime;
@@ -449,16 +465,17 @@
         int numWakeup;
         long startTime;
         int nesting;
-        final HashMap<Pair<String, ComponentName>, FilterStats> filterStats
-                = new HashMap<Pair<String, ComponentName>, FilterStats>();
+        final ArrayMap<Pair<String, ComponentName>, FilterStats> filterStats
+                = new ArrayMap<Pair<String, ComponentName>, FilterStats>();
 
-        BroadcastStats(String packageName) {
+        BroadcastStats(int uid, String packageName) {
+            mUid = uid;
             mPackageName = packageName;
         }
     }
     
-    final HashMap<String, BroadcastStats> mBroadcastStats
-            = new HashMap<String, BroadcastStats>();
+    final SparseArray<ArrayMap<String, BroadcastStats>> mBroadcastStats
+            = new SparseArray<ArrayMap<String, BroadcastStats>>();
     
     @Override
     public void onStart() {
@@ -470,7 +487,7 @@
         setTimeZoneImpl(SystemProperties.get(TIMEZONE_PROPERTY));
 
         PowerManager pm = (PowerManager) getContext().getSystemService(Context.POWER_SERVICE);
-        mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
+        mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "*alarm*");
         
         mTimeTickSender = PendingIntent.getBroadcastAsUser(getContext(), 0,
                 new Intent(Intent.ACTION_TIME_TICK).addFlags(
@@ -743,24 +760,26 @@
                 }
             };
             int len = 0;
-            for (Map.Entry<String, BroadcastStats> be : mBroadcastStats.entrySet()) {
-                BroadcastStats bs = be.getValue();
-                for (Map.Entry<Pair<String, ComponentName>, FilterStats> fe
-                        : bs.filterStats.entrySet()) {
-                    FilterStats fs = fe.getValue();
-                    int pos = len > 0
-                            ? Arrays.binarySearch(topFilters, 0, len, fs, comparator) : 0;
-                    if (pos < 0) {
-                        pos = -pos - 1;
-                    }
-                    if (pos < topFilters.length) {
-                        int copylen = topFilters.length - pos - 1;
-                        if (copylen > 0) {
-                            System.arraycopy(topFilters, pos, topFilters, pos+1, copylen);
+            for (int iu=0; iu<mBroadcastStats.size(); iu++) {
+                ArrayMap<String, BroadcastStats> uidStats = mBroadcastStats.valueAt(iu);
+                for (int ip=0; ip<uidStats.size(); ip++) {
+                    BroadcastStats bs = uidStats.valueAt(ip);
+                    for (int is=0; is<bs.filterStats.size(); is++) {
+                        FilterStats fs = bs.filterStats.valueAt(is);
+                        int pos = len > 0
+                                ? Arrays.binarySearch(topFilters, 0, len, fs, comparator) : 0;
+                        if (pos < 0) {
+                            pos = -pos - 1;
                         }
-                        topFilters[pos] = fs;
-                        if (len < topFilters.length) {
-                            len++;
+                        if (pos < topFilters.length) {
+                            int copylen = topFilters.length - pos - 1;
+                            if (copylen > 0) {
+                                System.arraycopy(topFilters, pos, topFilters, pos+1, copylen);
+                            }
+                            topFilters[pos] = fs;
+                            if (len < topFilters.length) {
+                                len++;
+                            }
                         }
                     }
                 }
@@ -774,7 +793,8 @@
                     TimeUtils.formatDuration(fs.aggregateTime, pw);
                     pw.print(" running, "); pw.print(fs.numWakeup);
                     pw.print(" wakeups, "); pw.print(fs.count);
-                    pw.print(" alarms: "); pw.print(fs.mBroadcastStats.mPackageName);
+                    pw.print(" alarms: "); UserHandle.formatUid(pw, fs.mBroadcastStats.mUid);
+                    pw.print(":"); pw.print(fs.mBroadcastStats.mPackageName);
                     pw.println();
                     pw.print("      ");
                     if (fs.mTarget.first != null) {
@@ -790,35 +810,39 @@
             pw.println(" ");
             pw.println("  Alarm Stats:");
             final ArrayList<FilterStats> tmpFilters = new ArrayList<FilterStats>();
-            for (Map.Entry<String, BroadcastStats> be : mBroadcastStats.entrySet()) {
-                BroadcastStats bs = be.getValue();
-                pw.print("  ");
-                if (bs.nesting > 0) pw.print("*ACTIVE* ");
-                pw.print(be.getKey());
-                pw.print(" "); TimeUtils.formatDuration(bs.aggregateTime, pw);
-                        pw.print(" running, "); pw.print(bs.numWakeup);
-                        pw.println(" wakeups:");
-                tmpFilters.clear();
-                for (Map.Entry<Pair<String, ComponentName>, FilterStats> fe
-                        : bs.filterStats.entrySet()) {
-                    tmpFilters.add(fe.getValue());
-                }
-                Collections.sort(tmpFilters, comparator);
-                for (int i=0; i<tmpFilters.size(); i++) {
-                    FilterStats fs = tmpFilters.get(i);
-                    pw.print("    ");
-                            if (fs.nesting > 0) pw.print("*ACTIVE* ");
-                            TimeUtils.formatDuration(fs.aggregateTime, pw);
-                            pw.print(" "); pw.print(fs.numWakeup);
-                            pw.print(" wakes " ); pw.print(fs.count);
-                            pw.print(" alarms:");
-                            if (fs.mTarget.first != null) {
-                                pw.print(" act="); pw.print(fs.mTarget.first);
-                            }
-                            if (fs.mTarget.second != null) {
-                                pw.print(" cmp="); pw.print(fs.mTarget.second.toShortString());
-                            }
-                            pw.println();
+            for (int iu=0; iu<mBroadcastStats.size(); iu++) {
+                ArrayMap<String, BroadcastStats> uidStats = mBroadcastStats.valueAt(iu);
+                for (int ip=0; ip<uidStats.size(); ip++) {
+                    BroadcastStats bs = uidStats.valueAt(ip);
+                    pw.print("  ");
+                    if (bs.nesting > 0) pw.print("*ACTIVE* ");
+                    UserHandle.formatUid(pw, bs.mUid);
+                    pw.print(":");
+                    pw.print(bs.mPackageName);
+                    pw.print(" "); TimeUtils.formatDuration(bs.aggregateTime, pw);
+                            pw.print(" running, "); pw.print(bs.numWakeup);
+                            pw.println(" wakeups:");
+                    tmpFilters.clear();
+                    for (int is=0; is<bs.filterStats.size(); is++) {
+                        tmpFilters.add(bs.filterStats.valueAt(is));
+                    }
+                    Collections.sort(tmpFilters, comparator);
+                    for (int i=0; i<tmpFilters.size(); i++) {
+                        FilterStats fs = tmpFilters.get(i);
+                        pw.print("    ");
+                                if (fs.nesting > 0) pw.print("*ACTIVE* ");
+                                TimeUtils.formatDuration(fs.aggregateTime, pw);
+                                pw.print(" "); pw.print(fs.numWakeup);
+                                pw.print(" wakes " ); pw.print(fs.count);
+                                pw.print(" alarms:");
+                                if (fs.mTarget.first != null) {
+                                    pw.print(" act="); pw.print(fs.mTarget.first);
+                                }
+                                if (fs.mTarget.second != null) {
+                                    pw.print(" cmp="); pw.print(fs.mTarget.second.toShortString());
+                                }
+                                pw.println();
+                    }
                 }
             }
 
@@ -1037,7 +1061,8 @@
     private native int waitForAlarm(long nativeData);
     private native int setKernelTimezone(long nativeData, int minuteswest);
 
-    void triggerAlarmsLocked(ArrayList<Alarm> triggerList, long nowELAPSED, long nowRTC) {
+    void triggerAlarmsLocked(ArrayList<Alarm> triggerList, final long nowELAPSED,
+            final long nowRTC) {
         // batches are temporally sorted, so we need only pull from the
         // start of the list until we either empty it or hit a batch
         // that is not yet deliverable
@@ -1076,6 +1101,14 @@
 
             }
         }
+
+        Collections.sort(triggerList, mAlarmDispatchComparator);
+
+        if (localLOGV) {
+            for (int i=0; i<triggerList.size(); i++) {
+                Slog.v(TAG, "Triggering alarm #" + i + ": " + triggerList.get(i));
+            }
+        }
     }
 
     /**
@@ -1096,7 +1129,8 @@
     }
     
     private static class Alarm {
-        public int type;
+        public final int type;
+        public final boolean wakeup;
         public int count;
         public long when;
         public long windowLength;
@@ -1109,6 +1143,8 @@
         public Alarm(int _type, long _when, long _whenElapsed, long _windowLength, long _maxWhen,
                 long _interval, PendingIntent _op, WorkSource _ws) {
             type = _type;
+            wakeup = _type == AlarmManager.ELAPSED_REALTIME_WAKEUP
+                    || _type == AlarmManager.RTC_WAKEUP;
             when = _when;
             whenElapsed = _whenElapsed;
             windowLength = _windowLength;
@@ -1126,6 +1162,8 @@
             sb.append(Integer.toHexString(System.identityHashCode(this)));
             sb.append(" type ");
             sb.append(type);
+            sb.append(" when ");
+            sb.append(when);
             sb.append(" ");
             sb.append(operation.getTargetPackage());
             sb.append('}');
@@ -1231,6 +1269,15 @@
                             // we have an active broadcast so stay awake.
                             if (mBroadcastRefCount == 0) {
                                 setWakelockWorkSource(alarm.operation, alarm.workSource);
+                                mWakeLock.setUnimportantForLogging(
+                                        alarm.operation == mTimeTickSender);
+                                // XXX debugging
+                                /*
+                                Intent intent = alarm.operation.getIntent();
+                                mWakeLock.setTag(intent.getAction() != null ? intent.getAction()
+                                        : (intent.getComponent() != null
+                                                ? intent.getComponent().toShortString() : TAG));
+                                */
                                 mWakeLock.acquire();
                             }
                             final InFlight inflight = new InFlight(AlarmManagerService.this,
@@ -1450,7 +1497,14 @@
                 if (pkgList != null && (pkgList.length > 0)) {
                     for (String pkg : pkgList) {
                         removeLocked(pkg);
-                        mBroadcastStats.remove(pkg);
+                        for (int i=mBroadcastStats.size()-1; i>=0; i--) {
+                            ArrayMap<String, BroadcastStats> uidStats = mBroadcastStats.valueAt(i);
+                            if (uidStats.remove(pkg) != null) {
+                                if (uidStats.size() <= 0) {
+                                    mBroadcastStats.removeAt(i);
+                                }
+                            }
+                        }
                     }
                 }
             }
@@ -1458,11 +1512,17 @@
     }
     
     private final BroadcastStats getStatsLocked(PendingIntent pi) {
-        String pkg = pi.getTargetPackage();
-        BroadcastStats bs = mBroadcastStats.get(pkg);
+        String pkg = pi.getCreatorPackage();
+        int uid = pi.getCreatorUid();
+        ArrayMap<String, BroadcastStats> uidStats = mBroadcastStats.get(uid);
+        if (uidStats == null) {
+            uidStats = new ArrayMap<String, BroadcastStats>();
+            mBroadcastStats.put(uid, uidStats);
+        }
+        BroadcastStats bs = uidStats.get(pkg);
         if (bs == null) {
-            bs = new BroadcastStats(pkg);
-            mBroadcastStats.put(pkg, bs);
+            bs = new BroadcastStats(uid, pkg);
+            uidStats.put(pkg, bs);
         }
         return bs;
     }
diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java
index eda08a9..8a29ac7 100644
--- a/services/core/java/com/android/server/am/BatteryStatsService.java
+++ b/services/core/java/com/android/server/am/BatteryStatsService.java
@@ -126,10 +126,11 @@
         }
     }
 
-    public void noteStartWakelock(int uid, int pid, String name, int type) {
+    public void noteStartWakelock(int uid, int pid, String name, int type,
+            boolean unimportantForLogging) {
         enforceCallingPermission();
         synchronized (mStats) {
-            mStats.noteStartWakeLocked(uid, pid, name, type);
+            mStats.noteStartWakeLocked(uid, pid, name, type, unimportantForLogging);
         }
     }
 
@@ -140,10 +141,11 @@
         }
     }
 
-    public void noteStartWakelockFromSource(WorkSource ws, int pid, String name, int type) {
+    public void noteStartWakelockFromSource(WorkSource ws, int pid, String name, int type,
+            boolean unimportantForLogging) {
         enforceCallingPermission();
         synchronized (mStats) {
-            mStats.noteStartWakeFromSourceLocked(ws, pid, name, type);
+            mStats.noteStartWakeFromSourceLocked(ws, pid, name, type, unimportantForLogging);
         }
     }
 
@@ -557,7 +559,7 @@
                     isUnpluggedOnly = true;
                 } else if ("--reset".equals(arg)) {
                     synchronized (mStats) {
-                        mStats.resetAllStatsLocked();
+                        mStats.resetAllStatsCmdLocked();
                         pw.println("Battery stats reset.");
                         noOutput = true;
                     }
diff --git a/services/core/java/com/android/server/power/DisplayPowerController.java b/services/core/java/com/android/server/power/DisplayPowerController.java
index f1be504..b63f625 100644
--- a/services/core/java/com/android/server/power/DisplayPowerController.java
+++ b/services/core/java/com/android/server/power/DisplayPowerController.java
@@ -536,6 +536,14 @@
 
         mScreenBrightnessRampAnimator = new RampAnimator<DisplayPowerState>(
                 mPowerState, DisplayPowerState.SCREEN_BRIGHTNESS);
+
+        // Initialize screen on state.
+        if (mPowerState.isScreenOn()) {
+            mNotifier.onScreenOn();
+        } else {
+            mNotifier.onScreenOff();
+        }
+        mNotifier.onScreenBrightness(mPowerState.getScreenBrightness());
     }
 
     private final Animator.AnimatorListener mAnimatorListener = new Animator.AnimatorListener() {
diff --git a/services/core/java/com/android/server/power/Notifier.java b/services/core/java/com/android/server/power/Notifier.java
index 264e2e9..09be3a8 100644
--- a/services/core/java/com/android/server/power/Notifier.java
+++ b/services/core/java/com/android/server/power/Notifier.java
@@ -34,6 +34,7 @@
 import android.os.Looper;
 import android.os.Message;
 import android.os.PowerManager;
+import android.os.Process;
 import android.os.RemoteException;
 import android.os.SystemClock;
 import android.os.UserHandle;
@@ -139,10 +140,14 @@
 
         try {
             final int monitorType = getBatteryStatsWakeLockMonitorType(flags);
+            boolean unimportantForLogging = (flags&PowerManager.UNIMPORTANT_FOR_LOGGING) != 0
+                    && ownerUid == Process.SYSTEM_UID;
             if (workSource != null) {
-                mBatteryStats.noteStartWakelockFromSource(workSource, ownerPid, tag, monitorType);
+                mBatteryStats.noteStartWakelockFromSource(workSource, ownerPid, tag, monitorType,
+                        unimportantForLogging);
             } else {
-                mBatteryStats.noteStartWakelock(ownerUid, ownerPid, tag, monitorType);
+                mBatteryStats.noteStartWakelock(ownerUid, ownerPid, tag, monitorType,
+                        unimportantForLogging);
                 // XXX need to deal with disabled operations.
                 mAppOps.startOperation(AppOpsManager.getToken(mAppOps),
                         AppOpsManager.OP_WAKE_LOCK, ownerUid, packageName);
diff --git a/services/core/java/com/android/server/wm/DimLayer.java b/services/core/java/com/android/server/wm/DimLayer.java
index 30eaf45..574ae2d 100644
--- a/services/core/java/com/android/server/wm/DimLayer.java
+++ b/services/core/java/com/android/server/wm/DimLayer.java
@@ -170,7 +170,7 @@
             dw = mBounds.width();
             dh = mBounds.height();
             xPos = mBounds.left;
-            yPos = mBounds.right;
+            yPos = mBounds.top;
         } else {
             // Set surface size to screen size.
             final DisplayInfo info = mDisplayContent.getDisplayInfo();
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 9f45e88..415a06b 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -22,12 +22,10 @@
 
 import android.graphics.Rect;
 import android.graphics.Region;
-import android.util.EventLog;
 import android.util.Slog;
 import android.view.Display;
 import android.view.DisplayInfo;
 import android.view.Surface;
-import com.android.server.EventLogTags;
 
 import java.io.PrintWriter;
 import java.util.ArrayList;
@@ -49,7 +47,7 @@
 
     /** Z-ordered (bottom-most first) list of all Window objects. Assigned to an element
      * from mDisplayWindows; */
-    private WindowList mWindows = new WindowList();
+    private final WindowList mWindows = new WindowList();
 
     // This protects the following display size properties, so that
     // getDisplaySize() doesn't need to acquire the global lock.  This is
@@ -79,21 +77,12 @@
     int pendingLayoutChanges;
     final boolean isDefaultDisplay;
 
-    /**
-     * Window tokens that are in the process of exiting, but still
-     * on screen for animations.
-     */
+    /** Window tokens that are in the process of exiting, but still on screen for animations. */
     final ArrayList<WindowToken> mExitingTokens = new ArrayList<WindowToken>();
 
-    /**
-     * Application tokens that are in the process of exiting, but still
-     * on screen for animations.
-     */
-    final AppTokenList mExitingAppTokens = new AppTokenList();
-
     /** Array containing all TaskStacks on this display.  Array
      * is stored in display order with the current bottom stack at 0. */
-    private ArrayList<TaskStack> mStacks = new ArrayList<TaskStack>();
+    private final ArrayList<TaskStack> mStacks = new ArrayList<TaskStack>();
 
     /** A special TaskStack with id==HOME_STACK_ID that moves to the bottom whenever any TaskStack
      * (except a future lockscreen TaskStack) moves to the top. */
@@ -105,14 +94,18 @@
     /** Detect user tapping outside of current focused stack bounds .*/
     Region mTouchExcludeRegion = new Region();
 
-    /** Save allocating when retrieving tasks */
-    private ArrayList<Task> mTaskHistory = new ArrayList<Task>();
-
     /** Save allocating when calculating rects */
     Rect mTmpRect = new Rect();
 
+    /** For gathering Task objects in order. */
+    final ArrayList<Task> mTmpTaskHistory = new ArrayList<Task>();
+
     final WindowManagerService mService;
 
+    static final int DEFER_DETACH = 1;
+    static final int DEFER_REMOVAL = 2;
+    int mDeferredActions;
+
     /**
      * @param display May not be null.
      * @param service You know.
@@ -152,41 +145,21 @@
         return (mDisplay.getFlags() & Display.FLAG_PRIVATE) != 0;
     }
 
+    ArrayList<TaskStack> getStacks() {
+        return mStacks;
+    }
+
     /**
      * Retrieve the tasks on this display in stack order from the bottommost TaskStack up.
      * @return All the Tasks, in order, on this display.
      */
     ArrayList<Task> getTasks() {
-        return mTaskHistory;
-    }
-
-    void addTask(Task task, boolean toTop) {
-        mTaskHistory.remove(task);
-
-        final int userId = task.mUserId;
-        int taskNdx;
-        final int numTasks = mTaskHistory.size();
-        if (toTop) {
-            for (taskNdx = numTasks - 1; taskNdx >= 0; --taskNdx) {
-                if (mTaskHistory.get(taskNdx).mUserId == userId) {
-                    break;
-                }
-            }
-            ++taskNdx;
-        } else {
-            for (taskNdx = 0; taskNdx < numTasks; ++taskNdx) {
-                if (mTaskHistory.get(taskNdx).mUserId == userId) {
-                    break;
-                }
-            }
+        mTmpTaskHistory.clear();
+        final int numStacks = mStacks.size();
+        for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) {
+            mTmpTaskHistory.addAll(mStacks.get(stackNdx).getTasks());
         }
-
-        mTaskHistory.add(taskNdx, task);
-        EventLog.writeEvent(EventLogTags.WM_TASK_MOVED, task.taskId, toTop ? 1 : 0, taskNdx);
-    }
-
-    void removeTask(Task task) {
-        mTaskHistory.remove(task);
+        return mTmpTaskHistory;
     }
 
     TaskStack getHomeStack() {
@@ -226,15 +199,6 @@
         out.set(left, top, left + width, top + height);
     }
 
-    /** @return The number of tokens in all of the Tasks on this display. */
-    int numTokens() {
-        int count = 0;
-        for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
-            count += mTaskHistory.get(taskNdx).mAppTokens.size();
-        }
-        return count;
-    }
-
     /** Refer to {@link WindowManagerService#attachStack(int, int)} */
     void attachStack(TaskStack stack) {
         if (stack.mStackId == HOME_STACK_ID) {
@@ -253,13 +217,6 @@
     }
 
     void detachStack(TaskStack stack) {
-        for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
-            final Task task = mTaskHistory.get(taskNdx);
-            if (task.mStack == stack) {
-                mService.tmpRemoveTaskWindowsLocked(task);
-                mTaskHistory.remove(taskNdx);
-            }
-        }
         mStacks.remove(stack);
     }
 
@@ -271,17 +228,6 @@
         mContentRect.set(contentRect);
     }
 
-    boolean getStackBounds(int stackId, Rect bounds) {
-        for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
-            final TaskStack stack = mStacks.get(stackNdx);
-            if (stackId == stack.mStackId) {
-                bounds.set(stack.mBounds);
-                return true;
-            }
-        }
-        return false;
-    }
-
     int stackIdFromPoint(int x, int y) {
         for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
             final TaskStack stack = mStacks.get(stackNdx);
@@ -307,7 +253,7 @@
         }
     }
 
-    void switchUserStacks(int oldUserId, int newUserId) {
+    void switchUserStacks(int newUserId) {
         final WindowList windows = getWindowList();
         for (int i = 0; i < windows.size(); i++) {
             final WindowState win = windows.get(i);
@@ -393,22 +339,27 @@
             pw.print(prefix); pw.print("mStacks[" + stackNdx + "]"); pw.println(stack.mStackId);
             stack.dump(prefix + "  ", pw);
         }
-        int ndx = numTokens();
-        if (ndx > 0) {
-            pw.println();
-            pw.println("  Application tokens in Z order:");
-            getTasks();
-            for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
-                AppTokenList tokens = mTaskHistory.get(taskNdx).mAppTokens;
+        pw.println();
+        pw.println("  Application tokens in bottom up Z order:");
+        int ndx = 0;
+        final int numStacks = mStacks.size();
+        for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) {
+            ArrayList<Task> tasks = mStacks.get(stackNdx).getTasks();
+            for (int taskNdx = tasks.size() - 1; taskNdx >= 0; --taskNdx) {
+                AppTokenList tokens = tasks.get(taskNdx).mAppTokens;
                 for (int tokenNdx = tokens.size() - 1; tokenNdx >= 0; --tokenNdx) {
                     final AppWindowToken wtoken = tokens.get(tokenNdx);
-                    pw.print("  App #"); pw.print(ndx--);
+                    pw.print("  App #"); pw.print(ndx++);
                             pw.print(' '); pw.print(wtoken); pw.println(":");
                     wtoken.dump(pw, "    ");
                 }
             }
         }
-        if (mExitingTokens.size() > 0) {
+        if (ndx == 0) {
+            pw.println("    None");
+        }
+        pw.println();
+        if (!mExitingTokens.isEmpty()) {
             pw.println();
             pw.println("  Exiting tokens:");
             for (int i=mExitingTokens.size()-1; i>=0; i--) {
@@ -419,17 +370,6 @@
                 token.dump(pw, "    ");
             }
         }
-        if (mExitingAppTokens.size() > 0) {
-            pw.println();
-            pw.println("  Exiting application tokens:");
-            for (int i=mExitingAppTokens.size()-1; i>=0; i--) {
-                WindowToken token = mExitingAppTokens.get(i);
-                pw.print("  Exiting App #"); pw.print(i);
-                  pw.print(' '); pw.print(token);
-                  pw.println(':');
-                  token.dump(pw, "    ");
-            }
-        }
         pw.println();
     }
 
diff --git a/services/core/java/com/android/server/wm/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java
index 1ada6c2..0941c76 100644
--- a/services/core/java/com/android/server/wm/TaskStack.java
+++ b/services/core/java/com/android/server/wm/TaskStack.java
@@ -67,6 +67,9 @@
      * then stop any dimming. */
     boolean mDimmingTag;
 
+    /** Application tokens that are exiting, but still on screen for animations. */
+    final AppTokenList mExitingAppTokens = new AppTokenList();
+
     TaskStack(WindowManagerService service, int stackId) {
         mService = service;
         mStackId = stackId;
@@ -134,6 +137,21 @@
         return mBounds.isEmpty();
     }
 
+    boolean isAnimating() {
+        for (int taskNdx = mTasks.size() - 1; taskNdx >= 0; --taskNdx) {
+            final ArrayList<AppWindowToken> activities = mTasks.get(taskNdx).mAppTokens;
+            for (int activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) {
+                final ArrayList<WindowState> windows = activities.get(activityNdx).allAppWindows;
+                for (int winNdx = windows.size() - 1; winNdx >= 0; --winNdx) {
+                    if (windows.get(winNdx).mWinAnimator.isAnimating()) {
+                        return true;
+                    }
+                }
+            }
+        }
+        return false;
+    }
+
     void resizeBounds(float oldWidth, float oldHeight, float newWidth, float newHeight) {
         if (oldWidth == newWidth && oldHeight == newHeight) {
             return;
@@ -174,8 +192,8 @@
         mTasks.add(stackNdx, task);
 
         task.mStack = this;
-        mDisplayContent.addTask(task, toTop);
         mDisplayContent.moveStack(this, true);
+        EventLog.writeEvent(EventLogTags.WM_TASK_MOVED, task.taskId, toTop ? 1 : 0, stackNdx);
     }
 
     void moveTaskToTop(Task task) {
@@ -200,7 +218,6 @@
         if (DEBUG_TASK_MOVEMENT) Slog.d(TAG, "removeTask: task=" + task);
         mTasks.remove(task);
         if (mDisplayContent != null) {
-            mDisplayContent.removeTask(task);
             if (mTasks.isEmpty()) {
                 mDisplayContent.moveStack(this, false);
             }
@@ -216,15 +233,13 @@
         mDisplayContent = displayContent;
         mDimLayer = new DimLayer(mService, this, displayContent);
         mAnimationBackgroundSurface = new DimLayer(mService, this, displayContent);
-
-        for (int taskNdx = 0; taskNdx < mTasks.size(); ++taskNdx) {
-            Task task = mTasks.get(taskNdx);
-            displayContent.addTask(task, true);
-        }
     }
 
-    void detach() {
+    void detachDisplay() {
         EventLog.writeEvent(EventLogTags.WM_STACK_REMOVED, mStackId);
+        for (int taskNdx = mTasks.size() - 1; taskNdx >= 0; --taskNdx) {
+            mService.tmpRemoveTaskWindowsLocked(mTasks.get(taskNdx));
+        }
         mAnimationBackgroundSurface.destroySurface();
         mAnimationBackgroundSurface = null;
         mDimLayer.destroySurface();
@@ -351,6 +366,19 @@
         mAnimationBackgroundSurface.mDimSurface.destroy();
     }
 
+    void checkForDeferredDetach() {
+        if (mDisplayContent != null &&
+                (mDisplayContent.mDeferredActions & DisplayContent.DEFER_DETACH) != 0 &&
+                !isAnimating()) {
+            mDisplayContent.mDeferredActions &= ~DisplayContent.DEFER_DETACH;
+            mService.detachStack(mStackId);
+            if ((mDisplayContent.mDeferredActions & DisplayContent.DEFER_REMOVAL) != 0) {
+                mDisplayContent.mDeferredActions &= ~DisplayContent.DEFER_REMOVAL;
+                mService.onDisplayRemoved(mDisplayContent.getDisplayId());
+            }
+        }
+    }
+
     public void dump(String prefix, PrintWriter pw) {
         pw.print(prefix); pw.print("mStackId="); pw.println(mStackId);
         for (int taskNdx = 0; taskNdx < mTasks.size(); ++taskNdx) {
@@ -365,6 +393,17 @@
             mDimLayer.printTo(prefix, pw);
             pw.print(prefix); pw.print("mDimWinAnimator="); pw.println(mDimWinAnimator);
         }
+        if (!mExitingAppTokens.isEmpty()) {
+            pw.println();
+            pw.println("  Exiting application tokens:");
+            for (int i=mExitingAppTokens.size()-1; i>=0; i--) {
+                WindowToken token = mExitingAppTokens.get(i);
+                pw.print("  Exiting App #"); pw.print(i);
+                pw.print(' '); pw.print(token);
+                pw.println(':');
+                token.dump(pw, "    ");
+            }
+        }
     }
 
     @Override
diff --git a/services/core/java/com/android/server/wm/WindowAnimator.java b/services/core/java/com/android/server/wm/WindowAnimator.java
index b4285c6..a9947c0 100644
--- a/services/core/java/com/android/server/wm/WindowAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowAnimator.java
@@ -64,7 +64,7 @@
     Object mLastWindowFreezeSource;
 
     SparseArray<DisplayContentsAnimator> mDisplayContentsAnimators =
-            new SparseArray<WindowAnimator.DisplayContentsAnimator>(2);
+            new SparseArray<DisplayContentsAnimator>(2);
 
     boolean mInitialized = false;
 
@@ -151,14 +151,33 @@
     }
 
     private void updateAppWindowsLocked(int displayId) {
-        final DisplayContent displayContent = mService.getDisplayContentLocked(displayId);
-        final ArrayList<Task> tasks = displayContent.getTasks();
-        final int numTasks = tasks.size();
-        for (int taskNdx = 0; taskNdx < numTasks; ++taskNdx) {
-            final AppTokenList tokens = tasks.get(taskNdx).mAppTokens;
-            final int numTokens = tokens.size();
-            for (int tokenNdx = 0; tokenNdx < numTokens; ++tokenNdx) {
-                final AppWindowAnimator appAnimator = tokens.get(tokenNdx).mAppAnimator;
+        ArrayList<TaskStack> stacks = mService.getDisplayContentLocked(displayId).getStacks();
+        for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
+            final TaskStack stack = stacks.get(stackNdx);
+            final ArrayList<Task> tasks = stack.getTasks();
+            for (int taskNdx = tasks.size() - 1; taskNdx >= 0; --taskNdx) {
+                final AppTokenList tokens = tasks.get(taskNdx).mAppTokens;
+                for (int tokenNdx = tokens.size() - 1; tokenNdx >= 0; --tokenNdx) {
+                    final AppWindowAnimator appAnimator = tokens.get(tokenNdx).mAppAnimator;
+                    final boolean wasAnimating = appAnimator.animation != null
+                            && appAnimator.animation != AppWindowAnimator.sDummyAnimation;
+                    if (appAnimator.stepAnimationLocked(mCurrentTime)) {
+                        mAnimating = true;
+                    } else if (wasAnimating) {
+                        // stopped animating, do one more pass through the layout
+                        setAppLayoutChanges(appAnimator,
+                                WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER,
+                                "appToken " + appAnimator.mAppToken + " done");
+                        if (WindowManagerService.DEBUG_ANIM) Slog.v(TAG,
+                                "updateWindowsApps...: done animating " + appAnimator.mAppToken);
+                    }
+                }
+            }
+
+            final AppTokenList exitingAppTokens = stack.mExitingAppTokens;
+            final int NEAT = exitingAppTokens.size();
+            for (int i = 0; i < NEAT; i++) {
+                final AppWindowAnimator appAnimator = exitingAppTokens.get(i).mAppAnimator;
                 final boolean wasAnimating = appAnimator.animation != null
                         && appAnimator.animation != AppWindowAnimator.sDummyAnimation;
                 if (appAnimator.stepAnimationLocked(mCurrentTime)) {
@@ -166,29 +185,12 @@
                 } else if (wasAnimating) {
                     // stopped animating, do one more pass through the layout
                     setAppLayoutChanges(appAnimator, WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER,
-                            "appToken " + appAnimator.mAppToken + " done");
+                        "exiting appToken " + appAnimator.mAppToken + " done");
                     if (WindowManagerService.DEBUG_ANIM) Slog.v(TAG,
-                            "updateWindowsApps...: done animating " + appAnimator.mAppToken);
+                            "updateWindowsApps...: done animating exiting " + appAnimator.mAppToken);
                 }
             }
         }
-
-        final AppTokenList exitingAppTokens = displayContent.mExitingAppTokens;
-        final int NEAT = exitingAppTokens.size();
-        for (int i = 0; i < NEAT; i++) {
-            final AppWindowAnimator appAnimator = exitingAppTokens.get(i).mAppAnimator;
-            final boolean wasAnimating = appAnimator.animation != null
-                    && appAnimator.animation != AppWindowAnimator.sDummyAnimation;
-            if (appAnimator.stepAnimationLocked(mCurrentTime)) {
-                mAnimating = true;
-            } else if (wasAnimating) {
-                // stopped animating, do one more pass through the layout
-                setAppLayoutChanges(appAnimator, WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER,
-                    "exiting appToken " + appAnimator.mAppToken + " done");
-                if (WindowManagerService.DEBUG_ANIM) Slog.v(TAG,
-                        "updateWindowsApps...: done animating exiting " + appAnimator.mAppToken);
-            }
-        }
     }
 
     private void updateWindowsLocked(final int displayId) {
@@ -449,11 +451,6 @@
         }
     }
 
-    private void performAnimationsLocked(final int displayId) {
-        updateWindowsLocked(displayId);
-        updateWallpaperLocked(displayId);
-    }
-
 
     /** Locked on mService.mWindowMap. */
     private void animateLocked() {
@@ -494,7 +491,8 @@
 
                 // Update animations of all applications, including those
                 // associated with exiting/removed apps
-                performAnimationsLocked(displayId);
+                updateWindowsLocked(displayId);
+                updateWallpaperLocked(displayId);
 
                 final WindowList windows = mService.getWindowListLocked(displayId);
                 final int N = windows.size();
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 5387436..d7f3fa0 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -602,6 +602,9 @@
     final WindowAnimator mAnimator;
 
     SparseArray<Task> mTaskIdToTask = new SparseArray<Task>();
+
+    /** All of the TaskStacks in the window manager, unordered. For an ordered list call
+     * DisplayContent.getStacks(). */
     SparseArray<TaskStack> mStackIdToStack = new SparseArray<TaskStack>();
 
     private final PointerEventDispatcher mPointerEventDispatcher;
@@ -4562,13 +4565,12 @@
                         TAG, "Removing app " + wtoken + " delayed=" + delayed
                         + " animation=" + wtoken.mAppAnimator.animation
                         + " animating=" + wtoken.mAppAnimator.animating);
-                final Task task = mTaskIdToTask.get(wtoken.groupId);
-                DisplayContent displayContent = task.getDisplayContent();
-                if (displayContent != null && delayed) {
+                final TaskStack stack = mTaskIdToTask.get(wtoken.groupId).mStack;
+                if (delayed) {
                     // set the token aside because it has an active animation to be finished
                     if (DEBUG_ADD_REMOVE || DEBUG_TOKEN_MOVEMENT) Slog.v(TAG,
                             "removeAppToken make exiting: " + wtoken);
-                    displayContent.mExitingAppTokens.add(wtoken);
+                    stack.mExitingAppTokens.add(wtoken);
                 } else {
                     // Make sure there is no animation running on this token,
                     // so any windows associated with it will be removed as
@@ -4639,17 +4641,19 @@
     }
 
     void dumpAppTokensLocked() {
-        final int numDisplays = mDisplayContents.size();
-        for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
-            final DisplayContent displayContent = mDisplayContents.valueAt(displayNdx);
-            Slog.v(TAG, "  Display " + displayContent.getDisplayId());
-            final ArrayList<Task> tasks = displayContent.getTasks();
-            int i = displayContent.numTokens();
-            for (int taskNdx = tasks.size() - 1; taskNdx >= 0; --taskNdx) {
-                AppTokenList tokens = tasks.get(taskNdx).mAppTokens;
-                for (int tokenNdx = tokens.size() - 1; tokenNdx >= 0; --tokenNdx) {
-                    final AppWindowToken wtoken = tokens.get(tokenNdx);
-                    Slog.v(TAG, "  #" + --i + ": " + wtoken.token);
+        final int numStacks = mStackIdToStack.size();
+        for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) {
+            final TaskStack stack = mStackIdToStack.valueAt(stackNdx);
+            Slog.v(TAG, "  Stack #" + stack.mStackId + " tasks from bottom to top:");
+            final ArrayList<Task> tasks = stack.getTasks();
+            final int numTasks = tasks.size();
+            for (int taskNdx = 0; taskNdx < numTasks; ++taskNdx) {
+                final Task task = tasks.get(taskNdx);
+                Slog.v(TAG, "    Task #" + task.taskId + " activities from bottom to top:");
+                AppTokenList tokens = task.mAppTokens;
+                final int numTokens = tokens.size();
+                for (int tokenNdx = 0; tokenNdx < numTokens; ++tokenNdx) {
+                    Slog.v(TAG, "      activity #" + tokenNdx + ": " + tokens.get(tokenNdx).token);
                 }
             }
         }
@@ -4911,8 +4915,12 @@
             if (stack != null) {
                 final DisplayContent displayContent = stack.getDisplayContent();
                 if (displayContent != null) {
+                    if (stack.isAnimating()) {
+                        displayContent.mDeferredActions |= DisplayContent.DEFER_DETACH;
+                        return;
+                    }
                     displayContent.detachStack(stack);
-                    stack.detach();
+                    stack.detachDisplay();
                 }
             }
         }
@@ -5241,7 +5249,7 @@
             final int numDisplays = mDisplayContents.size();
             for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
                 final DisplayContent displayContent = mDisplayContents.valueAt(displayNdx);
-                displayContent.switchUserStacks(oldUserId, newUserId);
+                displayContent.switchUserStacks(newUserId);
                 rebuildAppWindowListLocked(displayContent);
             }
             performLayoutAndPlaceSurfacesLocked();
@@ -7394,15 +7402,18 @@
                 case APP_FREEZE_TIMEOUT: {
                     synchronized (mWindowMap) {
                         Slog.w(TAG, "App freeze timeout expired.");
-                        DisplayContent displayContent = getDefaultDisplayContentLocked();
-                        final ArrayList<Task> tasks = displayContent.getTasks();
-                        for (int taskNdx = tasks.size() - 1; taskNdx >= 0; --taskNdx) {
-                            AppTokenList tokens = tasks.get(taskNdx).mAppTokens;
-                            for (int tokenNdx = tokens.size() - 1; tokenNdx >= 0; --tokenNdx) {
-                                AppWindowToken tok = tokens.get(tokenNdx);
-                                if (tok.mAppAnimator.freezingScreen) {
-                                    Slog.w(TAG, "Force clearing freeze: " + tok);
-                                    unsetAppFreezingScreenLocked(tok, true, true);
+                        final int numStacks = mStackIdToStack.size();
+                        for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) {
+                            final TaskStack stack = mStackIdToStack.valueAt(stackNdx);
+                            final ArrayList<Task> tasks = stack.getTasks();
+                            for (int taskNdx = tasks.size() - 1; taskNdx >= 0; --taskNdx) {
+                                AppTokenList tokens = tasks.get(taskNdx).mAppTokens;
+                                for (int tokenNdx = tokens.size() - 1; tokenNdx >= 0; --tokenNdx) {
+                                    AppWindowToken tok = tokens.get(tokenNdx);
+                                    if (tok.mAppAnimator.freezingScreen) {
+                                        Slog.w(TAG, "Force clearing freeze: " + tok);
+                                        unsetAppFreezingScreenLocked(tok, true, true);
+                                    }
                                 }
                             }
                         }
@@ -8012,21 +8023,27 @@
         // in the main app list, but still have windows shown.  We put them
         // in the back because now that the animation is over we no longer
         // will care about them.
-        AppTokenList exitingAppTokens = displayContent.mExitingAppTokens;
-        int NT = exitingAppTokens.size();
-        for (int j=0; j<NT; j++) {
-            i = reAddAppWindowsLocked(displayContent, i, exitingAppTokens.get(j));
+        final ArrayList<TaskStack> stacks = displayContent.getStacks();
+        final int numStacks = stacks.size();
+        for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) {
+            AppTokenList exitingAppTokens = stacks.get(stackNdx).mExitingAppTokens;
+            int NT = exitingAppTokens.size();
+            for (int j = 0; j < NT; j++) {
+                i = reAddAppWindowsLocked(displayContent, i, exitingAppTokens.get(j));
+            }
         }
 
         // And add in the still active app tokens in Z order.
-        final ArrayList<Task> tasks = displayContent.getTasks();
-        final int numTasks = tasks.size();
-        for (int taskNdx = 0; taskNdx < numTasks; ++taskNdx) {
-            final AppTokenList tokens = tasks.get(taskNdx).mAppTokens;
-            final int numTokens = tokens.size();
-            for (int tokenNdx = 0; tokenNdx < numTokens; ++tokenNdx) {
-                final AppWindowToken wtoken = tokens.get(tokenNdx);
-                i = reAddAppWindowsLocked(displayContent, i, wtoken);
+        for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) {
+            final ArrayList<Task> tasks = stacks.get(stackNdx).getTasks();
+            final int numTasks = tasks.size();
+            for (int taskNdx = 0; taskNdx < numTasks; ++taskNdx) {
+                final AppTokenList tokens = tasks.get(taskNdx).mAppTokens;
+                final int numTokens = tokens.size();
+                for (int tokenNdx = 0; tokenNdx < numTokens; ++tokenNdx) {
+                    final AppWindowToken wtoken = tokens.get(tokenNdx);
+                    i = reAddAppWindowsLocked(displayContent, i, wtoken);
+                }
             }
         }
 
@@ -8701,15 +8718,14 @@
 
         mAppTransition.setIdle();
         // Restore window app tokens to the ActivityManager views
-        final DisplayContent displayContent = getDefaultDisplayContentLocked();
-        final ArrayList<Task> tasks = displayContent.getTasks();
-        final int numTasks = tasks.size();
-        for (int taskNdx = 0; taskNdx < numTasks; ++taskNdx) {
-            final AppTokenList tokens = tasks.get(taskNdx).mAppTokens;
-            final int numTokens = tokens.size();
-            for (int tokenNdx = 0; tokenNdx < numTokens; ++tokenNdx) {
-                final AppWindowToken wtoken = tokens.get(tokenNdx);
-                wtoken.sendingToBottom = false;
+        ArrayList<TaskStack> stacks = getDefaultDisplayContentLocked().getStacks();
+        for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
+            final ArrayList<Task> tasks = stacks.get(stackNdx).getTasks();
+            for (int taskNdx = tasks.size() - 1; taskNdx >= 0; --taskNdx) {
+                final AppTokenList tokens = tasks.get(taskNdx).mAppTokens;
+                for (int tokenNdx = tokens.size() - 1; tokenNdx >= 0; --tokenNdx) {
+                    tokens.get(tokenNdx).sendingToBottom = false;
+                }
             }
         }
         rebuildAppWindowListLocked();
@@ -8863,7 +8879,7 @@
         }
     }
 
-    private void handleFlagDimBehind(WindowState w, int innerDw, int innerDh) {
+    private void handleFlagDimBehind(WindowState w) {
         final WindowManager.LayoutParams attrs = w.mAttrs;
         if ((attrs.flags & FLAG_DIM_BEHIND) != 0
                 && w.isDisplayedLw()
@@ -8881,22 +8897,23 @@
     private void updateAllDrawnLocked(DisplayContent displayContent) {
         // See if any windows have been drawn, so they (and others
         // associated with them) can now be shown.
-        final ArrayList<Task> tasks = displayContent.getTasks();
-        final int numTasks = tasks.size();
-        for (int taskNdx = 0; taskNdx < numTasks; ++taskNdx) {
-            final AppTokenList tokens = tasks.get(taskNdx).mAppTokens;
-            final int numTokens = tokens.size();
-            for (int tokenNdx = 0; tokenNdx < numTokens; ++tokenNdx) {
-                final AppWindowToken wtoken = tokens.get(tokenNdx);
-                if (!wtoken.allDrawn) {
-                    int numInteresting = wtoken.numInterestingWindows;
-                    if (numInteresting > 0 && wtoken.numDrawnWindows >= numInteresting) {
-                        if (DEBUG_VISIBILITY) Slog.v(TAG,
-                                "allDrawn: " + wtoken
-                                + " interesting=" + numInteresting
-                                + " drawn=" + wtoken.numDrawnWindows);
-                        wtoken.allDrawn = true;
-                        mH.obtainMessage(H.NOTIFY_ACTIVITY_DRAWN, wtoken.token).sendToTarget();
+        ArrayList<TaskStack> stacks = displayContent.getStacks();
+        for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
+            final ArrayList<Task> tasks = stacks.get(stackNdx).getTasks();
+            for (int taskNdx = tasks.size() - 1; taskNdx >= 0; --taskNdx) {
+                final AppTokenList tokens = tasks.get(taskNdx).mAppTokens;
+                for (int tokenNdx = tokens.size() - 1; tokenNdx >= 0; --tokenNdx) {
+                    final AppWindowToken wtoken = tokens.get(tokenNdx);
+                    if (!wtoken.allDrawn) {
+                        int numInteresting = wtoken.numInterestingWindows;
+                        if (numInteresting > 0 && wtoken.numDrawnWindows >= numInteresting) {
+                            if (DEBUG_VISIBILITY) Slog.v(TAG,
+                                    "allDrawn: " + wtoken
+                                    + " interesting=" + numInteresting
+                                    + " drawn=" + wtoken.numDrawnWindows);
+                            wtoken.allDrawn = true;
+                            mH.obtainMessage(H.NOTIFY_ACTIVITY_DRAWN, wtoken.token).sendToTarget();
+                        }
                     }
                 }
             }
@@ -8927,10 +8944,14 @@
             for (i=displayContent.mExitingTokens.size()-1; i>=0; i--) {
                 displayContent.mExitingTokens.get(i).hasVisible = false;
             }
+        }
 
+        for (int stackNdx = mStackIdToStack.size() - 1; stackNdx >= 0; --stackNdx) {
             // Initialize state of exiting applications.
-            for (i=displayContent.mExitingAppTokens.size()-1; i>=0; i--) {
-                displayContent.mExitingAppTokens.get(i).hasVisible = false;
+            final AppTokenList exitingAppTokens =
+                    mStackIdToStack.valueAt(stackNdx).mExitingAppTokens;
+            for (int tokenNdx = exitingAppTokens.size() - 1; tokenNdx >= 0; --tokenNdx) {
+                exitingAppTokens.get(tokenNdx).hasVisible = false;
             }
         }
 
@@ -9063,7 +9084,7 @@
                     }
 
                     if (!stack.testDimmingTag()) {
-                        handleFlagDimBehind(w, innerDw, innerDh);
+                        handleFlagDimBehind(w);
                     }
 
                     if (isDefaultDisplay && obscuredChanged && (mWallpaperTarget == w)
@@ -9343,9 +9364,13 @@
                     }
                 }
             }
+        }
 
-            // Time to remove any exiting applications?
-            AppTokenList exitingAppTokens = displayContent.mExitingAppTokens;
+        // Time to remove any exiting applications?
+        for (int stackNdx = mStackIdToStack.size() - 1; stackNdx >= 0; --stackNdx) {
+            // Initialize state of exiting applications.
+            final AppTokenList exitingAppTokens =
+                    mStackIdToStack.valueAt(stackNdx).mExitingAppTokens;
             for (i = exitingAppTokens.size() - 1; i >= 0; i--) {
                 AppWindowToken token = exitingAppTokens.get(i);
                 if (!token.hasVisible && !mClosingApps.contains(token)) {
@@ -10831,6 +10856,10 @@
     private void handleDisplayRemovedLocked(int displayId) {
         final DisplayContent displayContent = getDisplayContentLocked(displayId);
         if (displayContent != null) {
+            if ((displayContent.mDeferredActions & DisplayContent.DEFER_DETACH) != 0) {
+                displayContent.mDeferredActions |= DisplayContent.DEFER_REMOVAL;
+                return;
+            }
             mDisplayContents.delete(displayId);
             displayContent.close();
             if (displayId == Display.DEFAULT_DISPLAY) {
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index 76e885f..5cff319 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -416,6 +416,7 @@
             mService.mPendingRemove.add(mWin);
             mWin.mRemoveOnExit = false;
         }
+        mWin.getStack().checkForDeferredDetach();
         mAnimator.hideWallpapersLocked(mWin);
     }
 
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DeviceOwner.java b/services/devicepolicy/java/com/android/server/devicepolicy/DeviceOwner.java
new file mode 100644
index 0000000..1b048a1
--- /dev/null
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DeviceOwner.java
@@ -0,0 +1,274 @@
+/*
+ * 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.
+ */
+
+package com.android.server.devicepolicy;
+
+import android.app.AppGlobals;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.os.Environment;
+import android.os.RemoteException;
+import android.util.AtomicFile;
+import android.util.Slog;
+import android.util.Xml;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.FastXmlSerializer;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlSerializer;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.HashMap;
+
+/**
+ * Stores and restores state for the Device and Profile owners. By definition there can be
+ * only one device owner, but there may be a profile owner for each user.
+ */
+public class DeviceOwner {
+    private static final String TAG = "DevicePolicyManagerService";
+
+    private static final String DEVICE_OWNER_XML = "device_owner.xml";
+    private static final String TAG_DEVICE_OWNER = "device-owner";
+    private static final String TAG_PROFILE_OWNER = "profile-owner";
+    private static final String ATTR_NAME = "name";
+    private static final String ATTR_PACKAGE = "package";
+    private static final String ATTR_USERID = "userId";
+
+    private AtomicFile fileForWriting;
+
+    // Input/Output streams for testing.
+    private InputStream mInputStreamForTest;
+    private OutputStream mOutputStreamForTest;
+
+    // Internal state for the device owner package.
+    private String mDeviceOwnerPackageName;
+    private String mDeviceOwnerName;
+
+    // Internal state for the profile owner packages.
+    private final HashMap<Integer, String[]> mProfileOwners = new HashMap<Integer, String[]>();
+
+    // Private default constructor.
+    private DeviceOwner() {
+    }
+
+    @VisibleForTesting
+    DeviceOwner(InputStream in, OutputStream out) {
+        mInputStreamForTest = in;
+        mOutputStreamForTest = out;
+    }
+
+    /**
+     * Loads the device owner state from disk.
+     */
+    static DeviceOwner load() {
+        DeviceOwner owner = new DeviceOwner();
+        if (new File(Environment.getSystemSecureDirectory(), DEVICE_OWNER_XML).exists()) {
+            owner.readOwnerFile();
+            return owner;
+        } else {
+            return null;
+        }
+    }
+
+    /**
+     * Creates an instance of the device owner object with the device owner set.
+     */
+    static DeviceOwner createWithDeviceOwner(String packageName, String ownerName) {
+        DeviceOwner owner = new DeviceOwner();
+        owner.mDeviceOwnerPackageName = packageName;
+        owner.mDeviceOwnerName = ownerName;
+        return owner;
+    }
+
+    /**
+     * Creates an instance of the device owner object with the profile owner set.
+     */
+    static DeviceOwner createWithProfileOwner(String packageName, String ownerName, int userId) {
+        DeviceOwner owner = new DeviceOwner();
+        owner.mProfileOwners.put(userId, new String[] { packageName, ownerName });
+        return owner;
+    }
+
+    String getDeviceOwnerPackageName() {
+        return mDeviceOwnerPackageName;
+    }
+
+    String getDeviceOwnerName() {
+        return mDeviceOwnerName;
+    }
+
+    void setDeviceOwner(String packageName, String ownerName) {
+        mDeviceOwnerPackageName = packageName;
+        mDeviceOwnerName = ownerName;
+    }
+
+    void setProfileOwner(String packageName, String ownerName, int userId) {
+        mProfileOwners.put(userId, new String[] { packageName, ownerName });
+    }
+
+    void removeProfileOwner(int userId) {
+        mProfileOwners.remove(userId);
+    }
+
+    String getProfileOwnerPackageName(int userId) {
+        String[] profileOwner = mProfileOwners.get(userId);
+        return profileOwner != null ? profileOwner[0] : null;
+    }
+
+    String getProfileOwnerName(int userId) {
+        String[] profileOwner = mProfileOwners.get(userId);
+        return profileOwner != null ? profileOwner[1] : null;
+    }
+
+    boolean hasDeviceOwner() {
+        return mDeviceOwnerPackageName != null;
+    }
+
+    static boolean isInstalled(String packageName, PackageManager pm) {
+        try {
+            PackageInfo pi;
+            if ((pi = pm.getPackageInfo(packageName, 0)) != null) {
+                if ((pi.applicationInfo.flags) != 0) {
+                    return true;
+                }
+            }
+        } catch (NameNotFoundException nnfe) {
+            Slog.w(TAG, "Device Owner package " + packageName + " not installed.");
+        }
+        return false;
+    }
+
+    static boolean isInstalledForUser(String packageName, int userHandle) {
+        try {
+            PackageInfo pi = (AppGlobals.getPackageManager())
+                    .getPackageInfo(packageName, 0, userHandle);
+            if (pi != null && pi.applicationInfo.flags != 0) {
+                return true;
+            }
+        } catch (RemoteException re) {
+            throw new RuntimeException("Package manager has died", re);
+        }
+
+        return false;
+    }
+
+    void readOwnerFile() {
+        try {
+            InputStream input = openRead();
+            XmlPullParser parser = Xml.newPullParser();
+            parser.setInput(input, null);
+            int type;
+            while ((type=parser.next()) != XmlPullParser.END_DOCUMENT) {
+                if (type!=XmlPullParser.START_TAG) {
+                    continue;
+                }
+
+                String tag = parser.getName();
+                if (tag.equals(TAG_DEVICE_OWNER)) {
+                    mDeviceOwnerPackageName = parser.getAttributeValue(null, ATTR_PACKAGE);
+                    mDeviceOwnerName = parser.getAttributeValue(null, ATTR_NAME);
+                } else if (tag.equals(TAG_PROFILE_OWNER)) {
+                    String profileOwnerPackageName = parser.getAttributeValue(null, ATTR_PACKAGE);
+                    String profileOwnerName = parser.getAttributeValue(null, ATTR_NAME);
+                    int userId = Integer.parseInt(parser.getAttributeValue(null, ATTR_USERID));
+                    mProfileOwners.put(userId,
+                            new String[] { profileOwnerPackageName, profileOwnerName });
+                } else {
+                    throw new XmlPullParserException(
+                            "Unexpected tag in device owner file: " + tag);
+                }
+            }
+            input.close();
+        } catch (XmlPullParserException xppe) {
+            Slog.e(TAG, "Error parsing device-owner file\n" + xppe);
+        } catch (IOException ioe) {
+            Slog.e(TAG, "IO Exception when reading device-owner file\n" + ioe);
+        }
+    }
+
+    void writeOwnerFile() {
+        synchronized (this) {
+            writeOwnerFileLocked();
+        }
+    }
+
+    private void writeOwnerFileLocked() {
+        try {
+            OutputStream outputStream = startWrite();
+            XmlSerializer out = new FastXmlSerializer();
+            out.setOutput(outputStream, "utf-8");
+            out.startDocument(null, true);
+
+            // Write device owner tag
+            if (mDeviceOwnerPackageName != null) {
+                out.startTag(null, TAG_DEVICE_OWNER);
+                out.attribute(null, ATTR_PACKAGE, mDeviceOwnerPackageName);
+                if (mDeviceOwnerName != null) {
+                    out.attribute(null, ATTR_NAME, mDeviceOwnerName);
+                }
+                out.endTag(null, TAG_DEVICE_OWNER);
+            }
+
+            // Write profile owner tags
+            if (mProfileOwners.size() > 0) {
+                for (HashMap.Entry<Integer, String[]> owner : mProfileOwners.entrySet()) {
+                    out.startTag(null, TAG_PROFILE_OWNER);
+                    out.attribute(null, ATTR_PACKAGE, owner.getValue()[0]);
+                    out.attribute(null, ATTR_NAME, owner.getValue()[1]);
+                    out.attribute(null, ATTR_USERID, Integer.toString(owner.getKey()));
+                    out.endTag(null, TAG_PROFILE_OWNER);
+                }
+            }
+            out.endDocument();
+            out.flush();
+            finishWrite(outputStream);
+        } catch (IOException ioe) {
+            Slog.e(TAG, "IO Exception when writing device-owner file\n" + ioe);
+        }
+    }
+
+    private InputStream openRead() throws IOException {
+        if (mInputStreamForTest != null) {
+            return mInputStreamForTest;
+        }
+
+        return new AtomicFile(new File(Environment.getSystemSecureDirectory(),
+                DEVICE_OWNER_XML)).openRead();
+    }
+
+    private OutputStream startWrite() throws IOException {
+        if (mOutputStreamForTest != null) {
+            return mOutputStreamForTest;
+        }
+
+        fileForWriting = new AtomicFile(new File(Environment.getSystemSecureDirectory(),
+                DEVICE_OWNER_XML));
+        return fileForWriting.startWrite();
+    }
+
+    private void finishWrite(OutputStream stream) {
+        if (fileForWriting != null) {
+            fileForWriting.finishWrite((FileOutputStream) stream);
+        }
+    }
+}
\ No newline at end of file
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 186fbe1..a8f2df1 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -26,10 +26,6 @@
 import com.android.internal.widget.LockPatternUtils;
 import com.android.org.conscrypt.TrustedCertificateStore;
 
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
-import org.xmlpull.v1.XmlSerializer;
-
 import android.app.Activity;
 import android.app.ActivityManagerNative;
 import android.app.AlarmManager;
@@ -49,9 +45,7 @@
 import android.content.IntentFilter;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.IPackageManager;
-import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
-import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.pm.ResolveInfo;
 import android.content.pm.UserInfo;
 import android.net.ProxyProperties;
@@ -75,7 +69,6 @@
 import android.security.IKeyChainService;
 import android.security.KeyChain;
 import android.security.KeyChain.KeyChainConnection;
-import android.util.AtomicFile;
 import android.util.Log;
 import android.util.PrintWriterPrinter;
 import android.util.Printer;
@@ -84,6 +77,10 @@
 import android.util.Xml;
 import android.view.IWindowManager;
 
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlSerializer;
+
 import java.io.ByteArrayInputStream;
 import java.io.File;
 import java.io.FileDescriptor;
@@ -132,6 +129,7 @@
     IWindowManager mIWindowManager;
     NotificationManager mNotificationManager;
 
+    // Stores and loads state on device and profile owners.
     private DeviceOwner mDeviceOwner;
 
     /**
@@ -601,6 +599,10 @@
                 Slog.w(LOG_TAG, "Tried to remove device policy file for user 0! Ignoring.");
                 return;
             }
+
+            mDeviceOwner.removeProfileOwner(userHandle);
+            mDeviceOwner.writeOwnerFile();
+
             DevicePolicyData policy = mUserData.get(userHandle);
             if (policy != null) {
                 mUserData.remove(userHandle);
@@ -614,9 +616,7 @@
 
     void loadDeviceOwner() {
         synchronized (this) {
-            if (DeviceOwner.isRegistered()) {
-                mDeviceOwner = new DeviceOwner();
-            }
+            mDeviceOwner = DeviceOwner.load();
         }
     }
 
@@ -1294,7 +1294,8 @@
             if (admin.getUid() != Binder.getCallingUid()) {
                 // If trying to remove device owner, refuse when the caller is not the owner.
                 if (mDeviceOwner != null
-                        && adminReceiver.getPackageName().equals(mDeviceOwner.getPackageName())) {
+                        && adminReceiver.getPackageName().equals(
+                        mDeviceOwner.getDeviceOwnerPackageName())) {
                     return;
                 }
                 mContext.enforceCallingOrSelfPermission(
@@ -2739,14 +2740,26 @@
                     + " for device owner");
         }
         synchronized (this) {
-            if (mDeviceOwner == null && !isDeviceProvisioned()) {
-                mDeviceOwner = new DeviceOwner(packageName, ownerName);
+            if (isDeviceProvisioned()) {
+                throw new IllegalStateException(
+                        "Trying to set device owner but device is already provisioned.");
+            }
+
+            if (mDeviceOwner != null && mDeviceOwner.hasDeviceOwner()) {
+                throw new IllegalStateException(
+                        "Trying to set device owner but device owner is already set.");
+            }
+
+            if (mDeviceOwner == null) {
+                // Device owner is not set and does not exist, set it.
+                mDeviceOwner = DeviceOwner.createWithDeviceOwner(packageName, ownerName);
                 mDeviceOwner.writeOwnerFile();
                 return true;
             } else {
-                throw new IllegalStateException("Trying to set device owner to " + packageName
-                        + ", owner=" + mDeviceOwner.getPackageName()
-                        + ", device_provisioned=" + isDeviceProvisioned());
+                // Device owner is not set but a profile owner exists, update Device owner state.
+                mDeviceOwner.setDeviceOwner(packageName, ownerName);
+                mDeviceOwner.writeOwnerFile();
+                return true;
             }
         }
     }
@@ -2758,7 +2771,7 @@
         }
         synchronized (this) {
             return mDeviceOwner != null
-                    && mDeviceOwner.getPackageName().equals(packageName);
+                    && mDeviceOwner.getDeviceOwnerPackageName().equals(packageName);
         }
     }
 
@@ -2769,7 +2782,7 @@
         }
         synchronized (this) {
             if (mDeviceOwner != null) {
-                return mDeviceOwner.getPackageName();
+                return mDeviceOwner.getDeviceOwnerPackageName();
             }
         }
         return null;
@@ -2783,7 +2796,67 @@
         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USERS, null);
         synchronized (this) {
             if (mDeviceOwner != null) {
-                return mDeviceOwner.getName();
+                return mDeviceOwner.getDeviceOwnerName();
+            }
+        }
+        return null;
+    }
+
+    @Override
+    public boolean setProfileOwner(String packageName, String ownerName, int userHandle) {
+        if (!mHasFeature) {
+            return false;
+        }
+        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USERS, null);
+        if (packageName == null
+                || !DeviceOwner.isInstalledForUser(packageName, userHandle)) {
+            throw new IllegalArgumentException("Package name " + packageName
+                    + " not installed for userId:" + userHandle);
+        }
+        synchronized (this) {
+            if (isUserSetupComplete(userHandle)) {
+                throw new IllegalStateException(
+                        "Trying to set profile owner but user is already set-up.");
+            }
+            if (mDeviceOwner == null) {
+                // Device owner state does not exist, create it.
+                mDeviceOwner = DeviceOwner.createWithProfileOwner(packageName, ownerName,
+                        userHandle);
+                mDeviceOwner.writeOwnerFile();
+                return true;
+            } else {
+                // Device owner already exists, update it.
+                mDeviceOwner.setProfileOwner(packageName, ownerName, userHandle);
+                mDeviceOwner.writeOwnerFile();
+                return true;
+            }
+        }
+    }
+
+    @Override
+    public String getProfileOwner(int userHandle) {
+        if (!mHasFeature) {
+            return null;
+        }
+
+        synchronized (this) {
+            if (mDeviceOwner != null) {
+                return mDeviceOwner.getProfileOwnerPackageName(userHandle);
+            }
+        }
+        return null;
+    }
+
+    @Override
+    public String getProfileOwnerName(int userHandle) {
+        if (!mHasFeature) {
+            return null;
+        }
+        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USERS, null);
+
+        synchronized (this) {
+            if (mDeviceOwner != null) {
+                return mDeviceOwner.getProfileOwnerName(userHandle);
             }
         }
         return null;
@@ -2794,6 +2867,11 @@
                 Settings.Global.DEVICE_PROVISIONED, 0) > 0;
     }
 
+    private boolean isUserSetupComplete(int userId) {
+        return Settings.Secure.getIntForUser(mContext.getContentResolver(),
+                Settings.Secure.USER_SETUP_COMPLETE, 0, userId) > 0;
+    }
+
     private void enforceCrossUserPermission(int userHandle) {
         if (userHandle < 0) {
             throw new IllegalArgumentException("Invalid userId " + userHandle);
@@ -2858,103 +2936,4 @@
             }
         }
     }
-
-    static class DeviceOwner {
-        private static final String DEVICE_OWNER_XML = "device_owner.xml";
-        private static final String TAG_DEVICE_OWNER = "device-owner";
-        private static final String ATTR_NAME = "name";
-        private static final String ATTR_PACKAGE = "package";
-        private String mPackageName;
-        private String mOwnerName;
-
-        DeviceOwner() {
-            readOwnerFile();
-        }
-
-        DeviceOwner(String packageName, String ownerName) {
-            this.mPackageName = packageName;
-            this.mOwnerName = ownerName;
-        }
-
-        static boolean isRegistered() {
-            return new File(Environment.getSystemSecureDirectory(),
-                    DEVICE_OWNER_XML).exists();
-        }
-
-        String getPackageName() {
-            return mPackageName;
-        }
-
-        String getName() {
-            return mOwnerName;
-        }
-
-        static boolean isInstalled(String packageName, PackageManager pm) {
-            try {
-                PackageInfo pi;
-                if ((pi = pm.getPackageInfo(packageName, 0)) != null) {
-                    if ((pi.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
-                        return true;
-                    }
-                }
-            } catch (NameNotFoundException nnfe) {
-                Slog.w(LOG_TAG, "Device Owner package " + packageName + " not installed.");
-            }
-            return false;
-        }
-
-        void readOwnerFile() {
-            AtomicFile file = new AtomicFile(new File(Environment.getSystemSecureDirectory(),
-                    DEVICE_OWNER_XML));
-            try {
-                FileInputStream input = file.openRead();
-                XmlPullParser parser = Xml.newPullParser();
-                parser.setInput(input, null);
-                int type;
-                while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
-                        && type != XmlPullParser.START_TAG) {
-                }
-                String tag = parser.getName();
-                if (!TAG_DEVICE_OWNER.equals(tag)) {
-                    throw new XmlPullParserException(
-                            "Device Owner file does not start with device-owner tag: found " + tag);
-                }
-                mPackageName = parser.getAttributeValue(null, ATTR_PACKAGE);
-                mOwnerName = parser.getAttributeValue(null, ATTR_NAME);
-                input.close();
-            } catch (XmlPullParserException xppe) {
-                Slog.e(LOG_TAG, "Error parsing device-owner file\n" + xppe);
-            } catch (IOException ioe) {
-                Slog.e(LOG_TAG, "IO Exception when reading device-owner file\n" + ioe);
-            }
-        }
-
-        void writeOwnerFile() {
-            synchronized (this) {
-                writeOwnerFileLocked();
-            }
-        }
-
-        private void writeOwnerFileLocked() {
-            AtomicFile file = new AtomicFile(new File(Environment.getSystemSecureDirectory(),
-                    DEVICE_OWNER_XML));
-            try {
-                FileOutputStream output = file.startWrite();
-                XmlSerializer out = new FastXmlSerializer();
-                out.setOutput(output, "utf-8");
-                out.startDocument(null, true);
-                out.startTag(null, TAG_DEVICE_OWNER);
-                out.attribute(null, ATTR_PACKAGE, mPackageName);
-                if (mOwnerName != null) {
-                    out.attribute(null, ATTR_NAME, mOwnerName);
-                }
-                out.endTag(null, TAG_DEVICE_OWNER);
-                out.endDocument();
-                out.flush();
-                file.finishWrite(output);
-            } catch (IOException ioe) {
-                Slog.e(LOG_TAG, "IO Exception when writing device-owner file\n" + ioe);
-            }
-        }
-    }
 }
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DeviceOwnerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DeviceOwnerTest.java
new file mode 100644
index 0000000..f913b97
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DeviceOwnerTest.java
@@ -0,0 +1,88 @@
+/*
+ * 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.
+ */
+
+package com.android.server.devicepolicy;
+
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+
+/**
+ * Tests for the DeviceOwner object that saves & loads device and policy owner information.
+ * run this test with:
+ *   make -j FrameworksServicesTests
+ *   runtest --path frameworks/base/services/tests/servicestests/ \
+ *       src/com/android/server/devicepolicy/DeviceOwnerTest.java
+ */
+public class DeviceOwnerTest extends AndroidTestCase {
+
+    private ByteArrayInputStream mInputStreamForTest;
+    private ByteArrayOutputStream mOutputStreamForTest = new ByteArrayOutputStream();
+
+    @SmallTest
+    public void testDeviceOwnerOnly() throws Exception {
+        DeviceOwner out = new DeviceOwner(null, mOutputStreamForTest);
+        out.setDeviceOwner("some.device.owner.package", "owner");
+        out.writeOwnerFile();
+
+        mInputStreamForTest = new ByteArrayInputStream(mOutputStreamForTest.toByteArray());
+        DeviceOwner in = new DeviceOwner(mInputStreamForTest, null);
+        in.readOwnerFile();
+
+        assertEquals("some.device.owner.package", in.getDeviceOwnerPackageName());
+        assertEquals("owner", in.getDeviceOwnerName());
+        assertNull(in.getProfileOwnerPackageName(1));
+    }
+
+    @SmallTest
+    public void testProfileOwnerOnly() throws Exception {
+        DeviceOwner out = new DeviceOwner(null, mOutputStreamForTest);
+        out.setProfileOwner("some.profile.owner.package", "some-company", 1);
+        out.writeOwnerFile();
+
+        mInputStreamForTest = new ByteArrayInputStream(mOutputStreamForTest.toByteArray());
+        DeviceOwner in = new DeviceOwner(mInputStreamForTest, null);
+        in.readOwnerFile();
+
+        assertNull(in.getDeviceOwnerPackageName());
+        assertNull(in.getDeviceOwnerName());
+        assertEquals("some.profile.owner.package", in.getProfileOwnerPackageName(1));
+        assertEquals("some-company", in.getProfileOwnerName(1));
+    }
+
+    @SmallTest
+    public void testDeviceAndProfileOwners() throws Exception {
+        DeviceOwner out = new DeviceOwner(null, mOutputStreamForTest);
+        out.setDeviceOwner("some.device.owner.package", "owner");
+        out.setProfileOwner("some.profile.owner.package", "some-company", 1);
+        out.setProfileOwner("some.other.profile.owner", "some-other-company", 2);
+        out.writeOwnerFile();
+
+        mInputStreamForTest = new ByteArrayInputStream(mOutputStreamForTest.toByteArray());
+
+        DeviceOwner in = new DeviceOwner(mInputStreamForTest, null);
+        in.readOwnerFile();
+
+        assertEquals("some.device.owner.package", in.getDeviceOwnerPackageName());
+        assertEquals("owner", in.getDeviceOwnerName());
+        assertEquals("some.profile.owner.package", in.getProfileOwnerPackageName(1));
+        assertEquals("some-company", in.getProfileOwnerName(1));
+        assertEquals("some.other.profile.owner", in.getProfileOwnerPackageName(2));
+        assertEquals("some-other-company", in.getProfileOwnerName(2));
+    }
+}
\ No newline at end of file
diff --git a/tools/layoutlib/Android.mk b/tools/layoutlib/Android.mk
index ed497a5..1fa9615 100644
--- a/tools/layoutlib/Android.mk
+++ b/tools/layoutlib/Android.mk
@@ -33,6 +33,8 @@
 
 built_ext_dep := $(call java-lib-deps,ext)
 built_ext_classes := $(call java-lib-files,ext)
+built_ext_data := $(call intermediates-dir-for, \
+			JAVA_LIBRARIES,ext,,COMMON)/javalib.jar
 
 built_layoutlib_create_jar := $(call intermediates-dir-for, \
 			JAVA_LIBRARIES,layoutlib_create,HOST)/javalib.jar
@@ -60,7 +62,8 @@
 	             $@ \
 	             $(built_core_classes) \
 	             $(built_framework_classes) \
-	             $(built_ext_classes)
+	             $(built_ext_classes) \
+	             $(built_ext_data)
 	$(hide) ls -l $(built_framework_classes)
 
 
diff --git a/tools/layoutlib/bridge/src/android/graphics/BidiRenderer.java b/tools/layoutlib/bridge/src/android/graphics/BidiRenderer.java
index 62d0a0d..e1b3f92 100644
--- a/tools/layoutlib/bridge/src/android/graphics/BidiRenderer.java
+++ b/tools/layoutlib/bridge/src/android/graphics/BidiRenderer.java
@@ -20,6 +20,7 @@
 import java.awt.Graphics2D;
 import java.awt.font.FontRenderContext;
 import java.awt.font.GlyphVector;
+import java.awt.geom.Rectangle2D;
 import java.util.LinkedList;
 import java.util.List;
 
@@ -27,6 +28,7 @@
 import com.ibm.icu.lang.UScriptRun;
 
 import android.graphics.Paint_Delegate.FontInfo;
+import android.graphics.RectF;;
 
 /**
  * Render the text by breaking it into various scripts and using the right font for each script.
@@ -50,9 +52,11 @@
         }
     }
 
-    /* package */ Graphics2D graphics;
-    /* package */ Paint_Delegate paint;
-    /* package */ char[] text;
+    private Graphics2D graphics;
+    private Paint_Delegate paint;
+    private char[] text;
+    // Bounds of the text drawn so far.
+    private RectF bounds;
 
     /**
      * @param graphics May be null.
@@ -82,56 +86,54 @@
      * @param x The x-coordinate of the left edge of where the text should be drawn on the given
      *            graphics.
      * @param y The y-coordinate at which to draw the text on the given graphics.
-     * @return The x-coordinate of the right edge of the drawn text. In other words,
-     *            x + the width of the text.
+     * @return A rectangle specifying the bounds of the text drawn.
      */
-    /* package */ float renderText(int start, int limit, boolean isRtl, float advances[],
+    /* package */ RectF renderText(int start, int limit, boolean isRtl, float advances[],
             int advancesIndex, boolean draw, float x, float y) {
         // We break the text into scripts and then select font based on it and then render each of
         // the script runs.
+        bounds = new RectF(x, y, x, y);
         for (ScriptRun run : getScriptRuns(text, start, limit, isRtl, paint.getFonts())) {
             int flag = Font.LAYOUT_NO_LIMIT_CONTEXT | Font.LAYOUT_NO_START_CONTEXT;
             flag |= isRtl ? Font.LAYOUT_RIGHT_TO_LEFT : Font.LAYOUT_LEFT_TO_RIGHT;
-            x = renderScript(run.start, run.limit, run.font, flag, advances, advancesIndex, draw,
-                    x, y);
+            renderScript(run.start, run.limit, run.font, flag, advances, advancesIndex, draw);
             advancesIndex += run.limit - run.start;
         }
-        return x;
+        return bounds;
     }
 
     /**
-     * Render a script run. Use the preferred font to render as much as possible. This also
-     * implements a fallback mechanism to render characters that cannot be drawn using the
-     * preferred font.
-     *
-     * @return x + width of the text drawn.
+     * Render a script run to the right of the bounds passed. Use the preferred font to render as
+     * much as possible. This also implements a fallback mechanism to render characters that cannot
+     * be drawn using the preferred font.
      */
-    private float renderScript(int start, int limit, FontInfo preferredFont, int flag,
-            float advances[], int advancesIndex, boolean draw, float x, float y) {
+    private void renderScript(int start, int limit, FontInfo preferredFont, int flag,
+            float advances[], int advancesIndex, boolean draw) {
         List<FontInfo> fonts = paint.getFonts();
         if (fonts == null || preferredFont == null) {
-            return x;
+            return;
         }
 
         while (start < limit) {
             boolean foundFont = false;
             int canDisplayUpTo = preferredFont.mFont.canDisplayUpTo(text, start, limit);
             if (canDisplayUpTo == -1) {
-                return render(start, limit, preferredFont, flag, advances, advancesIndex, draw,
-                        x, y);
+                // We can draw all characters in the text.
+                render(start, limit, preferredFont, flag, advances, advancesIndex, draw);
+                return;
             } else if (canDisplayUpTo > start) { // can draw something
-                x = render(start, canDisplayUpTo, preferredFont, flag, advances, advancesIndex,
-                        draw, x, y);
+                render(start, canDisplayUpTo, preferredFont, flag, advances, advancesIndex, draw);
                 advancesIndex += canDisplayUpTo - start;
                 start = canDisplayUpTo;
             }
 
+            // The current character cannot be drawn with the preferred font. Cycle through all the
+            // fonts to check which one can draw it.
             int charCount = Character.isHighSurrogate(text[start]) ? 2 : 1;
             for (FontInfo font : fonts) {
                 canDisplayUpTo = font.mFont.canDisplayUpTo(text, start, start + charCount);
                 if (canDisplayUpTo == -1) {
-                    x = render(start, start+charCount, font, flag, advances, advancesIndex, draw,
-                            x, y);
+                    render(start, start+charCount, font, flag, advances, advancesIndex, draw);
                     start += charCount;
                     advancesIndex += charCount;
                     foundFont = true;
@@ -143,22 +145,20 @@
                 // probably appear as a box or a blank space. We could, probably, use some
                 // heuristics and break the character into the base character and diacritics and
                 // then draw it, but it's probably not worth the effort.
-                x = render(start, start + charCount, preferredFont, flag, advances, advancesIndex,
-                        draw, x, y);
+                render(start, start + charCount, preferredFont, flag, advances, advancesIndex,
+                        draw);
                 start += charCount;
                 advancesIndex += charCount;
             }
         }
-        return x;
     }
 
     /**
-     * Render the text with the given font.
+     * Render the text with the given font to the right of the bounds passed.
      */
-    private float render(int start, int limit, FontInfo font, int flag, float advances[],
-            int advancesIndex, boolean draw, float x, float y) {
+    private void render(int start, int limit, FontInfo font, int flag, float advances[],
+            int advancesIndex, boolean draw) {
 
-        float totalAdvance = 0;
         // Since the metrics don't have anti-aliasing set, we create a new FontRenderContext with
         // the anti-aliasing set.
         FontRenderContext f = font.mMetrics.getFontRenderContext();
@@ -173,12 +173,29 @@
                 int adv_idx = advancesIndex + ci[i];
                 advances[adv_idx] += adv;
             }
-            totalAdvance += adv;
         }
         if (draw && graphics != null) {
-            graphics.drawGlyphVector(gv, x, y);
+            graphics.drawGlyphVector(gv, bounds.right, bounds.bottom);
         }
-        return x + totalAdvance;
+        Rectangle2D awtBounds = gv.getVisualBounds();
+        RectF visualBounds = awtRectToAndroidRect(awtBounds, bounds.right, bounds.bottom);
+        // If the width of the bounds is zero, no text has been drawn yet. Hence, use the
+        // coordinates from the bounds as an offset only.
+        if (Math.abs(bounds.right - bounds.left) == 0) {
+            bounds = visualBounds;
+        } else {
+            bounds.union(visualBounds);
+        }
+    }
+
+    private RectF awtRectToAndroidRect(Rectangle2D awtRec, float offsetX, float offsetY) {
+        float left = (float) awtRec.getX();
+        float top = (float) awtRec.getY();
+        float right = (float) (left + awtRec.getWidth());
+        float bottom = (float) (top + awtRec.getHeight());
+        RectF androidRect = new RectF(left, top, right, bottom);
+        androidRect.offset(offsetX, offsetY);
+        return androidRect;
     }
 
     // --- Static helper methods ---
diff --git a/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java
index 602717b..1cc8ea5 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java
@@ -991,7 +991,8 @@
                 int limit = index + count;
                 boolean isRtl = flags == Canvas.DIRECTION_RTL;
                 if (paintDelegate.getTextAlign() != Paint.Align.LEFT.nativeInt) {
-                    float m = paintDelegate.measureText(text, index, count, isRtl);
+                    RectF bounds = paintDelegate.measureText(text, index, count, isRtl);
+                    float m = bounds.right - bounds.left;
                     if (paintDelegate.getTextAlign() == Paint.Align.CENTER.nativeInt) {
                         x -= m / 2;
                     } else if (paintDelegate.getTextAlign() == Paint.Align.RIGHT.nativeInt) {
diff --git a/tools/layoutlib/bridge/src/android/graphics/NinePatch_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/NinePatch_Delegate.java
index 38745ce..74b2893 100644
--- a/tools/layoutlib/bridge/src/android/graphics/NinePatch_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/NinePatch_Delegate.java
@@ -176,7 +176,7 @@
     /*package*/ static void nativeDraw(long canvas_instance, RectF loc, long bitmap_instance,
             long chunk, long paint_instance_or_null, int destDensity, int srcDensity) {
         draw(canvas_instance,
-                (int) loc.left, (int) loc.top, (int) loc.width(), (int) loc.height(),
+                (int) loc.left, (int) loc.top, (int) loc.right, (int) loc.bottom,
                 bitmap_instance, chunk, paint_instance_or_null,
                 destDensity, srcDensity);
     }
@@ -185,7 +185,7 @@
     /*package*/ static void nativeDraw(long canvas_instance, Rect loc, long bitmap_instance,
             long chunk, long paint_instance_or_null, int destDensity, int srcDensity) {
         draw(canvas_instance,
-                loc.left, loc.top, loc.width(), loc.height(),
+                loc.left, loc.top, loc.right, loc.bottom,
                 bitmap_instance, chunk, paint_instance_or_null,
                 destDensity, srcDensity);
     }
diff --git a/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java
index ca8e8aa..7007b71 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java
@@ -575,7 +575,8 @@
             return 0;
         }
 
-        return delegate.measureText(text, index, count, isRtl(bidiFlags));
+        RectF bounds = delegate.measureText(text, index, count, isRtl(bidiFlags));
+        return bounds.right - bounds.left;
     }
 
     @LayoutlibDelegate
@@ -614,7 +615,8 @@
             }
 
             // measure from start to end
-            float res = delegate.measureText(text, start, end - start + 1, isRtl(bidiFlags));
+            RectF bounds = delegate.measureText(text, start, end - start + 1, isRtl(bidiFlags));
+            float res = bounds.right - bounds.left;
 
             if (measuredWidth != null) {
                 measuredWidth[measureIndex] = res;
@@ -991,8 +993,9 @@
         boolean isRtl = isRtl(flags);
 
         int limit = index + count;
-        return new BidiRenderer(null, delegate, text).renderText(
+        RectF bounds = new BidiRenderer(null, delegate, text).renderText(
                 index, limit, isRtl, advances, advancesIndex, false, 0, 0);
+        return bounds.right - bounds.left;
     }
 
     @LayoutlibDelegate
@@ -1058,9 +1061,7 @@
         if (delegate == null || delegate.mFonts == null || delegate.mFonts.size() == 0) {
             return;
         }
-        int w = (int) delegate.measureText(text, index, count, isRtl(bidiFlags));
-        int h= delegate.getFonts().get(0).mMetrics.getHeight();
-        bounds.set(0, 0, w, h);
+        delegate.measureText(text, index, count, isRtl(bidiFlags)).roundOut(bounds);
     }
 
     @LayoutlibDelegate
@@ -1154,7 +1155,7 @@
         }
     }
 
-    /*package*/ float measureText(char[] text, int index, int count, boolean isRtl) {
+    /*package*/ RectF measureText(char[] text, int index, int count, boolean isRtl) {
         return new BidiRenderer(null, this, text).renderText(
                 index, index + count, isRtl, null, 0, false, 0, 0);
     }
diff --git a/tools/layoutlib/bridge/src/android/text/format/Time_Delegate.java b/tools/layoutlib/bridge/src/android/text/format/Time_Delegate.java
index 15cd687..320dd0d 100644
--- a/tools/layoutlib/bridge/src/android/text/format/Time_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/text/format/Time_Delegate.java
@@ -17,6 +17,7 @@
 package android.text.format;
 
 import java.util.Calendar;
+import java.util.TimeZone;
 import java.util.UnknownFormatConversionException;
 import java.util.regex.Pattern;
 
@@ -35,6 +36,28 @@
     // Regex to match odd number of '%'.
     private static final Pattern p = Pattern.compile("(?<!%)(%%)*%(?!%)");
 
+    // Format used by toString()
+    private static final String FORMAT = "%1$tY%1$tm%1$tdT%1$tH%1$tM%1$tS<%1$tZ>";
+
+    @LayoutlibDelegate
+    /*package*/ static long normalize(Time thisTime, boolean ignoreDst) {
+        long millis = toMillis(thisTime, ignoreDst);
+        set(thisTime, millis);
+        return millis;
+    }
+
+    @LayoutlibDelegate
+    /*package*/ static void switchTimezone(Time thisTime, String timezone) {
+        Calendar c = timeToCalendar(thisTime);
+        c.setTimeZone(TimeZone.getTimeZone(timezone));
+        calendarToTime(c, thisTime);
+    }
+
+    @LayoutlibDelegate
+    /*package*/ static int nativeCompare(Time a, Time b) {
+      return timeToCalendar(a).compareTo(timeToCalendar(b));
+    }
+
     @LayoutlibDelegate
     /*package*/ static String format1(Time thisTime, String format) {
 
@@ -46,16 +69,92 @@
             // of $.
             return String.format(
                     p.matcher(format).replaceAll("$0\\1\\$t"),
-                    timeToCalendar(thisTime, Calendar.getInstance()));
+                    timeToCalendar(thisTime));
         } catch (UnknownFormatConversionException e) {
             Bridge.getLog().fidelityWarning(LayoutLog.TAG_STRFTIME, "Unrecognized format", e, format);
             return format;
         }
     }
 
-    private static Calendar timeToCalendar(Time time, Calendar calendar) {
+    /**
+     * Return the current time in YYYYMMDDTHHMMSS<tz> format
+     */
+    @LayoutlibDelegate
+    /*package*/ static String toString(Time thisTime) {
+        Calendar c = timeToCalendar(thisTime);
+        return String.format(FORMAT, c);
+    }
+
+    @LayoutlibDelegate
+    /*package*/ static boolean nativeParse(Time thisTime, String s) {
+        Bridge.getLog().error(LayoutLog.TAG_UNSUPPORTED,
+                "android.text.format.Time.parse() not supported.", null);
+        return false;
+    }
+
+    @LayoutlibDelegate
+    /*package*/ static boolean nativeParse3339(Time thisTime, String s) {
+        Bridge.getLog().error(LayoutLog.TAG_UNSUPPORTED,
+                "android.text.format.Time.parse3339() not supported.", null);
+        return false;
+    }
+
+    @LayoutlibDelegate
+    /*package*/ static void setToNow(Time thisTime) {
+        calendarToTime(getCalendarInstance(thisTime), thisTime);
+    }
+
+    @LayoutlibDelegate
+    /*package*/ static long toMillis(Time thisTime, boolean ignoreDst) {
+        // TODO: Respect ignoreDst.
+        return timeToCalendar(thisTime).getTimeInMillis();
+    }
+
+    @LayoutlibDelegate
+    /*package*/ static void set(Time thisTime, long millis) {
+        Calendar c = getCalendarInstance(thisTime);
+        c.setTimeInMillis(millis);
+        calendarToTime(c,thisTime);
+    }
+
+    @LayoutlibDelegate
+    /*package*/ static String format2445(Time thisTime) {
+        Bridge.getLog().error(LayoutLog.TAG_UNSUPPORTED,
+                "android.text.format.Time.format2445() not supported.", null);
+        return "";
+    }
+
+    // ---- private helper methods ----
+
+    private static Calendar timeToCalendar(Time time) {
+        Calendar calendar = getCalendarInstance(time);
         calendar.set(time.year, time.month, time.monthDay, time.hour, time.minute, time.second);
         return calendar;
     }
 
+    private static void calendarToTime(Calendar c, Time time) {
+        time.timezone = c.getTimeZone().getID();
+        time.set(c.get(Calendar.SECOND), c.get(Calendar.MINUTE), c.get(Calendar.HOUR_OF_DAY),
+                c.get(Calendar.DATE), c.get(Calendar.MONTH), c.get(Calendar.YEAR));
+        time.weekDay = c.get(Calendar.DAY_OF_WEEK);
+        time.yearDay = c.get(Calendar.DAY_OF_YEAR);
+        time.isDst = c.getTimeZone().inDaylightTime(c.getTime()) ? 1 : 0;
+        // gmtoff is in seconds and TimeZone.getOffset() returns milliseconds.
+        time.gmtoff = c.getTimeZone().getOffset(c.getTimeInMillis()) / DateUtils.SECOND_IN_MILLIS;
+    }
+
+    /**
+     * Return a calendar instance with the correct timezone.
+     *
+     * @param time Time to obtain the timezone from.
+     */
+    private static Calendar getCalendarInstance(Time time) {
+        // TODO: Check platform code to make sure the behavior is same for null/invalid timezone.
+        if (time == null || time.timezone == null) {
+            // Default to local timezone.
+            return Calendar.getInstance();
+        }
+        // If timezone is invalid, use GMT.
+        return Calendar.getInstance(TimeZone.getTimeZone(time.timezone));
+    }
 }
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java
index 57771e3..377d996 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java
@@ -334,7 +334,7 @@
                 backgroundView = backgroundLayout;
                 backgroundLayout.setOrientation(LinearLayout.VERTICAL);
                 LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(
-                        LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
+                        LayoutParams.MATCH_PARENT, 0);
                 layoutParams.weight = 1;
                 backgroundLayout.setLayoutParams(layoutParams);
                 topLayout.addView(backgroundLayout);
@@ -369,7 +369,7 @@
                 // content frame
                 mContentRoot = new FrameLayout(context);
                 layoutParams = new LinearLayout.LayoutParams(
-                        LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
+                        LayoutParams.MATCH_PARENT, 0);
                 layoutParams.weight = 1;
                 mContentRoot.setLayoutParams(layoutParams);
                 backgroundLayout.addView(mContentRoot);
diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/AsmAnalyzer.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/AsmAnalyzer.java
index 1572a40..9a31705 100644
--- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/AsmAnalyzer.java
+++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/AsmAnalyzer.java
@@ -29,6 +29,7 @@
 import org.objectweb.asm.signature.SignatureVisitor;
 
 import java.io.IOException;
+import java.io.InputStream;
 import java.util.ArrayList;
 import java.util.Enumeration;
 import java.util.List;
@@ -60,6 +61,9 @@
     private final String[] mIncludeGlobs;
     /** The set of classes to exclude.*/
     private final Set<String> mExcludedClasses;
+    /** Glob patterns of files to keep as is. */
+    private final String[] mIncludeFileGlobs;
+    /** Copy these files into the output as is. */
 
     /**
      * Creates a new analyzer.
@@ -70,15 +74,19 @@
      * @param deriveFrom Keep all classes that derive from these one (these included).
      * @param includeGlobs Glob patterns of classes to keep, e.g. "com.foo.*"
      *        ("*" does not matches dots whilst "**" does, "." and "$" are interpreted as-is)
+     * @param includeFileGlobs Glob patterns of files which are kept as is. This is only for files
+     *        not ending in .class.
      */
     public AsmAnalyzer(Log log, List<String> osJarPath, AsmGenerator gen,
-            String[] deriveFrom, String[] includeGlobs, Set<String> excludeClasses) {
+            String[] deriveFrom, String[] includeGlobs, Set<String> excludeClasses,
+            String[] includeFileGlobs) {
         mLog = log;
         mGen = gen;
         mOsSourceJar = osJarPath != null ? osJarPath : new ArrayList<String>();
         mDeriveFrom = deriveFrom != null ? deriveFrom : new String[0];
         mIncludeGlobs = includeGlobs != null ? includeGlobs : new String[0];
         mExcludedClasses = excludeClasses;
+        mIncludeFileGlobs = includeFileGlobs != null ? includeFileGlobs : new String[0];
     }
 
     /**
@@ -86,7 +94,11 @@
      * Fills the generator with classes & dependencies found.
      */
     public void analyze() throws IOException, LogAbortException {
-        Map<String, ClassReader> zipClasses = parseZip(mOsSourceJar);
+
+        TreeMap<String, ClassReader> zipClasses = new TreeMap<String, ClassReader>();
+        Map<String, InputStream> filesFound = new TreeMap<String, InputStream>();
+
+        parseZip(mOsSourceJar, zipClasses, filesFound);
         mLog.info("Found %d classes in input JAR%s.", zipClasses.size(),
                 mOsSourceJar.size() > 1 ? "s" : "");
 
@@ -96,15 +108,29 @@
         if (mGen != null) {
             mGen.setKeep(found);
             mGen.setDeps(deps);
+            mGen.setCopyFiles(filesFound);
         }
     }
 
     /**
-     * Parses a JAR file and returns a list of all classes founds using a map
-     * class name => ASM ClassReader. Class names are in the form "android.view.View".
+     * Parses a JAR file and adds all the classes found to <code>classes</code>
+     * and all other files to <code>filesFound</code>.
+     *
+     * @param classes The map of class name => ASM ClassReader. Class names are
+     *                in the form "android.view.View".
+     * @param fileFound The map of file name => InputStream. The file name is
+     *                  in the form "android/data/dataFile".
      */
-    Map<String,ClassReader> parseZip(List<String> jarPathList) throws IOException {
-        TreeMap<String, ClassReader> classes = new TreeMap<String, ClassReader>();
+    void parseZip(List<String> jarPathList, Map<String, ClassReader> classes,
+            Map<String, InputStream> filesFound) throws IOException {
+        if (classes == null || filesFound == null) {
+            return;
+        }
+
+        Pattern[] includeFilePatterns = new Pattern[mIncludeFileGlobs.length];
+        for (int i = 0; i < mIncludeFileGlobs.length; ++i) {
+            includeFilePatterns[i] = getPatternFromGlob(mIncludeFileGlobs[i]);
+        }
 
         for (String jarPath : jarPathList) {
             ZipFile zip = new ZipFile(jarPath);
@@ -116,11 +142,17 @@
                     ClassReader cr = new ClassReader(zip.getInputStream(entry));
                     String className = classReaderToClassName(cr);
                     classes.put(className, cr);
+                } else {
+                    for (int i = 0; i < includeFilePatterns.length; ++i) {
+                        if (includeFilePatterns[i].matcher(entry.getName()).matches()) {
+                            filesFound.put(entry.getName(), zip.getInputStream(entry));
+                            break;
+                        }
+                    }
                 }
             }
         }
 
-        return classes;
     }
 
     /**
@@ -202,7 +234,19 @@
      */
     void findGlobs(String globPattern, Map<String, ClassReader> zipClasses,
             Map<String, ClassReader> inOutFound) throws LogAbortException {
-        // transforms the glob pattern in a regexp:
+
+        Pattern regexp = getPatternFromGlob(globPattern);
+
+        for (Entry<String, ClassReader> entry : zipClasses.entrySet()) {
+            String class_name = entry.getKey();
+            if (regexp.matcher(class_name).matches()) {
+                findClass(class_name, zipClasses, inOutFound);
+            }
+        }
+    }
+
+    Pattern getPatternFromGlob(String globPattern) {
+     // transforms the glob pattern in a regexp:
         // - escape "." with "\."
         // - replace "*" by "[^.]*"
         // - escape "$" with "\$"
@@ -216,14 +260,7 @@
         globPattern = globPattern.replaceAll("@", ".*");
         globPattern += "$";
 
-        Pattern regexp = Pattern.compile(globPattern);
-
-        for (Entry<String, ClassReader> entry : zipClasses.entrySet()) {
-            String class_name = entry.getKey();
-            if (regexp.matcher(class_name).matches()) {
-                findClass(class_name, zipClasses, inOutFound);
-            }
-        }
+        return Pattern.compile(globPattern);
     }
 
     /**
diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/AsmGenerator.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/AsmGenerator.java
index b102561..207d8ae 100644
--- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/AsmGenerator.java
+++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/AsmGenerator.java
@@ -20,6 +20,7 @@
 import org.objectweb.asm.ClassVisitor;
 import org.objectweb.asm.ClassWriter;
 
+import java.io.ByteArrayOutputStream;
 import java.io.FileNotFoundException;
 import java.io.FileOutputStream;
 import java.io.IOException;
@@ -52,6 +53,8 @@
     private Map<String, ClassReader> mKeep;
     /** All dependencies that must be completely stubbed. */
     private Map<String, ClassReader> mDeps;
+    /** All files that are to be copied as-is. */
+    private Map<String, InputStream> mCopyFiles;
     /** Counter of number of classes renamed during transform. */
     private int mRenameCount;
     /** FQCN Names of the classes to rename: map old-FQCN => new-FQCN */
@@ -195,6 +198,11 @@
         mDeps = deps;
     }
 
+    /** Sets the map of files to output as-is. */
+    public void setCopyFiles(Map<String, InputStream> copyFiles) {
+        mCopyFiles = copyFiles;
+    }
+
     /** Gets the map of classes to output as-is, except if they have native methods */
     public Map<String, ClassReader> getKeep() {
         return mKeep;
@@ -205,6 +213,11 @@
         return mDeps;
     }
 
+    /** Gets the map of files to output as-is. */
+    public Map<String, InputStream> getCopyFiles() {
+        return mCopyFiles;
+    }
+
     /** Generates the final JAR */
     public void generate() throws FileNotFoundException, IOException {
         TreeMap<String, byte[]> all = new TreeMap<String, byte[]>();
@@ -232,6 +245,15 @@
             all.put(name, b);
         }
 
+        for (Entry<String, InputStream> entry : mCopyFiles.entrySet()) {
+            try {
+                byte[] b = inputStreamToByteArray(entry.getValue());
+                all.put(entry.getKey(), b);
+            } catch (IOException e) {
+                // Ignore.
+            }
+
+        }
         mLog.info("# deps classes: %d", mDeps.size());
         mLog.info("# keep classes: %d", mKeep.size());
         mLog.info("# renamed     : %d", mRenameCount);
@@ -381,4 +403,13 @@
         return cv.hasNativeMethods();
     }
 
+    private byte[] inputStreamToByteArray(InputStream is) throws IOException {
+        ByteArrayOutputStream buffer = new ByteArrayOutputStream();
+        byte[] data = new byte[8192];  // 8KB
+        int n;
+        while ((n = is.read(data, 0, data.length)) != -1) {
+            buffer.write(data, 0, n);
+        }
+        return buffer.toByteArray();
+    }
 }
diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java
index f6779e3..79aa642 100644
--- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java
+++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java
@@ -131,7 +131,6 @@
         "android.os.HandlerThread#run",
         "android.os.Build#getString",
         "android.text.format.DateFormat#is24HourFormat",
-        "android.text.format.Time#format1",
         "android.view.Choreographer#getRefreshRate",
         "android.view.Display#updateDisplayInfoLocked",
         "android.view.LayoutInflater#rInflate",
@@ -188,6 +187,7 @@
         "android.graphics.Xfermode",
         "android.os.SystemClock",
         "android.text.AndroidBidi",
+        "android.text.format.Time",
         "android.util.FloatMath",
         "android.view.Display",
         "libcore.icu.DateIntervalFormat",
diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/Main.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/Main.java
index ee501d2..a79fba1 100644
--- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/Main.java
+++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/Main.java
@@ -115,7 +115,10 @@
                         "android.database.ContentObserver", // for Digital clock
                         "com.android.i18n.phonenumbers.*",  // for TextView with autolink attribute
                     },
-                    excludeClasses);
+                    excludeClasses,
+                    new String[] {
+                        "com/android/i18n/phonenumbers/data/*",
+                    });
             aa.analyze();
             agen.generate();
 
diff --git a/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/AsmAnalyzerTest.java b/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/AsmAnalyzerTest.java
index 005fc9d..7ec0d38 100644
--- a/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/AsmAnalyzerTest.java
+++ b/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/AsmAnalyzerTest.java
@@ -29,6 +29,7 @@
 import org.objectweb.asm.ClassReader;
 
 import java.io.IOException;
+import java.io.InputStream;
 import java.net.URL;
 import java.util.ArrayList;
 import java.util.HashSet;
@@ -55,8 +56,10 @@
 
         Set<String> excludeClasses = new HashSet<String>(1);
         excludeClasses.add("java.lang.JavaClass");
-        mAa = new AsmAnalyzer(mLog, mOsJarPath, null /* gen */,
-                null /* deriveFrom */, null /* includeGlobs */, excludeClasses);
+
+        String[] includeFiles = new String[]{"mock_android/data/data*"};
+        mAa = new AsmAnalyzer(mLog, mOsJarPath, null /* gen */, null /* deriveFrom */,
+                null /* includeGlobs */, excludeClasses, includeFiles);
     }
 
     @After
@@ -65,7 +68,11 @@
 
     @Test
     public void testParseZip() throws IOException {
-        Map<String, ClassReader> map = mAa.parseZip(mOsJarPath);
+
+        Map<String, ClassReader> map = new TreeMap<String, ClassReader>();
+        Map<String, InputStream> filesFound = new TreeMap<String, InputStream>();
+
+        mAa.parseZip(mOsJarPath, map, filesFound);
 
         assertArrayEquals(new String[] {
                 "java.lang.JavaClass",
@@ -86,11 +93,17 @@
                 "mock_android.widget.TableLayout$LayoutParams"
             },
             map.keySet().toArray());
+        assertArrayEquals(new String[] {"mock_android/data/dataFile"},
+            filesFound.keySet().toArray());
     }
 
     @Test
     public void testFindClass() throws IOException, LogAbortException {
-        Map<String, ClassReader> zipClasses = mAa.parseZip(mOsJarPath);
+
+        Map<String, ClassReader> zipClasses = new TreeMap<String, ClassReader>();
+        Map<String, InputStream> filesFound = new TreeMap<String, InputStream>();
+
+        mAa.parseZip(mOsJarPath, zipClasses, filesFound);
         TreeMap<String, ClassReader> found = new TreeMap<String, ClassReader>();
 
         ClassReader cr = mAa.findClass("mock_android.view.ViewGroup$LayoutParams",
@@ -105,7 +118,11 @@
 
     @Test
     public void testFindGlobs() throws IOException, LogAbortException {
-        Map<String, ClassReader> zipClasses = mAa.parseZip(mOsJarPath);
+
+        Map<String, ClassReader> zipClasses = new TreeMap<String, ClassReader>();
+        Map<String, InputStream> filesFound = new TreeMap<String, InputStream>();
+
+        mAa.parseZip(mOsJarPath, zipClasses, filesFound);
         TreeMap<String, ClassReader> found = new TreeMap<String, ClassReader>();
 
         // this matches classes, a package match returns nothing
@@ -164,7 +181,11 @@
 
     @Test
     public void testFindClassesDerivingFrom() throws LogAbortException, IOException {
-        Map<String, ClassReader> zipClasses = mAa.parseZip(mOsJarPath);
+
+        Map<String, ClassReader> zipClasses = new TreeMap<String, ClassReader>();
+        Map<String, InputStream> filesFound = new TreeMap<String, InputStream>();
+
+        mAa.parseZip(mOsJarPath, zipClasses, filesFound);
         TreeMap<String, ClassReader> found = new TreeMap<String, ClassReader>();
 
         mAa.findClassesDerivingFrom("mock_android.view.View", zipClasses, found);
@@ -186,7 +207,11 @@
 
     @Test
     public void testDependencyVisitor() throws IOException, LogAbortException {
-        Map<String, ClassReader> zipClasses = mAa.parseZip(mOsJarPath);
+
+        Map<String, ClassReader> zipClasses = new TreeMap<String, ClassReader>();
+        Map<String, InputStream> filesFound = new TreeMap<String, InputStream>();
+
+        mAa.parseZip(mOsJarPath, zipClasses, filesFound);
         TreeMap<String, ClassReader> keep = new TreeMap<String, ClassReader>();
         TreeMap<String, ClassReader> new_keep = new TreeMap<String, ClassReader>();
         TreeMap<String, ClassReader> in_deps = new TreeMap<String, ClassReader>();
diff --git a/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/AsmGeneratorTest.java b/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/AsmGeneratorTest.java
index 8a27173..0dbc238 100644
--- a/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/AsmGeneratorTest.java
+++ b/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/AsmGeneratorTest.java
@@ -33,6 +33,7 @@
 
 import java.io.File;
 import java.io.IOException;
+import java.io.InputStream;
 import java.net.URL;
 import java.util.ArrayList;
 import java.util.Enumeration;
@@ -131,7 +132,8 @@
                 new String[] {        // include classes
                     "**"
                 },
-                new HashSet<String>(0) /* excluded classes */);
+                new HashSet<String>(0) /* excluded classes */,
+                new String[]{} /* include files */);
         aa.analyze();
         agen.generate();
 
@@ -195,10 +197,15 @@
                 new String[] {        // include classes
                     "**"
                 },
-                new HashSet<String>(1));
+                new HashSet<String>(1),
+                new String[] {        /* include files */
+                    "mock_android/data/data*"
+                });
         aa.analyze();
         agen.generate();
-        Map<String, ClassReader> output = parseZip(mOsDestJar);
+        Map<String, ClassReader> output = new TreeMap<String, ClassReader>();
+        Map<String, InputStream> filesFound = new TreeMap<String, InputStream>();
+        parseZip(mOsDestJar, output, filesFound);
         boolean injectedClassFound = false;
         for (ClassReader cr: output.values()) {
             TestClassVisitor cv = new TestClassVisitor();
@@ -206,10 +213,13 @@
             injectedClassFound |= cv.mInjectedClassFound;
         }
         assertTrue(injectedClassFound);
+        assertArrayEquals(new String[] {"mock_android/data/dataFile"},
+                filesFound.keySet().toArray());
     }
 
-    private Map<String,ClassReader> parseZip(String jarPath) throws IOException {
-        TreeMap<String, ClassReader> classes = new TreeMap<String, ClassReader>();
+    private void parseZip(String jarPath,
+            Map<String, ClassReader> classes,
+            Map<String, InputStream> filesFound) throws IOException {
 
             ZipFile zip = new ZipFile(jarPath);
             Enumeration<? extends ZipEntry> entries = zip.entries();
@@ -220,10 +230,11 @@
                     ClassReader cr = new ClassReader(zip.getInputStream(entry));
                     String className = classReaderToClassName(cr);
                     classes.put(className, cr);
+                } else {
+                    filesFound.put(entry.getName(), zip.getInputStream(entry));
                 }
             }
 
-        return classes;
     }
 
     private String classReaderToClassName(ClassReader classReader) {
diff --git a/tools/layoutlib/create/tests/data/mock_android.jar b/tools/layoutlib/create/tests/data/mock_android.jar
index 60d8efb..8dd0481 100644
--- a/tools/layoutlib/create/tests/data/mock_android.jar
+++ b/tools/layoutlib/create/tests/data/mock_android.jar
Binary files differ
diff --git a/tools/layoutlib/create/tests/mock_data/mock_android/data/anotherDataFile b/tools/layoutlib/create/tests/mock_data/mock_android/data/anotherDataFile
new file mode 100644
index 0000000..ab29fbe
--- /dev/null
+++ b/tools/layoutlib/create/tests/mock_data/mock_android/data/anotherDataFile
@@ -0,0 +1 @@
+A simple data file that should *not* be copied to the output jar.
\ No newline at end of file
diff --git a/tools/layoutlib/create/tests/mock_data/mock_android/data/dataFile b/tools/layoutlib/create/tests/mock_data/mock_android/data/dataFile
new file mode 100644
index 0000000..9b01893
--- /dev/null
+++ b/tools/layoutlib/create/tests/mock_data/mock_android/data/dataFile
@@ -0,0 +1 @@
+A simple data file that should be copied to the output jar unchanged.
\ No newline at end of file