Merge "Change order of operations so flag is not overwritten" into klp-dev
diff --git a/api/current.txt b/api/current.txt
index 94b40279..8e69592 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -3084,18 +3084,18 @@
     method public void cancel(android.app.PendingIntent);
     method public void set(int, long, android.app.PendingIntent);
     method public void setExact(int, long, android.app.PendingIntent);
-    method public deprecated void setInexactRepeating(int, long, long, android.app.PendingIntent);
+    method public void setInexactRepeating(int, long, long, android.app.PendingIntent);
     method public void setRepeating(int, long, long, android.app.PendingIntent);
     method public void setTime(long);
     method public void setTimeZone(java.lang.String);
     method public void setWindow(int, long, long, android.app.PendingIntent);
     field public static final int ELAPSED_REALTIME = 3; // 0x3
     field public static final int ELAPSED_REALTIME_WAKEUP = 2; // 0x2
-    field public static final deprecated long INTERVAL_DAY = 86400000L; // 0x5265c00L
-    field public static final deprecated long INTERVAL_FIFTEEN_MINUTES = 900000L; // 0xdbba0L
-    field public static final deprecated long INTERVAL_HALF_DAY = 43200000L; // 0x2932e00L
-    field public static final deprecated long INTERVAL_HALF_HOUR = 1800000L; // 0x1b7740L
-    field public static final deprecated long INTERVAL_HOUR = 3600000L; // 0x36ee80L
+    field public static final long INTERVAL_DAY = 86400000L; // 0x5265c00L
+    field public static final long INTERVAL_FIFTEEN_MINUTES = 900000L; // 0xdbba0L
+    field public static final long INTERVAL_HALF_DAY = 43200000L; // 0x2932e00L
+    field public static final long INTERVAL_HALF_HOUR = 1800000L; // 0x1b7740L
+    field public static final long INTERVAL_HOUR = 3600000L; // 0x36ee80L
     field public static final int RTC = 1; // 0x1
     field public static final int RTC_WAKEUP = 0; // 0x0
   }
@@ -13228,6 +13228,7 @@
     field public static final java.util.UUID EFFECT_TYPE_BASS_BOOST;
     field public static final java.util.UUID EFFECT_TYPE_ENV_REVERB;
     field public static final java.util.UUID EFFECT_TYPE_EQUALIZER;
+    field public static final java.util.UUID EFFECT_TYPE_LOUDNESS_ENHANCER;
     field public static final java.util.UUID EFFECT_TYPE_NS;
     field public static final java.util.UUID EFFECT_TYPE_PRESET_REVERB;
     field public static final java.util.UUID EFFECT_TYPE_VIRTUALIZER;
@@ -13385,6 +13386,7 @@
   }
 
   public class LoudnessEnhancer extends android.media.audiofx.AudioEffect {
+    ctor public LoudnessEnhancer(int) throws java.lang.IllegalArgumentException, java.lang.IllegalStateException, java.lang.RuntimeException, java.lang.UnsupportedOperationException;
     method public float getTargetGain() throws java.lang.IllegalArgumentException, java.lang.IllegalStateException, java.lang.UnsupportedOperationException;
     method public void setTargetGain(int) throws java.lang.IllegalArgumentException, java.lang.IllegalStateException, java.lang.UnsupportedOperationException;
     field public static final int PARAM_TARGET_GAIN_MB = 0; // 0x0
@@ -25633,10 +25635,8 @@
     ctor public TransitionManager();
     method public static void beginDelayedTransition(android.view.ViewGroup);
     method public static void beginDelayedTransition(android.view.ViewGroup, android.transition.Transition);
-    method public static android.transition.Transition getDefaultTransition();
     method public static void go(android.transition.Scene);
     method public static void go(android.transition.Scene, android.transition.Transition);
-    method public void setDefaultTransition(android.transition.Transition);
     method public void setTransition(android.transition.Scene, android.transition.Transition);
     method public void setTransition(android.transition.Scene, android.transition.Scene, android.transition.Transition);
     method public void transitionTo(android.transition.Scene);
diff --git a/core/java/android/app/AlarmManager.java b/core/java/android/app/AlarmManager.java
index 5c3a3e5..0cf7ad0 100644
--- a/core/java/android/app/AlarmManager.java
+++ b/core/java/android/app/AlarmManager.java
@@ -48,6 +48,15 @@
  * etc) it is easier and much more efficient to use
  * {@link android.os.Handler}.</b>
  *
+ * <p class="caution"><strong>Note:</strong> Beginning with API 19
+ * ({@link android.os.Build.VERSION_CODES#KITKAT}) alarm delivery is inexact:
+ * the OS will shift alarms in order to minimize wakeups and battery use.  There are
+ * new APIs to support applications which need strict delivery guarantees; see
+ * {@link #setWindow(int, long, long, PendingIntent)} and
+ * {@link #setExact(int, long, PendingIntent)}.  Applications whose {@code targetSdkVersion}
+ * is earlier than API 19 will continue to see the previous behavior in which all
+ * alarms are delivered exactly when requested.
+ *
  * <p>You do not
  * instantiate this class directly; instead, retrieve it through
  * {@link android.content.Context#getSystemService
@@ -109,21 +118,19 @@
     }
 
     /**
-     * TBW: discussion of fuzzy nature of alarms in KLP+.
-     *
      * <p>Schedule an alarm.  <b>Note: for timing operations (ticks, timeouts,
-     * etc) it is easier and much more efficient to use
-     * {@link android.os.Handler}.</b>  If there is already an alarm scheduled
-     * for the same IntentSender, it will first be canceled.
+     * etc) it is easier and much more efficient to use {@link android.os.Handler}.</b>
+     * If there is already an alarm scheduled for the same IntentSender, that previous
+     * alarm will first be canceled.
      *
-     * <p>If the time occurs in the past, the alarm will be triggered
+     * <p>If the stated trigger time is in the past, the alarm will be triggered
      * immediately.  If there is already an alarm for this Intent
      * scheduled (with the equality of two intents being defined by
      * {@link Intent#filterEquals}), then it will be removed and replaced by
      * this one.
      *
      * <p>
-     * The alarm is an intent broadcast that goes to a broadcast receiver that
+     * The alarm is an Intent broadcast that goes to a broadcast receiver that
      * you registered with {@link android.content.Context#registerReceiver}
      * or through the &lt;receiver&gt; tag in an AndroidManifest.xml file.
      *
@@ -133,9 +140,34 @@
      * how many past alarm events have been accumulated into this intent
      * broadcast.  Recurring alarms that have gone undelivered because the
      * phone was asleep may have a count greater than one when delivered.  
-     *  
-     * @param type One of ELAPSED_REALTIME, ELAPSED_REALTIME_WAKEUP, RTC or
-     *             RTC_WAKEUP.
+     *
+     * <div class="note">
+     * <p>
+     * <b>Note:</b> Beginning in API 19, the trigger time passed to this method
+     * is treated as inexact: the alarm will not be delivered before this time, but
+     * may be deferred and delivered some time later.  The OS will use
+     * this policy in order to "batch" alarms together across the entire system,
+     * minimizing the number of times the device needs to "wake up" and minimizing
+     * battery use.  In general, alarms scheduled in the near future will not
+     * be deferred as long as alarms scheduled far in the future.
+     *
+     * <p>
+     * With the new batching policy, delivery ordering guarantees are not as
+     * strong as they were previously.  If the application sets multiple alarms,
+     * it is possible that these alarms' <em>actual</em> delivery ordering may not match
+     * the order of their <em>requested</em> delivery times.  If your application has
+     * strong ordering requirements there are other APIs that you can use to get
+     * the necessary behavior; see {@link #setWindow(int, long, long, PendingIntent)}
+     * and {@link #setExact(int, long, PendingIntent)}.
+     *
+     * <p>
+     * Applications whose {@code targetSdkVersion} is before API 19 will
+     * continue to get the previous alarm behavior: all of their scheduled alarms
+     * will be treated as exact.
+     * </div>
+     *
+     * @param type One of {@link #ELAPSED_REALTIME}, {@link #ELAPSED_REALTIME_WAKEUP},
+     *        {@link #RTC}, or {@link #RTC_WAKEUP}.
      * @param triggerAtMillis time in milliseconds that the alarm should go
      * off, using the appropriate clock (depending on the alarm type).
      * @param operation Action to perform when the alarm goes off;
@@ -165,10 +197,10 @@
      * {@link android.os.Handler}.</b>  If there is already an alarm scheduled
      * for the same IntentSender, it will first be canceled.
      *
-     * <p>Like {@link #set}, except you can also
-     * supply a rate at which the alarm will repeat.  This alarm continues
-     * repeating until explicitly removed with {@link #cancel}.  If the time
-     * occurs in the past, the alarm will be triggered immediately, with an
+     * <p>Like {@link #set}, except you can also supply a period at which
+     * the alarm will automatically repeat.  This alarm continues
+     * repeating until explicitly removed with {@link #cancel}.  If the stated
+     * trigger time is in the past, the alarm will be triggered immediately, with an
      * alarm count depending on how far in the past the trigger time is relative
      * to the repeat interval.
      *
@@ -185,8 +217,15 @@
      * between alarms, then the approach to take is to use one-time alarms, 
      * scheduling the next one yourself when handling each alarm delivery.
      *
-     * @param type One of ELAPSED_REALTIME, ELAPSED_REALTIME_WAKEUP}, RTC or
-     *             RTC_WAKEUP.
+     * <p class="note">
+     * <b>Note:</b> as of API 19, all repeating alarms are inexact.  If your
+     * application needs precise delivery times then it must use one-time
+     * exact alarms, rescheduling each time as described above. Legacy applications
+     * whose {@code targetSdkVersion} is earlier than API 19 will continue to have all
+     * of their alarms, including repeating alarms, treated as exact.
+     *
+     * @param type One of {@link #ELAPSED_REALTIME}, {@link #ELAPSED_REALTIME_WAKEUP},
+     *        {@link #RTC}, or {@link #RTC_WAKEUP}.
      * @param triggerAtMillis time in milliseconds that the alarm should first
      * go off, using the appropriate clock (depending on the alarm type).
      * @param intervalMillis interval in milliseconds between subsequent repeats
@@ -214,18 +253,33 @@
     }
 
     /**
-     * Schedule an alarm to be delivered within a given window of time.
+     * Schedule an alarm to be delivered within a given window of time.  This method
+     * is similar to {@link #set(int, long, PendingIntent)}, but allows the
+     * application to precisely control the degree to which its delivery might be
+     * adjusted by the OS. This method allows an application to take advantage of the
+     * battery optimizations that arise from delivery batching even when it has
+     * modest timeliness requirements for its alarms.
      *
-     * TBW: clean up these docs
+     * <p>
+     * This method can also be used to achieve strict ordering guarantees among
+     * multiple alarms by ensuring that the windows requested for each alarm do
+     * not intersect.
      *
-     * @param type One of ELAPSED_REALTIME, ELAPSED_REALTIME_WAKEUP, RTC or
-     *        RTC_WAKEUP.
+     * <p>
+     * When precise delivery is not required, applications should use the standard
+     * {@link #set(int, long, PendingIntent)} method.  This will give the OS the most
+     * flexibility to minimize wakeups and battery use.  For alarms that must be delivered
+     * at precisely-specified times with no acceptable variation, applications can use
+     * {@link #setExact(int, long, PendingIntent)}.
+     *
+     * @param type One of {@link #ELAPSED_REALTIME}, {@link #ELAPSED_REALTIME_WAKEUP},
+     *        {@link #RTC}, or {@link #RTC_WAKEUP}.
      * @param windowStartMillis The earliest time, in milliseconds, that the alarm should
      *        be delivered, expressed in the appropriate clock's units (depending on the alarm
      *        type).
      * @param windowLengthMillis The length of the requested delivery window,
      *        in milliseconds.  The alarm will be delivered no later than this many
-     *        milliseconds after the windowStartMillis time.  Note that this parameter
+     *        milliseconds after {@code windowStartMillis}.  Note that this parameter
      *        is a <i>duration,</i> not the timestamp of the end of the window.
      * @param operation Action to perform when the alarm goes off;
      *        typically comes from {@link PendingIntent#getBroadcast
@@ -249,8 +303,38 @@
     }
 
     /**
-     * TBW: new 'exact' alarm that must be delivered as nearly as possible
-     * to the precise time specified.
+     * Schedule an alarm to be delivered precisely at the stated time.
+     *
+     * <p>
+     * This method is like {@link #set(int, long, PendingIntent)}, but does not permit
+     * the OS to adjust the delivery time.  The alarm will be delivered as nearly as
+     * possible to the requested trigger time.
+     *
+     * <p>
+     * <b>Note:</b> only alarms for which there is a strong demand for exact-time
+     * delivery (such as an alarm clock ringing at the requested time) should be
+     * scheduled as exact.  Applications are strongly discouraged from using exact
+     * alarms unnecessarily as they reduce the OS's ability to minimize battery use.
+     *
+     * @param type One of {@link #ELAPSED_REALTIME}, {@link #ELAPSED_REALTIME_WAKEUP},
+     *        {@link #RTC}, or {@link #RTC_WAKEUP}.
+     * @param triggerAtMillis time in milliseconds that the alarm should go
+     *        off, using the appropriate clock (depending on the alarm type).
+     * @param operation Action to perform when the alarm goes off;
+     *        typically comes from {@link PendingIntent#getBroadcast
+     *        IntentSender.getBroadcast()}.
+     *
+     * @see #set
+     * @see #setRepeating
+     * @see #setWindow
+     * @see #cancel
+     * @see android.content.Context#sendBroadcast
+     * @see android.content.Context#registerReceiver
+     * @see android.content.Intent#filterEquals
+     * @see #ELAPSED_REALTIME
+     * @see #ELAPSED_REALTIME_WAKEUP
+     * @see #RTC
+     * @see #RTC_WAKEUP
      */
     public void setExact(int type, long triggerAtMillis, PendingIntent operation) {
         setImpl(type, triggerAtMillis, WINDOW_EXACT, 0, operation, null);
@@ -283,74 +367,82 @@
     }
 
     /**
-     * @deprecated setInexactRepeating() is deprecated; as of API 19 all
-     * repeating alarms are inexact.
+     * Available inexact recurrence interval recognized by
+     * {@link #setInexactRepeating(int, long, long, PendingIntent)}
+     * when running on Android prior to API 19.
      */
-    @Deprecated
     public static final long INTERVAL_FIFTEEN_MINUTES = 15 * 60 * 1000;
 
     /**
-     * @deprecated setInexactRepeating() is deprecated; as of API 19 all
-     * repeating alarms are inexact.
+     * Available inexact recurrence interval recognized by
+     * {@link #setInexactRepeating(int, long, long, PendingIntent)}
+     * when running on Android prior to API 19.
      */
-    @Deprecated
     public static final long INTERVAL_HALF_HOUR = 2*INTERVAL_FIFTEEN_MINUTES;
 
     /**
-     * @deprecated setInexactRepeating() is deprecated; as of API 19 all
-     * repeating alarms are inexact.
+     * Available inexact recurrence interval recognized by
+     * {@link #setInexactRepeating(int, long, long, PendingIntent)}
+     * when running on Android prior to API 19.
      */
-    @Deprecated
     public static final long INTERVAL_HOUR = 2*INTERVAL_HALF_HOUR;
 
     /**
-     * @deprecated setInexactRepeating() is deprecated; as of API 19 all
-     * repeating alarms are inexact.
+     * Available inexact recurrence interval recognized by
+     * {@link #setInexactRepeating(int, long, long, PendingIntent)}
+     * when running on Android prior to API 19.
      */
-    @Deprecated
     public static final long INTERVAL_HALF_DAY = 12*INTERVAL_HOUR;
 
     /**
-     * @deprecated setInexactRepeating() is deprecated; as of API 19 all
-     * repeating alarms are inexact.
+     * Available inexact recurrence interval recognized by
+     * {@link #setInexactRepeating(int, long, long, PendingIntent)}
+     * when running on Android prior to API 19.
      */
-    @Deprecated
     public static final long INTERVAL_DAY = 2*INTERVAL_HALF_DAY;
 
     /**
      * Schedule a repeating alarm that has inexact trigger time requirements;
      * for example, an alarm that repeats every hour, but not necessarily at
      * the top of every hour.  These alarms are more power-efficient than
-     * the strict recurrences supplied by {@link #setRepeating}, since the
-     * system can adjust alarms' phase to cause them to fire simultaneously,
+     * the strict recurrences traditionally supplied by {@link #setRepeating}, since the
+     * system can adjust alarms' delivery times to cause them to fire simultaneously,
      * avoiding waking the device from sleep more than necessary.
-     * 
+     *
      * <p>Your alarm's first trigger will not be before the requested time,
      * but it might not occur for almost a full interval after that time.  In
      * addition, while the overall period of the repeating alarm will be as
      * requested, the time between any two successive firings of the alarm
      * may vary.  If your application demands very low jitter, use
-     * {@link #setRepeating} instead.
+     * one-shot alarms with an appropriate window instead; see {@link
+     * #setWindow(int, long, long, PendingIntent)} and
+     * {@link #setExact(int, long, PendingIntent)}.
      *
-     * @param type One of ELAPSED_REALTIME, ELAPSED_REALTIME_WAKEUP}, RTC or
-     *             RTC_WAKEUP.
+     * <p class="note">
+     * As of API 19, all repeating alarms are inexact.  Because this method has
+     * been available since API 3, your application can safely call it and be
+     * assured that it will get similar behavior on both current and older versions
+     * of Android.
+     *
+     * @param type One of {@link #ELAPSED_REALTIME}, {@link #ELAPSED_REALTIME_WAKEUP},
+     *        {@link #RTC}, or {@link #RTC_WAKEUP}.
      * @param triggerAtMillis time in milliseconds that the alarm should first
      * go off, using the appropriate clock (depending on the alarm type).  This
      * is inexact: the alarm will not fire before this time, but there may be a
      * delay of almost an entire alarm interval before the first invocation of
      * the alarm.
      * @param intervalMillis interval in milliseconds between subsequent repeats
-     * of the alarm.  If this is one of INTERVAL_FIFTEEN_MINUTES,
+     * of the alarm.  Prior to API 19, if this is one of INTERVAL_FIFTEEN_MINUTES,
      * INTERVAL_HALF_HOUR, INTERVAL_HOUR, INTERVAL_HALF_DAY, or INTERVAL_DAY
      * then the alarm will be phase-aligned with other alarms to reduce the
      * number of wakeups.  Otherwise, the alarm will be set as though the
-     * application had called {@link #setRepeating}.
+     * application had called {@link #setRepeating}.  As of API 19, all repeating
+     * alarms will be inexact and subject to batching with other alarms regardless
+     * of their stated repeat interval.
      * @param operation Action to perform when the alarm goes off;
      * typically comes from {@link PendingIntent#getBroadcast
      * IntentSender.getBroadcast()}.
      *
-     * @deprecated As of API 19, all repeating alarms are inexact.
-     *
      * @see android.os.Handler
      * @see #set
      * @see #cancel
@@ -367,7 +459,6 @@
      * @see #INTERVAL_HALF_DAY
      * @see #INTERVAL_DAY
      */
-    @Deprecated
     public void setInexactRepeating(int type, long triggerAtMillis,
             long intervalMillis, PendingIntent operation) {
         setImpl(type, triggerAtMillis, WINDOW_HEURISTIC, intervalMillis, operation, null);
diff --git a/core/java/android/hardware/SystemSensorManager.java b/core/java/android/hardware/SystemSensorManager.java
index 14f67c5..50fdb41 100644
--- a/core/java/android/hardware/SystemSensorManager.java
+++ b/core/java/android/hardware/SystemSensorManager.java
@@ -358,14 +358,20 @@
             mListener = listener;
         }
 
+        @Override
         public void addSensorEvent(Sensor sensor) {
             SensorEvent t = new SensorEvent(Sensor.getMaxLengthValuesArray(sensor,
                     mManager.mTargetSdkLevel));
-            mSensorsEvents.put(sensor.getHandle(), t);
+            synchronized (mSensorsEvents) {
+                mSensorsEvents.put(sensor.getHandle(), t);
+            }
         }
 
+        @Override
         public void removeSensorEvent(Sensor sensor) {
-            mSensorsEvents.delete(sensor.getHandle());
+            synchronized (mSensorsEvents) {
+                mSensorsEvents.delete(sensor.getHandle());
+            }
         }
 
         // Called from native code.
@@ -374,9 +380,14 @@
         protected void dispatchSensorEvent(int handle, float[] values, int inAccuracy,
                 long timestamp) {
             final Sensor sensor = sHandleToSensor.get(handle);
-            SensorEvent t = mSensorsEvents.get(handle);
+            SensorEvent t = null;
+            synchronized (mSensorsEvents) {
+                t = mSensorsEvents.get(handle);
+            }
+
             if (t == null) {
-                Log.e(TAG, "Error: Sensor Event is null for Sensor: " + sensor);
+                // This may happen if the client has unregistered and there are pending events in
+                // the queue waiting to be delivered. Ignore.
                 return;
             }
             // Copy from the values array.
@@ -427,14 +438,20 @@
             mListener = listener;
         }
 
+        @Override
         public void addSensorEvent(Sensor sensor) {
             TriggerEvent t = new TriggerEvent(Sensor.getMaxLengthValuesArray(sensor,
                     mManager.mTargetSdkLevel));
-            mTriggerEvents.put(sensor.getHandle(), t);
+            synchronized (mTriggerEvents) {
+                mTriggerEvents.put(sensor.getHandle(), t);
+            }
         }
 
+        @Override
         public void removeSensorEvent(Sensor sensor) {
-            mTriggerEvents.delete(sensor.getHandle());
+            synchronized (mTriggerEvents) {
+                mTriggerEvents.delete(sensor.getHandle());
+            }
         }
 
         // Called from native code.
@@ -443,7 +460,10 @@
         protected void dispatchSensorEvent(int handle, float[] values, int accuracy,
                 long timestamp) {
             final Sensor sensor = sHandleToSensor.get(handle);
-            TriggerEvent t = mTriggerEvents.get(handle);
+            TriggerEvent t = null;
+            synchronized (mTriggerEvents) {
+                t = mTriggerEvents.get(handle);
+            }
             if (t == null) {
                 Log.e(TAG, "Error: Trigger Event is null for Sensor: " + sensor);
                 return;
diff --git a/core/java/android/os/Bundle.java b/core/java/android/os/Bundle.java
index 5a919fb..f9c1d31 100644
--- a/core/java/android/os/Bundle.java
+++ b/core/java/android/os/Bundle.java
@@ -35,10 +35,12 @@
     public static final Bundle EMPTY;
 
     static final int BUNDLE_MAGIC = 0x4C444E42; // 'B' 'N' 'D' 'L'
+    static final Parcel EMPTY_PARCEL;
 
     static {
         EMPTY = new Bundle();
         EMPTY.mMap = ArrayMap.EMPTY;
+        EMPTY_PARCEL = Parcel.obtain();
     }
 
     // Invariant - exactly one of mMap / mParcelledData will be null
@@ -115,9 +117,13 @@
      */
     public Bundle(Bundle b) {
         if (b.mParcelledData != null) {
-            mParcelledData = Parcel.obtain();
-            mParcelledData.appendFrom(b.mParcelledData, 0, b.mParcelledData.dataSize());
-            mParcelledData.setDataPosition(0);
+            if (b.mParcelledData == EMPTY_PARCEL) {
+                mParcelledData = EMPTY_PARCEL;
+            } else {
+                mParcelledData = Parcel.obtain();
+                mParcelledData.appendFrom(b.mParcelledData, 0, b.mParcelledData.dataSize());
+                mParcelledData.setDataPosition(0);
+            }
         } else {
             mParcelledData = null;
         }
@@ -216,6 +222,18 @@
             return;
         }
 
+        if (mParcelledData == EMPTY_PARCEL) {
+            if (DEBUG) Log.d(TAG, "unparcel " + Integer.toHexString(System.identityHashCode(this))
+                    + ": empty");
+            if (mMap == null) {
+                mMap = new ArrayMap<String, Object>(1);
+            } else {
+                mMap.erase();
+            }
+            mParcelledData = null;
+            return;
+        }
+
         int N = mParcelledData.readInt();
         if (DEBUG) Log.d(TAG, "unparcel " + Integer.toHexString(System.identityHashCode(this))
                 + ": reading " + N + " maps");
@@ -1652,11 +1670,20 @@
         final boolean oldAllowFds = parcel.pushAllowFds(mAllowFds);
         try {
             if (mParcelledData != null) {
-                int length = mParcelledData.dataSize();
-                parcel.writeInt(length);
-                parcel.writeInt(BUNDLE_MAGIC);
-                parcel.appendFrom(mParcelledData, 0, length);
+                if (mParcelledData == EMPTY_PARCEL) {
+                    parcel.writeInt(0);
+                } else {
+                    int length = mParcelledData.dataSize();
+                    parcel.writeInt(length);
+                    parcel.writeInt(BUNDLE_MAGIC);
+                    parcel.appendFrom(mParcelledData, 0, length);
+                }
             } else {
+                // Special case for empty bundles.
+                if (mMap == null || mMap.size() <= 0) {
+                    parcel.writeInt(0);
+                    return;
+                }
                 int lengthPos = parcel.dataPosition();
                 parcel.writeInt(-1); // dummy, will hold length
                 parcel.writeInt(BUNDLE_MAGIC);
@@ -1690,6 +1717,13 @@
     }
 
     void readFromParcelInner(Parcel parcel, int length) {
+        if (length == 0) {
+            // Empty Bundle or end of data.
+            mParcelledData = EMPTY_PARCEL;
+            mHasFds = false;
+            mFdsKnown = true;
+            return;
+        }
         int magic = parcel.readInt();
         if (magic != BUNDLE_MAGIC) {
             //noinspection ThrowableInstanceNeverThrown
@@ -1716,8 +1750,12 @@
     @Override
     public synchronized String toString() {
         if (mParcelledData != null) {
-            return "Bundle[mParcelledData.dataSize=" +
-                    mParcelledData.dataSize() + "]";
+            if (mParcelledData == EMPTY_PARCEL) {
+                return "Bundle[EMPTY_PARCEL]";
+            } else {
+                return "Bundle[mParcelledData.dataSize=" +
+                        mParcelledData.dataSize() + "]";
+            }
         }
         return "Bundle[" + mMap.toString() + "]";
     }
diff --git a/core/java/android/os/IPowerManager.aidl b/core/java/android/os/IPowerManager.aidl
index 4c7bbb4..56176a4 100644
--- a/core/java/android/os/IPowerManager.aidl
+++ b/core/java/android/os/IPowerManager.aidl
@@ -23,11 +23,12 @@
 
 interface IPowerManager
 {
-    // WARNING: The first three methods must remain the first three methods because their
+    // WARNING: The first four methods must remain the first three methods because their
     // transaction numbers must not change unless IPowerManager.cpp is also updated.
     void acquireWakeLock(IBinder lock, int flags, String tag, String packageName, in WorkSource ws);
     void acquireWakeLockWithUid(IBinder lock, int flags, String tag, String packageName, int uidtoblame);
     void releaseWakeLock(IBinder lock, int flags);
+    void updateWakeLockUids(IBinder lock, in int[] uids);
 
     void updateWakeLockWorkSource(IBinder lock, in WorkSource ws);
     boolean isWakeLockLevelSupported(int level);
diff --git a/core/java/android/os/Parcel.java b/core/java/android/os/Parcel.java
index 02b1998..94b9617 100644
--- a/core/java/android/os/Parcel.java
+++ b/core/java/android/os/Parcel.java
@@ -611,11 +611,15 @@
             here.fillInStackTrace();
             Log.d(TAG, "Writing " + N + " ArrayMap entries", here);
         }
+        int startPos;
         for (int i=0; i<N; i++) {
-            if (DEBUG_ARRAY_MAP) Log.d(TAG, "  Write #" + i + ": key=0x"
-                    + (val.keyAt(i) != null ? val.keyAt(i).hashCode() : 0) + " " + val.keyAt(i));
+            if (DEBUG_ARRAY_MAP) startPos = dataPosition();
             writeValue(val.keyAt(i));
             writeValue(val.valueAt(i));
+            if (DEBUG_ARRAY_MAP) Log.d(TAG, "  Write #" + i + " "
+                    + (dataPosition()-startPos) + " bytes: key=0x"
+                    + Integer.toHexString(val.keyAt(i) != null ? val.keyAt(i).hashCode() : 0)
+                    + " " + val.keyAt(i));
         }
     }
 
@@ -2303,11 +2307,14 @@
             here.fillInStackTrace();
             Log.d(TAG, "Reading " + N + " ArrayMap entries", here);
         }
+        int startPos;
         while (N > 0) {
+            if (DEBUG_ARRAY_MAP) startPos = dataPosition();
             Object key = readValue(loader);
-            if (DEBUG_ARRAY_MAP) Log.d(TAG, "  Read #" + (N-1) + ": key=0x"
-                    + (key != null ? key.hashCode() : 0) + " " + key);
             Object value = readValue(loader);
+            if (DEBUG_ARRAY_MAP) Log.d(TAG, "  Read #" + (N-1) + " "
+                    + (dataPosition()-startPos) + " bytes: key=0x"
+                    + Integer.toHexString((key != null ? key.hashCode() : 0)) + " " + key);
             outVal.append(key, value);
             N--;
         }
diff --git a/core/java/android/os/ParcelFileDescriptor.java b/core/java/android/os/ParcelFileDescriptor.java
index 1456387..5273c20 100644
--- a/core/java/android/os/ParcelFileDescriptor.java
+++ b/core/java/android/os/ParcelFileDescriptor.java
@@ -231,10 +231,11 @@
         final FileDescriptor fd = openInternal(file, mode);
         if (fd == null) return null;
 
-        final FileDescriptor[] comm = createCommSocketPair(true);
+        final FileDescriptor[] comm = createCommSocketPair();
         final ParcelFileDescriptor pfd = new ParcelFileDescriptor(fd, comm[0]);
 
         // Kick off thread to watch for status updates
+        IoUtils.setBlocking(comm[1], true);
         final ListenerBridge bridge = new ListenerBridge(comm[1], handler.getLooper(), listener);
         bridge.start();
 
@@ -378,7 +379,7 @@
      */
     public static ParcelFileDescriptor[] createReliablePipe() throws IOException {
         try {
-            final FileDescriptor[] comm = createCommSocketPair(false);
+            final FileDescriptor[] comm = createCommSocketPair();
             final FileDescriptor[] fds = Libcore.os.pipe();
             return new ParcelFileDescriptor[] {
                     new ParcelFileDescriptor(fds[0], comm[0]),
@@ -416,7 +417,7 @@
      */
     public static ParcelFileDescriptor[] createReliableSocketPair() throws IOException {
         try {
-            final FileDescriptor[] comm = createCommSocketPair(false);
+            final FileDescriptor[] comm = createCommSocketPair();
             final FileDescriptor fd0 = new FileDescriptor();
             final FileDescriptor fd1 = new FileDescriptor();
             Libcore.os.socketpair(AF_UNIX, SOCK_STREAM, 0, fd0, fd1);
@@ -428,13 +429,13 @@
         }
     }
 
-    private static FileDescriptor[] createCommSocketPair(boolean blocking) throws IOException {
+    private static FileDescriptor[] createCommSocketPair() throws IOException {
         try {
             final FileDescriptor comm1 = new FileDescriptor();
             final FileDescriptor comm2 = new FileDescriptor();
             Libcore.os.socketpair(AF_UNIX, SOCK_STREAM, 0, comm1, comm2);
-            IoUtils.setBlocking(comm1, blocking);
-            IoUtils.setBlocking(comm2, blocking);
+            IoUtils.setBlocking(comm1, false);
+            IoUtils.setBlocking(comm2, false);
             return new FileDescriptor[] { comm1, comm2 };
         } catch (ErrnoException e) {
             throw e.rethrowAsIOException();
@@ -670,34 +671,35 @@
         }
 
         try {
+            if (status == Status.SILENCE) return;
+
+            // Since we're about to close, read off any remote status. It's
+            // okay to remember missing here.
+            mStatus = readCommStatus(mCommFd, getOrCreateStatusBuffer());
+
+            // Skip writing status when other end has already gone away.
+            if (mStatus != null) return;
+
             try {
-                if (status != Status.SILENCE) {
-                    final byte[] buf = getOrCreateStatusBuffer();
-                    int writePtr = 0;
+                final byte[] buf = getOrCreateStatusBuffer();
+                int writePtr = 0;
 
-                    Memory.pokeInt(buf, writePtr, status, ByteOrder.BIG_ENDIAN);
-                    writePtr += 4;
+                Memory.pokeInt(buf, writePtr, status, ByteOrder.BIG_ENDIAN);
+                writePtr += 4;
 
-                    if (msg != null) {
-                        final byte[] rawMsg = msg.getBytes();
-                        final int len = Math.min(rawMsg.length, buf.length - writePtr);
-                        System.arraycopy(rawMsg, 0, buf, writePtr, len);
-                        writePtr += len;
-                    }
-
-                    Libcore.os.write(mCommFd, buf, 0, writePtr);
+                if (msg != null) {
+                    final byte[] rawMsg = msg.getBytes();
+                    final int len = Math.min(rawMsg.length, buf.length - writePtr);
+                    System.arraycopy(rawMsg, 0, buf, writePtr, len);
+                    writePtr += len;
                 }
+
+                Libcore.os.write(mCommFd, buf, 0, writePtr);
             } catch (ErrnoException e) {
                 // Reporting status is best-effort
                 Log.w(TAG, "Failed to report status: " + e);
             }
 
-            if (status != Status.SILENCE) {
-                // Since we're about to close, read off any remote status. It's
-                // okay to remember missing here.
-                mStatus = readCommStatus(mCommFd, getOrCreateStatusBuffer());
-            }
-
         } finally {
             IoUtils.closeQuietly(mCommFd);
             mCommFd = null;
diff --git a/core/java/android/print/PageRange.java b/core/java/android/print/PageRange.java
index cdcd0c7..d6320f0 100644
--- a/core/java/android/print/PageRange.java
+++ b/core/java/android/print/PageRange.java
@@ -39,9 +39,8 @@
      * @param start The start page index (zero based and inclusive).
      * @param end The end page index (zero based and inclusive).
      *
-     * @throws IllegalArgumentException If start is less than zero.
-     * @throws IllegalArgumentException If end is less than zero.
-     * @throws IllegalArgumentException If start greater than end.
+     * @throws IllegalArgumentException If start is less than zero or end
+     * is less than zero or start greater than end.
      */
     public PageRange(int start, int end) {
         if (start < 0) {
diff --git a/core/java/android/print/PrintAttributes.java b/core/java/android/print/PrintAttributes.java
index e1a9cb7..c6254e0 100644
--- a/core/java/android/print/PrintAttributes.java
+++ b/core/java/android/print/PrintAttributes.java
@@ -30,7 +30,11 @@
 import java.util.Map;
 
 /**
- * This class represents the attributes of a print job.
+ * This class represents the attributes of a print job. These attributes
+ * describe how the printed content should be laid out. For example, the
+ * print attributes may state that the content should be laid out on a
+ * letter size with 300 DPI (dots per inch) resolution, have a margin of
+ * 10 mills (thousand of an inch) on all sides, and be black and white.
  */
 public final class PrintAttributes implements Parcelable {
     /** Color mode: Monochrome color scheme, for example one color is used. */
@@ -277,7 +281,7 @@
          * Unknown media size in portrait mode.
          * <p>
          * <strong>Note: </strong>This is for specifying orientation without media
-         * size. You should not use the dimensions reported by this class.
+         * size. You should not use the dimensions reported by this instance.
          * </p>
          */
         public static final MediaSize UNKNOWN_PORTRAIT =
@@ -288,7 +292,7 @@
          * Unknown media size in landscape mode.
          * <p>
          * <strong>Note: </strong>This is for specifying orientation without media
-         * size. You should not use the dimensions reported by this class.
+         * size. You should not use the dimensions reported by this instance.
          * </p>
          */
         public static final MediaSize UNKNOWN_LANDSCAPE =
@@ -615,9 +619,7 @@
         private final int mHeightMils;
 
         /**
-         * Creates a new instance. This is the preferred constructor since
-         * it enables the media size label to be shown in a localized fashion
-         * on a locale change.
+         * Creates a new instance.
          *
          * @param id The unique media size id.
          * @param packageName The name of the creating package.
@@ -625,10 +627,9 @@
          * @param widthMils The width in mils (thousands of an inch).
          * @param heightMils The height in mils (thousands of an inch).
          *
-         * @throws IllegalArgumentException If the id is empty.
-         * @throws IllegalArgumentException If the label is empty.
-         * @throws IllegalArgumentException If the widthMils is less than or equal to zero.
-         * @throws IllegalArgumentException If the heightMils is less than or equal to zero.
+         * @throws IllegalArgumentException If the id is empty or the label
+         * is empty or the widthMils is less than or equal to zero or the
+         * heightMils is less than or equal to zero.
          *
          * @hide
          */
@@ -667,14 +668,13 @@
          *
          * @param id The unique media size id. It is unique amongst other media sizes
          *        supported by the printer.
-         * @param label The <strong>internationalized</strong> human readable label.
+         * @param label The <strong>localized</strong> human readable label.
          * @param widthMils The width in mils (thousands of an inch).
          * @param heightMils The height in mils (thousands of an inch).
          *
-         * @throws IllegalArgumentException If the id is empty.
-         * @throws IllegalArgumentException If the label is empty.
-         * @throws IllegalArgumentException If the widthMils is less than or equal to zero.
-         * @throws IllegalArgumentException If the heightMils is less than or equal to zero.
+         * @throws IllegalArgumentException If the id is empty or the label is empty
+         * or the widthMils is less than or equal to zero or the heightMils is less
+         * than or equal to zero.
          */
         public MediaSize(String id, String label, int widthMils, int heightMils) {
             if (TextUtils.isEmpty(id)) {
@@ -776,12 +776,16 @@
         }
 
         /**
-         * Returns a new media size in a portrait orientation
+         * Returns a new media size instance in a portrait orientation,
          * which is the height is the greater dimension.
          *
-         * @return New instance in landscape orientation.
+         * @return New instance in landscape orientation if this one
+         * is in landscape, otherwise this instance.
          */
         public MediaSize asPortrait() {
+            if (isPortrait()) {
+                return this;
+            }
             return new MediaSize(mId, mLabel, mPackageName,
                     Math.min(mWidthMils, mHeightMils),
                     Math.max(mWidthMils, mHeightMils),
@@ -789,12 +793,16 @@
         }
 
         /**
-         * Returns a new media size in a landscape orientation
+         * Returns a new media size instance in a landscape orientation,
          * which is the height is the lesser dimension.
          *
-         * @return New instance in landscape orientation.
+         * @return New instance in landscape orientation if this one
+         * is in portrait, otherwise this instance.
          */
         public MediaSize asLandscape() {
+            if (!isPortrait()) {
+                return this;
+            }
             return new MediaSize(mId, mLabel, mPackageName,
                     Math.max(mWidthMils, mHeightMils),
                     Math.min(mWidthMils, mHeightMils),
@@ -881,8 +889,8 @@
      * This class specifies a supported resolution in DPI (dots per inch).
      * Resolution defines how many points with different color can be placed
      * on one inch in horizontal or vertical direction of the target media.
-     * For example, a printer with 600DIP can produce higher quality images
-     * the one with 300DPI resolution.
+     * For example, a printer with 600 DPI can produce higher quality images
+     * the one with 300 DPI resolution.
      */
     public static final class Resolution {
         private final String mId;
@@ -895,14 +903,13 @@
          *
          * @param id The unique resolution id. It is unique amongst other resolutions
          *        supported by the printer.
-         * @param label The <strong>internationalized</strong> human readable label.
+         * @param label The <strong>localized</strong> human readable label.
          * @param horizontalDpi The horizontal resolution in DPI (dots per inch).
          * @param verticalDpi The vertical resolution in DPI (dots per inch).
          *
-         * @throws IllegalArgumentException If the id is empty.
-         * @throws IllegalArgumentException If the label is empty.
-         * @throws IllegalArgumentException If the horizontalDpi is less than or equal to zero.
-         * @throws IllegalArgumentException If the verticalDpi is less than or equal to zero.
+         * @throws IllegalArgumentException If the id is empty or the label is empty
+         * or the horizontalDpi is less than or equal to zero or the verticalDpi is
+         * less than or equal to zero.
          */
         public Resolution(String id, String label, int horizontalDpi, int verticalDpi) {
             if (TextUtils.isEmpty(id)) {
diff --git a/core/java/android/print/PrintDocumentAdapter.java b/core/java/android/print/PrintDocumentAdapter.java
index 4113ac7..9e811a6 100644
--- a/core/java/android/print/PrintDocumentAdapter.java
+++ b/core/java/android/print/PrintDocumentAdapter.java
@@ -38,15 +38,46 @@
  * </li>
  * <li>
  * After every call to {@link #onLayout(PrintAttributes, PrintAttributes,
- * CancellationSignal, LayoutResultCallback, Bundle)}, you may get a call to
- * {@link #onWrite(PageRange[], ParcelFileDescriptor, CancellationSignal, WriteResultCallback)}
- * asking you to write a PDF file with the content for specific pages.
+ * CancellationSignal, LayoutResultCallback, Bundle)}, you <strong>may</strong> get
+ * a call to {@link #onWrite(PageRange[], ParcelFileDescriptor, CancellationSignal,
+ * WriteResultCallback)} asking you to write a PDF file with the content for
+ * specific pages.
  * </li>
  * <li>
  * Finally, you will receive a call to {@link #onFinish()}. You can use this
  * callback to release resources allocated in {@link #onStart()}.
  * </li>
  * </ul>
+ * <p>
+ * The {@link #onStart()} callback is always the first call you will receive and
+ * is useful for doing one time setup or resource allocation before printing. You
+ * will not receive a subsequent call here.
+ * </p>
+ * <p>
+ * The {@link #onLayout(PrintAttributes, PrintAttributes, CancellationSignal,
+ * LayoutResultCallback, Bundle)} callback requires that you layout the content
+ * based on the current {@link PrintAttributes}. The execution of this method is
+ * not considered completed until you invoke one of the methods on the passed in
+ * callback instance. Hence, you will not receive a subsequent call to any other
+ * method of this class until the execution of this method is complete by invoking
+ * one of the callback methods.
+ * </p>
+ * <p>
+ * The {@link #onWrite(PageRange[], ParcelFileDescriptor, CancellationSignal,
+ * WriteResultCallback)} requires that you render and write the content of some
+ * pages to the provided destination. The execution of this method is not
+ * considered complete until you invoke one of the methods on the passed in
+ * callback instance. Hence, you will not receive a subsequent call to any other
+ * method of this class until the execution of this method is complete by invoking
+ * one of the callback methods. You will never receive a sequence of one or more
+ * calls to this method without a previous call to {@link #onLayout(PrintAttributes,
+ * PrintAttributes, CancellationSignal, LayoutResultCallback, Bundle)}.
+ * </p>
+ * <p>
+ * The {@link #onFinish()} callback is always the last call you will receive and
+ * is useful for doing one time cleanup or resource deallocation after printing.
+ * You will not receive a subsequent call here.
+ * </p>
  * </p>
  * <h3>Implementation</h3>
  * <p>
@@ -54,7 +85,11 @@
  * of the work on an arbitrary thread. For example, if the printed content
  * does not depend on the UI state, i.e. on what is shown on the screen, then
  * you can offload the entire work on a dedicated thread, thus making your
- * application interactive while the print work is being performed.
+ * application interactive while the print work is being performed. Note that
+ * while your activity is covered by the system print UI and a user cannot
+ * interact with it, doing the printing work on the main application thread
+ * may affect the performance of your other application components as they
+ * are also executed on that thread.
  * </p>
  * <p>
  * You can also do work on different threads, for example if you print UI
@@ -64,7 +99,7 @@
  * This will ensure that the UI does not change while you are laying out the
  * printed content. Then you can handle {@link #onWrite(PageRange[], ParcelFileDescriptor,
  * CancellationSignal, WriteResultCallback)} and {@link #onFinish()} on another
- * thread. This will ensure that the UI is frozen for the minimal amount of
+ * thread. This will ensure that the main thread is busy for a minimal amount of
  * time. Also this assumes that you will generate the printed content in
  * {@link #onLayout(PrintAttributes, PrintAttributes, CancellationSignal,
  * LayoutResultCallback, Bundle)} which is not mandatory. If you use multiple
@@ -76,6 +111,12 @@
     /**
      * Extra: mapped to a boolean value that is <code>true</code> if
      * the current layout is for a print preview, <code>false</code> otherwise.
+     * This extra is provided in the {@link Bundle} argument of the {@link
+     * #onLayout(PrintAttributes, PrintAttributes, CancellationSignal,
+     * LayoutResultCallback, Bundle)} callback.
+     *
+     * @see #onLayout(PrintAttributes, PrintAttributes, CancellationSignal,
+     * LayoutResultCallback, Bundle)
      */
     public static final String EXTRA_PRINT_PREVIEW = "EXTRA_PRINT_PREVIEW";
 
@@ -95,17 +136,20 @@
      * After you are done laying out, you <strong>must</strong> invoke: {@link
      * LayoutResultCallback#onLayoutFinished(PrintDocumentInfo, boolean)} with
      * the last argument <code>true</code> or <code>false</code> depending on
-     * whether the layout changed the content or not, respectively; and {@link
-     * LayoutResultCallback#onLayoutFailed(CharSequence)}, if an error occurred.
-     * Note that you must call one of the methods of the given callback.
+     * whether the layout changed the content or not, respectively; or {@link
+     * LayoutResultCallback#onLayoutFailed(CharSequence)}, if an error occurred;
+     * or {@link LayoutResultCallback#onLayoutCancelled()} if layout was
+     * cancelled in a response to a cancellation request via the passed in
+     * {@link CancellationSignal}. Note that you <strong>must</strong> call one of
+     * the methods of the given callback for this method to be considered complete.
      * </p>
      * <p>
      * <strong>Note:</strong> If the content is large and a layout will be
      * performed, it is a good practice to schedule the work on a dedicated
      * thread and register an observer in the provided {@link
      * CancellationSignal} upon invocation of which you should stop the
-     * layout. The cancellation callback will not be made on the main
-     * thread.
+     * layout. The cancellation callback <strong>will not</strong> be made on
+     * the main thread.
      * </p>
      *
      * @param oldAttributes The old print attributes.
@@ -128,10 +172,12 @@
      * on the main thread.
      *<p>
      * After you are done writing, you should close the file descriptor and
-     * invoke {@link WriteResultCallback #onWriteFinished(PageRange[]), if writing
+     * invoke {@link WriteResultCallback#onWriteFinished(PageRange[])}, if writing
      * completed successfully; or {@link WriteResultCallback#onWriteFailed(
-     * CharSequence)}, if an error occurred. Note that you must call one of
-     * the methods of the given callback.
+     * CharSequence)}, if an error occurred; or {@link WriteResultCallback#onWriteCancelled()},
+     * if writing was cancelled in a response to a cancellation request via the passed
+     * in {@link CancellationSignal}. Note that you <strong>must</strong> call one of
+     * the methods of the given callback for this method to be considered complete.
      * </p>
      * <p>
      * <strong>Note:</strong> If the printed content is large, it is a good
@@ -178,7 +224,8 @@
         /**
          * Notifies that all the data was written.
          *
-         * @param pages The pages that were written. Cannot be null or empty.
+         * @param pages The pages that were written. Cannot be <code>null</code>
+         * or empty.
          */
         public void onWriteFinished(PageRange[] pages) {
             /* do nothing - stub */
@@ -187,7 +234,8 @@
         /**
          * Notifies that an error occurred while writing the data.
          *
-         * @param error Error message. May be null if error is unknown.
+         * @param error The <strong>localized</strong> error message.
+         * shown to the user. May be <code>null</code> if error is unknown.
          */
         public void onWriteFailed(CharSequence error) {
             /* do nothing - stub */
@@ -218,7 +266,7 @@
         /**
          * Notifies that the layout finished and whether the content changed.
          *
-         * @param info An info object describing the document. Cannot be null.
+         * @param info An info object describing the document. Cannot be <code>null</code>.
          * @param changed Whether the layout changed.
          *
          * @see PrintDocumentInfo
@@ -230,7 +278,8 @@
         /**
          * Notifies that an error occurred while laying out the document.
          *
-         * @param error Error message. May be null if error is unknown.
+         * @param error The <strong>localized</strong> error message.
+         * shown to the user. May be <code>null</code> if error is unknown.
          */
         public void onLayoutFailed(CharSequence error) {
             /* do nothing - stub */
diff --git a/core/java/android/print/PrintDocumentInfo.java b/core/java/android/print/PrintDocumentInfo.java
index b721ef4..928be6c 100644
--- a/core/java/android/print/PrintDocumentInfo.java
+++ b/core/java/android/print/PrintDocumentInfo.java
@@ -21,12 +21,56 @@
 import android.text.TextUtils;
 
 /**
- * This class encapsulates information about a printed document.
+ * This class encapsulates information about a document for printing
+ * purposes. This meta-data is used by the platform and print services,
+ * components that interact with printers. For example, this class
+ * contains the number of pages contained in the document it describes and
+ * this number of pages is shown to the user allowing him/her to select
+ * the range to print. Also a print service may optimize the printing
+ * process based on the content type, such as document or photo.
+ * <p>
+ * Instances of this class are created by the printing application and
+ * passed to the {@link PrintDocumentAdapter.LayoutResultCallback#onLayoutFinished(
+ * PrintDocumentInfo, boolean) PrintDocumentAdapter.LayoutResultCallback.onLayoutFinished(
+ * PrintDocumentInfo, boolean)} callback after successfully laying out the
+ * content which is performed in {@link PrintDocumentAdapter#onLayout(PrintAttributes,
+ * PrintAttributes, android.os.CancellationSignal, PrintDocumentAdapter.LayoutResultCallback,
+ * android.os.Bundle) PrintDocumentAdapter.onLayout(PrintAttributes,
+ * PrintAttributes, android.os.CancellationSignal,
+ * PrintDocumentAdapter.LayoutResultCallback, android.os.Bundle)}.
+ * </p>
+ * <p>
+ * An example usage looks like this:
+ * <pre>
+ *
+ * . . .
+ *
+ * public void onLayout(PrintAttributes oldAttributes, PrintAttributes newAttributes,
+ *         CancellationSignal cancellationSignal, LayoutResultCallback callback,
+ *         Bundle metadata) {
+ *
+ *        // Assume the app defined a LayoutResult class which contains
+ *        // the layout result data and that the content is a document.
+ *        LayoutResult result = doSomeLayoutWork();
+ *
+ *        PrintDocumentInfo info = new PrintDocumentInfo
+ *                .Builder("printed_file.pdf")
+ *                .setContentType(PrintDocumentInfo.CONTENT_TYPE_DOCUMENT)
+ *                .setPageCount(result.getPageCount())
+ *                .build();
+ *
+ *       callback.onLayoutFinished(info, result.getContentChanged());
+ *   }
+ *
+ *   . . .
+ *
+ * </pre>
+ * </p>
  */
 public final class PrintDocumentInfo implements Parcelable {
 
     /**
-     * Constant for unknown page count..
+     * Constant for unknown page count.
      */
     public static final int PAGE_COUNT_UNKNOWN = -1;
 
@@ -37,11 +81,23 @@
 
     /**
      * Content type: document.
+     * <p>
+     * A print service may use normal paper to print the content instead
+     * of dedicated photo paper. Also it may use a lower quality printing
+     * process as the content is not as sensitive to print quality variation
+     * as a photo is.
+     * </p>
      */
     public static final int CONTENT_TYPE_DOCUMENT = 0;
 
     /**
      * Content type: photo.
+     * <p>
+     * A print service may use dedicated photo paper to print the content
+     * instead of normal paper. Also it may use a higher quality printing
+     * process as the content is more sensitive to print quality variation
+     * than a document.
+     * </p>
      */
     public static final int CONTENT_TYPE_PHOTO = 1;
 
@@ -82,7 +138,8 @@
     }
 
     /**
-     * Gets the document name.
+     * Gets the document name. This name may be shown to
+     * the user.
      *
      * @return The document name.
      */
@@ -213,20 +270,23 @@
     }
 
     /**
-     * Builder for creating an {@link PrintDocumentInfo}.
+     * Builder for creating a {@link PrintDocumentInfo}.
      */
     public static final class Builder {
         private final PrintDocumentInfo mPrototype;
 
         /**
          * Constructor.
+         * 
          * <p>
-         * The values of the relevant properties are initialized with default
-         * values. Please refer to the documentation of the individual setters
-         * for information about the default values.
+         * The values of the relevant properties are initialized with defaults.
+         * Please refer to the documentation of the individual setters for
+         * information about the default values.
          * </p>
          *
-         * @param name The document name. Cannot be empty. 
+         * @param name The document name which may be shown to the user and
+         * is the file name if the content it describes is saved as a PDF.
+         * Cannot be empty. 
          */
         public Builder(String name) {
             if (TextUtils.isEmpty(name)) {
diff --git a/core/java/android/print/PrintJob.java b/core/java/android/print/PrintJob.java
index 535ae43..0abe2193 100644
--- a/core/java/android/print/PrintJob.java
+++ b/core/java/android/print/PrintJob.java
@@ -17,8 +17,13 @@
 package android.print;
 
 /**
- * This class represents a print job from the perspective of
- * an application.
+ * This class represents a print job from the perspective of an
+ * application. It contains behavior methods for performing operations
+ * on it as well as methods for querying its state. A snapshot of the
+ * print job state is represented by the {@link PrintJobInfo} class.
+ * The state of a print job may change over time. An application receives
+ * instances of this class when creating a print job or querying for
+ * its print jobs.
  */
 public final class PrintJob {
 
@@ -145,11 +150,12 @@
     /**
      * Gets whether this print job is failed. Such a print job is
      * not successfully printed due to an error. You can request
-     * a restart via {@link #restart()}.
+     * a restart via {@link #restart()} or cancel via {@link #cancel()}.
      *
      * @return Whether the print job is failed.
      *
      * @see #restart()
+     * @see #cancel()
      */
     public boolean isFailed() {
         return getInfo().getState() == PrintJobInfo.STATE_FAILED;
diff --git a/core/java/android/print/PrintJobInfo.java b/core/java/android/print/PrintJobInfo.java
index c6f0a68..c2f190d 100644
--- a/core/java/android/print/PrintJobInfo.java
+++ b/core/java/android/print/PrintJobInfo.java
@@ -22,7 +22,10 @@
 import java.util.Arrays;
 
 /**
- * This class represents the description of a print job.
+ * This class represents the description of a print job. The print job
+ * state includes properties such as its id, print attributes used for
+ * generating the content, and so on. Note that the print jobs state may
+ * change over time and this class represents a snapshot of this state.
  */
 public final class PrintJobInfo implements Parcelable {
 
@@ -93,7 +96,7 @@
     public static final int STATE_BLOCKED = 4;
 
     /**
-     * Print job state: The print job was successfully printed.
+     * Print job state: The print job is successfully printed.
      * This is a terminal state.
      * <p>
      * Next valid states: None
@@ -103,15 +106,14 @@
 
     /**
      * Print job state: The print job was printing but printing failed.
-     * This is a terminal state.
      * <p>
-     * Next valid states: None
+     * Next valid states: {@link #STATE_CANCELED}, {@link #STATE_STARTED}
      * </p>
      */
     public static final int STATE_FAILED = 6;
 
     /**
-     * Print job state: The print job was canceled.
+     * Print job state: The print job is canceled.
      * This is a terminal state.
      * <p>
      * Next valid states: None
@@ -297,6 +299,14 @@
      * Gets the current job state.
      *
      * @return The job state.
+     *
+     * @see #STATE_CREATED
+     * @see #STATE_QUEUED
+     * @see #STATE_STARTED
+     * @see #STATE_COMPLETED
+     * @see #STATE_BLOCKED
+     * @see #STATE_FAILED
+     * @see #STATE_CANCELED
      */
     public int getState() {
         return mState;
@@ -611,7 +621,7 @@
          * Constructor.
          *
          * @param prototype Prototype to use as a starting point.
-         * Can be null.
+         * Can be <code>null</code>.
          */
         public Builder(PrintJobInfo prototype) {
             mPrototype = (prototype != null)
diff --git a/core/java/android/print/PrintManager.java b/core/java/android/print/PrintManager.java
index 955b4d8..bbfc307 100644
--- a/core/java/android/print/PrintManager.java
+++ b/core/java/android/print/PrintManager.java
@@ -55,6 +55,49 @@
  * PrintManager printManager =
  *         (PrintManager) context.getSystemService(Context.PRINT_SERVICE);
  * </pre>
+ * 
+ * <h3>Print mechanics</h3>
+ * <p>
+ * The key idea behind printing on the platform is that the content to be printed
+ * should be laid out for the currently selected print options resulting in an
+ * optimized output and higher user satisfaction. To achieve this goal the platform
+ * declares a contract that the printing application has to follow which is defined
+ * by the {@link PrintDocumentAdapter} class. At a higher level the contract is that
+ * when the user selects some options from the print UI that may affect the way
+ * content is laid out, for example page size, the application receives a callback
+ * allowing it to layout the content to better fit these new constraints. After a
+ * layout pass the system may ask the application to render one or more pages one
+ * or more times. For example, an application may produce a single column list for
+ * smaller page sizes and a multi-column table for larger page sizes.
+ * </p>
+ * <h3>Print jobs</h3>
+ * <p>
+ * Print jobs are started by calling the {@link #print(String, PrintDocumentAdapter,
+ * PrintAttributes)} from an activity which results in bringing up the system print
+ * UI. Once the print UI is up, when the user changes a selected print option that
+ * affects the way content is laid out the system starts to interact with the
+ * application following the mechanics described the section above.
+ * </p>
+ * <p>
+ * Print jobs can be in {@link PrintJobInfo#STATE_CREATED created}, {@link
+ * PrintJobInfo#STATE_QUEUED queued}, {@link PrintJobInfo#STATE_STARTED started},
+ * {@link PrintJobInfo#STATE_BLOCKED blocked}, {@link PrintJobInfo#STATE_COMPLETED
+ * completed}, {@link PrintJobInfo#STATE_FAILED failed}, and {@link
+ * PrintJobInfo#STATE_CANCELED canceled} state. Print jobs are stored in dedicated
+ * system spooler until they are handled which is they are cancelled or completed.
+ * Active print jobs, ones that are not cancelled or completed, are considered failed
+ * if the device reboots as the new boot may be after a very long time. The user may
+ * choose to restart such print jobs. Once a print job is queued all relevant content
+ * is stored in the system spooler and its lifecycle becomes detached from this of
+ * the application that created it.
+ * </p>
+ * <p>
+ * An applications can query the print spooler for current print jobs it created
+ * but not print jobs created by other applications.
+ * </p>
+ *
+ * @see PrintJob
+ * @see PrintJobInfo
  */
 public final class PrintManager {
 
@@ -292,20 +335,54 @@
     /**
      * Creates a print job for printing a {@link PrintDocumentAdapter} with
      * default print attributes.
-     * 
-     * @param printJobName A name for the new print job.
+     * <p>
+     * Calling this method brings the print UI allowing the user to customize
+     * the print job and returns a {@link PrintJob} object without waiting for the
+     * user to customize or confirm the print job. The returned print job instance
+     * is in a {@link PrintJobInfo#STATE_CREATED created} state.
+     * <p>
+     * This method can be called only from an {@link Activity}. The rationale is that
+     * printing from a service will create an inconsistent user experience as the print
+     * UI would appear without any context.
+     * </p>
+     * <p>
+     * Also the passed in {@link PrintDocumentAdapter} will be considered invalid if
+     * your activity is finished. The rationale is that once the activity that
+     * initiated printing is finished, the provided adapter may be in an inconsistent
+     * state as it may depend on the UI presented by the activity.
+     * </p>
+     * <p>
+     * The default print attributes are a hint to the system how the data is to
+     * be printed. For example, a photo editor may look at the photo aspect ratio
+     * to determine the default orientation and provide a hint whether the printing
+     * should be in portrait or landscape. The system will do a best effort to
+     * selected the hinted options in the print dialog, given the current printer
+     * supports them.
+     * </p>
+     *
+     * @param printJobName A name for the new print job which is shown to the user.
      * @param documentAdapter An adapter that emits the document to print.
-     * @param attributes The default print job attributes.
+     * @param attributes The default print job attributes or <code>null</code>.
      * @return The created print job on success or null on failure.
+     * @throws IllegalStateException If not called from an {@link Activity}.
+     * @throws IllegalArgumentException If the print job name is empty or the
+     * document adapter is null.
+     *
      * @see PrintJob
      */
     public PrintJob print(String printJobName, PrintDocumentAdapter documentAdapter,
             PrintAttributes attributes) {
+        if (!(mContext instanceof Activity)) {
+            throw new IllegalStateException("Can print only from an activity");
+        }
         if (TextUtils.isEmpty(printJobName)) {
-            throw new IllegalArgumentException("priintJobName cannot be empty");
+            throw new IllegalArgumentException("printJobName cannot be empty");
+        }
+        if (documentAdapter == null) {
+            throw new IllegalArgumentException("documentAdapter cannot be null");
         }
         PrintDocumentAdapterDelegate delegate = new PrintDocumentAdapterDelegate(
-                mContext, documentAdapter);
+                (Activity) mContext, documentAdapter);
         try {
             Bundle result = mService.print(printJobName, delegate,
                     attributes, mContext.getPackageName(), mAppId, mUserId);
@@ -398,12 +475,9 @@
 
         private boolean mDestroyed;
 
-        public PrintDocumentAdapterDelegate(Context context,
+        public PrintDocumentAdapterDelegate(Activity activity,
                 PrintDocumentAdapter documentAdapter) {
-            if (!(context instanceof Activity)) {
-                throw new IllegalStateException("Can print only from an activity");
-            }
-            mActivity = (Activity) context;
+            mActivity = activity;
             mDocumentAdapter = documentAdapter;
             mHandler = new MyHandler(mActivity.getMainLooper());
             mActivity.getApplication().registerActivityLifecycleCallbacks(this);
diff --git a/core/java/android/print/PrinterCapabilitiesInfo.java b/core/java/android/print/PrinterCapabilitiesInfo.java
index df51ec1..b615600 100644
--- a/core/java/android/print/PrinterCapabilitiesInfo.java
+++ b/core/java/android/print/PrinterCapabilitiesInfo.java
@@ -24,10 +24,17 @@
 
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Collections;
 import java.util.List;
 
 /**
- * This class represents the capabilities of a printer.
+ * This class represents the capabilities of a printer. Instances
+ * of this class are created by a print service to report the
+ * capabilities of a printer it manages. The capabilities of a
+ * printer specify how it can print content. For example, what
+ * are the media sizes supported by the printer, what are the
+ * minimal margins of the printer based on its technical design,
+ * etc.
  */
 public final class PrinterCapabilitiesInfo implements Parcelable {
     /**
@@ -112,7 +119,7 @@
      * @return The media sizes.
      */
     public List<MediaSize> getMediaSizes() {
-        return mMediaSizes;
+        return Collections.unmodifiableList(mMediaSizes);
     }
 
     /**
@@ -121,7 +128,7 @@
      * @return The resolutions.
      */
     public List<Resolution> getResolutions() {
-        return mResolutions;
+        return Collections.unmodifiableList(mResolutions);
     }
 
     /**
@@ -135,9 +142,9 @@
     }
 
     /**
-     * Gets the supported color modes.
+     * Gets the bit mask of supported color modes.
      *
-     * @return The color modes.
+     * @return The bit mask of supported color modes.
      *
      * @see PrintAttributes#COLOR_MODE_COLOR
      * @see PrintAttributes#COLOR_MODE_MONOCHROME
@@ -355,9 +362,10 @@
     }
 
     /**
-     * Builder for creating of a {@link PrinterInfo}. This class is responsible
-     * to enforce that all required attributes have at least one default value.
-     * In other words, this class creates only well-formed {@link PrinterInfo}s.
+     * Builder for creating of a {@link PrinterCapabilitiesInfo}. This class is
+     * responsible to enforce that all required attributes have at least one
+     * default value. In other words, this class creates only well-formed {@link
+     * PrinterCapabilitiesInfo}s.
      * <p>
      * Look at the individual methods for a reference whether a property is
      * required or if it is optional.
@@ -369,9 +377,9 @@
         /**
          * Creates a new instance.
          *
-         * @param printerId The printer id. Cannot be null.
+         * @param printerId The printer id. Cannot be <code>null</code>.
          *
-         * @throws IllegalArgumentException If the printer id is null.
+         * @throws IllegalArgumentException If the printer id is <code>null</code>.
          */
         public Builder(PrinterId printerId) {
             if (printerId == null) {
@@ -492,7 +500,7 @@
 
         /**
          * Crates a new {@link PrinterCapabilitiesInfo} enforcing that all
-         * required properties have need specified. See individual methods
+         * required properties have been specified. See individual methods
          * in this class for reference about required attributes.
          *
          * @return A new {@link PrinterCapabilitiesInfo}.
@@ -521,7 +529,7 @@
             if (mPrototype.mMinMargins == null) {
                 throw new IllegalArgumentException("margins cannot be null");
             }
-            return new PrinterCapabilitiesInfo(mPrototype);
+            return mPrototype;
         }
 
         private void throwIfDefaultAlreadySpecified(int propertyIndex) {
diff --git a/core/java/android/print/PrinterInfo.java b/core/java/android/print/PrinterInfo.java
index ad79a38..7fcc81f 100644
--- a/core/java/android/print/PrinterInfo.java
+++ b/core/java/android/print/PrinterInfo.java
@@ -21,7 +21,12 @@
 import android.text.TextUtils;
 
 /**
- * This class represents the description of a printer.
+ * This class represents the description of a printer. Instances of
+ * this class are created by print services to report to the system
+ * the printers they manage. The information of this class has two
+ * major components, printer properties such as name, id, status,
+ * description and printer capabilities which describe the various
+ * print modes a printer supports such as media sizes, margins, etc.
  */
 public final class PrinterInfo implements Parcelable {
 
@@ -96,6 +101,10 @@
      * Gets the printer status.
      *
      * @return The status.
+     *
+     * @see #STATUS_BUSY
+     * @see #STATUS_IDLE
+     * @see #STATUS_UNAVAILABLE
      */
     public int getStatus() {
         return mStatus;
@@ -216,6 +225,8 @@
          * @param printerId The printer id. Cannot be null.
          * @param name The printer name. Cannot be empty.
          * @param status The printer status. Must be a valid status.
+         * @throws IllegalArgumentException If the printer id is null, or the
+         * printer name is empty or the status is not a valid one.
          */
         public Builder(PrinterId printerId, String name, int status) {
             if (printerId == null) {
@@ -259,7 +270,8 @@
         }
 
         /**
-         * Sets the printer name.
+         * Sets the <strong>localized</strong> printer name which
+         * is shown to the user
          *
          * @param name The name.
          * @return This builder.
@@ -270,7 +282,8 @@
         }
 
         /**
-         * Sets the printer description.
+         * Sets the <strong>localized</strong> printer description
+         * which is shown to the user
          *
          * @param description The description.
          * @return This builder.
@@ -292,12 +305,12 @@
         }
 
         /**
-         * Crates a new {@link PrinterInfo}.
+         * Creates a new {@link PrinterInfo}.
          *
          * @return A new {@link PrinterInfo}.
          */
         public PrinterInfo build() {
-            return new PrinterInfo(mPrototype);
+            return mPrototype;
         }
 
         private boolean isValidStatus(int status) {
diff --git a/core/java/android/print/package.html b/core/java/android/print/package.html
new file mode 100644
index 0000000..579567d
--- /dev/null
+++ b/core/java/android/print/package.html
@@ -0,0 +1,46 @@
+<HTML>
+<BODY>
+<h3>Overview</h3>
+<p>
+Provides classes for implementing print support in applications and also contains all
+base classes and abstractions involved in printing. These base classes are also used
+by other more specialized printing related packages.
+</p>
+<p>
+The entry point for interacting with the print system is the {@link android.print.PrintManager}
+which is a system service that can be obtained from the current context. The print manager
+provides APIs for printing, querying the state of print jobs, etc.
+<p/>
+<h3>Print contract</h3>
+<p>
+An application that wants to implement printing must extend
+{@link android.print.PrintDocumentAdapter} which defines the contract between the system
+and the application.The key idea behind this adapter is that the printed content may change
+based on the selected print options, such as media size, orientation, which
+requires the content to be re-laid out. The constraints according to which the content has
+to be laid out are encapsulated in the {@link android.print.PrintAttributes} class. Once
+layout is completed the application calls back to the system passing a
+{@link android.print.PrintDocumentInfo} instance which describes the generated content. After
+the content has been laid out the application may be asked to render some pages of that content
+for preview or printing. The range of pages that have to be rendered is abstracted by the
+{@link android.print.PageRange} class.
+</p>
+<h3>Print jobs</h3>
+<p>
+A print job is represented by the {@link android.print.PrintJob} class which has behavior
+methods as well as methods for querying its state. Each print job has a unique id represented
+by the {@link android.print.PrintJobId} class and exposes APIs for obtaining a {@link
+android.print.PrintJobInfo} which is a snapshot of its state. The print job state may
+change over time.
+</p>
+<h3>Printers</h3>
+<p>
+An available printer represented by the {@link android.print.PrinterInfo} class has a
+unique id which is abstracted by the {@link android.print.PrinterId} class. The {@link
+android.print.PrinterInfo} contains printer properties such as id, name, description, status,
+and printer capabilities encapsulated in the {@link android.print.PrinterCapabilitiesInfo}
+class. Printer capabilities describe how a printer can print content, for example what are
+the supported media sizes, color modes, resolutions, etc.
+<p>
+</BODY>
+</HTML>
diff --git a/core/java/android/provider/DocumentsContract.java b/core/java/android/provider/DocumentsContract.java
index 7f8dca2..09f5fe3 100644
--- a/core/java/android/provider/DocumentsContract.java
+++ b/core/java/android/provider/DocumentsContract.java
@@ -81,6 +81,9 @@
     /** {@hide} */
     public static final String EXTRA_PACKAGE_NAME = "android.content.extra.PACKAGE_NAME";
 
+    /** {@hide} */
+    public static final String EXTRA_SHOW_ADVANCED = "android.content.extra.SHOW_ADVANCED";
+
     /**
      * Included in {@link AssetFileDescriptor#getExtras()} when returned
      * thumbnail should be rotated.
diff --git a/core/java/android/transition/Scene.java b/core/java/android/transition/Scene.java
index 5800bd5..e1f1896 100644
--- a/core/java/android/transition/Scene.java
+++ b/core/java/android/transition/Scene.java
@@ -57,7 +57,7 @@
                 com.android.internal.R.id.scene_layoutid_cache);
         if (scenes == null) {
             scenes = new SparseArray<Scene>();
-            sceneRoot.setTag(com.android.internal.R.id.scene_layoutid_cache, scenes);
+            sceneRoot.setTagInternal(com.android.internal.R.id.scene_layoutid_cache, scenes);
         }
         Scene scene = scenes.get(layoutId);
         if (scene != null) {
diff --git a/core/java/android/transition/TransitionManager.java b/core/java/android/transition/TransitionManager.java
index 9b1494d..3bf6790 100644
--- a/core/java/android/transition/TransitionManager.java
+++ b/core/java/android/transition/TransitionManager.java
@@ -82,6 +82,8 @@
      * an {@link AutoTransition} instance.
      *
      * @param transition The default transition to be used for scene changes.
+     *
+     * @hide pending later changes
      */
     public void setDefaultTransition(Transition transition) {
         sDefaultTransition = transition;
@@ -93,6 +95,8 @@
      *
      * @return The current default transition.
      * @see #setDefaultTransition(Transition)
+     *
+     * @hide pending later changes
      */
     public static Transition getDefaultTransition() {
         return sDefaultTransition;
@@ -105,7 +109,7 @@
      * transition to run.
      * @param transition The transition that will play when the given scene is
      * entered. A value of null will result in the default behavior of
-     * using the {@link #getDefaultTransition() default transition} instead.
+     * using the default transition instead.
      */
     public void setTransition(Scene scene, Transition transition) {
         mSceneTransitions.put(scene, transition);
@@ -121,7 +125,7 @@
      * be run
      * @param transition The transition that will play when the given scene is
      * entered. A value of null will result in the default behavior of
-     * using the {@link #getDefaultTransition() default transition} instead.
+     * using the default transition instead.
      */
     public void setTransition(Scene fromScene, Scene toScene, Transition transition) {
         ArrayMap<Scene, Transition> sceneTransitionMap = mScenePairTransitions.get(toScene);
@@ -139,8 +143,8 @@
      *
      * @param scene The scene being entered
      * @return The Transition to be used for the given scene change. If no
-     * Transition was specified for this scene change, the {@link #getDefaultTransition()
-     * default transition} will be used instead.
+     * Transition was specified for this scene change, the default transition
+     * will be used instead.
      */
     private Transition getTransition(Scene scene) {
         Transition transition = null;
diff --git a/core/java/com/android/internal/app/ResolverActivity.java b/core/java/com/android/internal/app/ResolverActivity.java
index cd853b6..591267e 100644
--- a/core/java/com/android/internal/app/ResolverActivity.java
+++ b/core/java/com/android/internal/app/ResolverActivity.java
@@ -181,11 +181,12 @@
             } else {
                 mAlwaysUseOption = false;
             }
-        }
-        final int initialHighlight = mAdapter.getInitialHighlight();
-        if (initialHighlight >= 0) {
-            mListView.setItemChecked(initialHighlight, true);
-            onItemClick(null, null, initialHighlight, 0); // Other entries are not used
+            // Set the initial highlight if there was a preferred or last used choice
+            final int initialHighlight = mAdapter.getInitialHighlight();
+            if (initialHighlight >= 0) {
+                mListView.setItemChecked(initialHighlight, true);
+                onItemClick(null, null, initialHighlight, 0); // Other entries are not used
+            }
         }
     }
 
diff --git a/core/jni/android_os_Trace.cpp b/core/jni/android_os_Trace.cpp
index 01d02c5..b11c5bb 100644
--- a/core/jni/android_os_Trace.cpp
+++ b/core/jni/android_os_Trace.cpp
@@ -15,6 +15,7 @@
  */
 
 #define LOG_TAG "Trace"
+// #define LOG_NDEBUG 0
 
 #include <JNIHelp.h>
 #include <ScopedUtfChars.h>
@@ -46,6 +47,8 @@
 static void android_os_Trace_nativeTraceCounter(JNIEnv* env, jclass clazz,
         jlong tag, jstring nameStr, jint value) {
     ScopedUtfChars name(env, nameStr);
+
+    ALOGV("%s: %lld %s %d", __FUNCTION__, tag, name.c_str(), value);
     atrace_int(tag, name.c_str(), value);
 }
 
@@ -55,11 +58,15 @@
     ScopedStringChars jchars(env, nameStr);
     String8 utf8Chars(reinterpret_cast<const char16_t*>(jchars.get()), jchars.size());
     sanitizeString(utf8Chars);
+
+    ALOGV("%s: %lld %s", __FUNCTION__, tag, utf8Chars.string());
     atrace_begin(tag, utf8Chars.string());
 }
 
 static void android_os_Trace_nativeTraceEnd(JNIEnv* env, jclass clazz,
         jlong tag) {
+
+    ALOGV("%s: %lld", __FUNCTION__, tag);
     atrace_end(tag);
 }
 
@@ -69,6 +76,8 @@
     ScopedStringChars jchars(env, nameStr);
     String8 utf8Chars(reinterpret_cast<const char16_t*>(jchars.get()), jchars.size());
     sanitizeString(utf8Chars);
+
+    ALOGV("%s: %lld %s %d", __FUNCTION__, tag, utf8Chars.string(), cookie);
     atrace_async_begin(tag, utf8Chars.string(), cookie);
 }
 
@@ -78,16 +87,22 @@
     ScopedStringChars jchars(env, nameStr);
     String8 utf8Chars(reinterpret_cast<const char16_t*>(jchars.get()), jchars.size());
     sanitizeString(utf8Chars);
+
+    ALOGV("%s: %lld %s %d", __FUNCTION__, tag, utf8Chars.string(), cookie);
     atrace_async_end(tag, utf8Chars.string(), cookie);
 }
 
 static void android_os_Trace_nativeSetAppTracingAllowed(JNIEnv* env,
         jclass clazz, jboolean allowed) {
+    ALOGV("%s: %d", __FUNCTION__, allowed);
+
     atrace_set_debuggable(allowed);
 }
 
 static void android_os_Trace_nativeSetTracingEnabled(JNIEnv* env,
         jclass clazz, jboolean enabled) {
+    ALOGV("%s: %d", __FUNCTION__, enabled);
+
     atrace_set_tracing_enabled(enabled);
 }
 
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index e82ad1e..490eab8 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -97,6 +97,13 @@
          the SIM card. -->
     <string name="needPuk">Your SIM card is PUK-locked. Type the PUK code to unlock it.</string>
     <string name="needPuk2">Type PUK2 to unblock SIM card.</string>
+    <!-- Displayed when user attempts to change SIM PIN1 without enabling PIN1. -->
+    <string name="enablePin">Unsuccessful, enable SIM/RUIM Lock.</string>
+    <!-- Displayed when a SIM PIN/PUK is entered incorrectly. -->
+    <plurals name="pinpuk_attempts">
+        <item quantity="one">You have <xliff:g id="number">%d</xliff:g> remaining attempt before SIM is locked.</item>
+        <item quantity="other">You have <xliff:g id="number">%d</xliff:g> remaining attempts before SIM is locked.</item>
+    </plurals>
     <!-- Title for the dialog used to display the user's IMEI number [CHAR LIMIT=10] -->
     <string name="imei">IMEI</string>
 
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index dc0841a..a5573c9 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -612,6 +612,7 @@
   <java-symbol type="string" name="more_item_label" />
   <java-symbol type="string" name="needPuk" />
   <java-symbol type="string" name="needPuk2" />
+  <java-symbol type="string" name="enablePin" />
   <java-symbol type="string" name="new_app_action" />
   <java-symbol type="string" name="new_app_description" />
   <java-symbol type="string" name="noApplications" />
@@ -965,6 +966,7 @@
   <java-symbol type="plurals" name="num_minutes_ago" />
   <java-symbol type="plurals" name="num_seconds_ago" />
   <java-symbol type="plurals" name="restr_pin_countdown" />
+  <java-symbol type="plurals" name="pinpuk_attempts" />
 
   <java-symbol type="array" name="carrier_properties" />
   <java-symbol type="array" name="config_data_usage_network_types" />
diff --git a/data/fonts/Roboto-Bold.ttf b/data/fonts/Roboto-Bold.ttf
index 072b842..c5b9c67 100644
--- a/data/fonts/Roboto-Bold.ttf
+++ b/data/fonts/Roboto-Bold.ttf
Binary files differ
diff --git a/data/fonts/Roboto-BoldItalic.ttf b/data/fonts/Roboto-BoldItalic.ttf
index 74919ff..0320214 100644
--- a/data/fonts/Roboto-BoldItalic.ttf
+++ b/data/fonts/Roboto-BoldItalic.ttf
Binary files differ
diff --git a/data/fonts/Roboto-Italic.ttf b/data/fonts/Roboto-Italic.ttf
index 4642d6f..38ba570 100644
--- a/data/fonts/Roboto-Italic.ttf
+++ b/data/fonts/Roboto-Italic.ttf
Binary files differ
diff --git a/data/fonts/Roboto-Light.ttf b/data/fonts/Roboto-Light.ttf
index 13bf13a..271606b 100644
--- a/data/fonts/Roboto-Light.ttf
+++ b/data/fonts/Roboto-Light.ttf
Binary files differ
diff --git a/data/fonts/Roboto-LightItalic.ttf b/data/fonts/Roboto-LightItalic.ttf
index 130672a..17ef355 100644
--- a/data/fonts/Roboto-LightItalic.ttf
+++ b/data/fonts/Roboto-LightItalic.ttf
Binary files differ
diff --git a/data/fonts/Roboto-Regular.ttf b/data/fonts/Roboto-Regular.ttf
index 0ba95c9..7469063 100644
--- a/data/fonts/Roboto-Regular.ttf
+++ b/data/fonts/Roboto-Regular.ttf
Binary files differ
diff --git a/data/fonts/Roboto-Thin.ttf b/data/fonts/Roboto-Thin.ttf
index 309c22d..74efe4d 100644
--- a/data/fonts/Roboto-Thin.ttf
+++ b/data/fonts/Roboto-Thin.ttf
Binary files differ
diff --git a/data/fonts/Roboto-ThinItalic.ttf b/data/fonts/Roboto-ThinItalic.ttf
index 0b53ba4..f08ea51 100644
--- a/data/fonts/Roboto-ThinItalic.ttf
+++ b/data/fonts/Roboto-ThinItalic.ttf
Binary files differ
diff --git a/data/fonts/RobotoCondensed-Bold.ttf b/data/fonts/RobotoCondensed-Bold.ttf
index f0fd409..1252d00 100644
--- a/data/fonts/RobotoCondensed-Bold.ttf
+++ b/data/fonts/RobotoCondensed-Bold.ttf
Binary files differ
diff --git a/data/fonts/RobotoCondensed-BoldItalic.ttf b/data/fonts/RobotoCondensed-BoldItalic.ttf
index e67b02b0..e914a07 100644
--- a/data/fonts/RobotoCondensed-BoldItalic.ttf
+++ b/data/fonts/RobotoCondensed-BoldItalic.ttf
Binary files differ
diff --git a/data/fonts/RobotoCondensed-Italic.ttf b/data/fonts/RobotoCondensed-Italic.ttf
index a08414b..8a570cf 100644
--- a/data/fonts/RobotoCondensed-Italic.ttf
+++ b/data/fonts/RobotoCondensed-Italic.ttf
Binary files differ
diff --git a/data/fonts/RobotoCondensed-Regular.ttf b/data/fonts/RobotoCondensed-Regular.ttf
index 713fd30..a16b9cb 100644
--- a/data/fonts/RobotoCondensed-Regular.ttf
+++ b/data/fonts/RobotoCondensed-Regular.ttf
Binary files differ
diff --git a/docs/html/sdk/installing/studio.jd b/docs/html/sdk/installing/studio.jd
index 3399ee8..f2fd79b 100644
--- a/docs/html/sdk/installing/studio.jd
+++ b/docs/html/sdk/installing/studio.jd
@@ -253,36 +253,36 @@
     <td>Windows</td>
     <td>
   <a onclick="return onDownload(this)" id="win-studio"
-      href="http://dl.google.com/android/studio/android-studio-bundle-130.737825-windows.exe">
-      android-studio-bundle-130.737825-windows.exe
+      href="http://dl.google.com/android/studio/android-studio-bundle-132.883541-windows.exe">
+      android-studio-bundle-132.883541-windows.exe
       </a>
     </td>
-    <td>396091268 bytes</td>
-    <td>6da1bc8effa048c8ff669e4c484eb11f</td>
+    <td>448245492 bytes</td>
+    <td>ca5f5c4d21b4350ddf3bda7021a6ee5e</td>
   </tr>
 
   <tr>
     <td><nobr>Mac OS X</nobr></td>
     <td>
   <a onclick="return onDownload(this)" id="mac-studio"
-    href="http://dl.google.com/android/studio/android-studio-bundle-130.737825-mac.dmg">
-    android-studio-bundle-130.737825-mac.dmg
+    href="http://dl.google.com/android/studio/android-studio-bundle-132.883541-mac.dmg">
+    android-studio-bundle-132.883541-mac.dmg
     </a>
     </td>
-    <td>383326582 bytes</td>
-    <td>2959bc5039238d286670cc6225342b89</td>
+    <td>427317993 bytes</td>
+    <td>67831af6e7896a0a146d43423fabb542</td>
   </tr>
 
   <tr>
     <td>Linux</td>
     <td>
   <a onclick="return onDownload(this)" id="linux-studio"
-    href="http://dl.google.com/android/studio/android-studio-bundle-130.737825-linux.tgz">
-    android-studio-bundle-130.737825-linux.tgz
+    href="http://dl.google.com/android/studio/android-studio-bundle-132.883541-linux.tgz">
+    android-studio-bundle-132.883541-linux.tgz
     </a>
     </td>
-    <td>409935592 bytes</td>
-    <td>dcd13922f7cf577e3c852b224205d843</td>
+    <td>451652493 bytes</td>
+    <td>7a6f9b12b2cd5321ab0818b51306e01c</td>
   </tr>
   </table>
 
@@ -290,9 +290,13 @@
 
 
 
-<h2 id="Updating">Updating to 0.2.x</h2>
+<h2 id="Updating">Updating from older versions</h2>
 
-<p>To update from Android Studio 0.1.x to 0.2.x,
+<p>If you already have Android Studio installed, in most cases, you can upgrade to the latest
+version by installing a patch. From within Android Studio, select
+<strong>Help &gt; Check for updates</strong> to see whether an update is available.</p>
+
+<p>If an update is not available,
 follow the <a href="#Installing">installation instructions</a> below and replace your existing
 installation.</p>
 
@@ -304,13 +308,10 @@
 before installing the update. Then move them back once the update is complete.
 If you fail to copy these packages, then you can instead download them again through
 the Android SDK Manager.</p>
-<p><strong>Windows users:</strong> Do not install Android Studio 0.2.x in the same
-location as 0.1.x. Doing so may cause errors such as ClassCastException or other unexpected
-behaviors. It's best if you remove your previous version of Android Studio 0.1.x.</p>
 </div>
 
 
-<p>Also note that due to the update to Gradle 0.5, you will encounter errors when opening
+<p>Also note that due to the update to Android Gradle Plugin 0.6, you will encounter errors when opening
 existing projects. See the <a href="#Troubleshooting">Troubleshooting</a> notes below for
 information about how to resolve them.</p>
 
@@ -419,16 +420,22 @@
 
 <h2 id="Revisions">Revisions</h2>
 
-<p class="note"><strong>Note:</strong> <strong>There is not a patch update available from
-0.1.9 to 0.2</strong>. To update from Android Studio 0.1.x to 0.2.x, you must
-install a new Android Studio bundle from this page.  The reason for that is that we have made
-changes to the bundled SDK such that it includes a pre-configured local Maven repository
-which can serve up the v4 support library and which is required for creating new projects.</p>
-
-
 <div class="toggle-content opened">
   <p><a href="#" onclick="return toggleContent(this)">
     <img src="{@docRoot}assets/images/triangle-opened.png" class="toggle-content-img"
+      alt=""/>Android Studio v0.3.1</a> <em>(Oct 2013)</em>
+  </p>
+
+  <div class="toggle-content-toggleme">
+  <ul>
+    <li>See <a href="http://tools.android.com/recent">tools.android.com</a> for a full list of changes.</li>
+  </ul>
+  </div>
+</div>
+
+<div class="toggle-content closed">
+  <p><a href="#" onclick="return toggleContent(this)">
+    <img src="{@docRoot}assets/images/triangle-closed.png" class="toggle-content-img"
       alt=""/>Android Studio v0.2.x</a> <em>(July 2013)</em>
   </p>
 
@@ -610,7 +617,7 @@
   if (os) {
     /* set up primary ACE download button */
     $('#download-ide-button').show();
-    $('#download-ide-button').append("Download Android Studio <span class='small'>v0.2.x</span>"
+    $('#download-ide-button').append("Download Android Studio <span class='small'>v0.3.1</span>"
         + "<br/> <span class='small'>for " + os + "</span>");
     $('#download-ide-button').click(function() {return onDownload(this,true);}).attr('href', bundlename);
 
diff --git a/docs/html/training/displaying-bitmaps/cache-bitmap.jd b/docs/html/training/displaying-bitmaps/cache-bitmap.jd
index 25efe1e..ad084c2 100644
--- a/docs/html/training/displaying-bitmaps/cache-bitmap.jd
+++ b/docs/html/training/displaying-bitmaps/cache-bitmap.jd
@@ -346,6 +346,7 @@
         RetainFragment fragment = (RetainFragment) fm.findFragmentByTag(TAG);
         if (fragment == null) {
             fragment = new RetainFragment();
+            fm.beginTransaction().add(fragment, TAG).commit();
         }
         return fragment;
     }
diff --git a/media/java/android/media/MediaFocusControl.java b/media/java/android/media/MediaFocusControl.java
index 07d91ac..59d411d 100644
--- a/media/java/android/media/MediaFocusControl.java
+++ b/media/java/android/media/MediaFocusControl.java
@@ -1476,16 +1476,17 @@
      * Set the new remote control receiver at the top of the RC focus stack.
      * Called synchronized on mAudioFocusLock, then mRCStack
      * precondition: mediaIntent != null
+     * @return true if mRCStack was changed, false otherwise
      */
-    private void pushMediaButtonReceiver_syncAfRcs(PendingIntent mediaIntent, ComponentName target,
-            IBinder token) {
+    private boolean pushMediaButtonReceiver_syncAfRcs(PendingIntent mediaIntent,
+            ComponentName target, IBinder token) {
         // already at top of stack?
         if (!mRCStack.empty() && mRCStack.peek().mMediaIntent.equals(mediaIntent)) {
-            return;
+            return false;
         }
         if (mAppOps.noteOp(AppOpsManager.OP_TAKE_MEDIA_BUTTONS, Binder.getCallingUid(),
                 mediaIntent.getCreatorPackage()) != AppOpsManager.MODE_ALLOWED) {
-            return;
+            return false;
         }
         RemoteControlStackEntry rcse = null;
         boolean wasInsideStack = false;
@@ -1513,6 +1514,9 @@
             mEventHandler.sendMessage( mEventHandler.obtainMessage(
                     MSG_PERSIST_MEDIABUTTONRECEIVER, 0, 0, target/*obj*/) );
         }
+
+        // RC stack was modified
+        return true;
     }
 
     /**
@@ -1856,9 +1860,10 @@
 
         synchronized(mAudioFocusLock) {
             synchronized(mRCStack) {
-                pushMediaButtonReceiver_syncAfRcs(mediaIntent, eventReceiver, token);
-                // new RC client, assume every type of information shall be queried
-                checkUpdateRemoteControlDisplay_syncAfRcs(RC_INFO_ALL);
+                if (pushMediaButtonReceiver_syncAfRcs(mediaIntent, eventReceiver, token)) {
+                    // new RC client, assume every type of information shall be queried
+                    checkUpdateRemoteControlDisplay_syncAfRcs(RC_INFO_ALL);
+                }
             }
         }
     }
@@ -1925,6 +1930,7 @@
         int rccId = RemoteControlClient.RCSE_ID_UNREGISTERED;
         synchronized(mAudioFocusLock) {
             synchronized(mRCStack) {
+                boolean wasCurrentRcController = isCurrentRcController(mediaIntent);
                 // store the new display information
                 try {
                     for (int index = mRCStack.size()-1; index >= 0; index--) {
@@ -1971,9 +1977,9 @@
                     Log.e(TAG, "Wrong index accessing RC stack, lock error? ", e);
                 }
 
-                // if the eventReceiver is at the top of the stack
+                // if the eventReceiver is now at the top of the stack but wasn't before
                 // then check for potential refresh of the remote controls
-                if (isCurrentRcController(mediaIntent)) {
+                if (isCurrentRcController(mediaIntent) && !wasCurrentRcController) {
                     checkUpdateRemoteControlDisplay_syncAfRcs(RC_INFO_ALL);
                 }
             }//synchronized(mRCStack)
diff --git a/media/java/android/media/audiofx/AudioEffect.java b/media/java/android/media/audiofx/AudioEffect.java
index 12f7bd9..1e1ef8c 100644
--- a/media/java/android/media/audiofx/AudioEffect.java
+++ b/media/java/android/media/audiofx/AudioEffect.java
@@ -120,8 +120,6 @@
             .fromString("58b4b260-8e06-11e0-aa8e-0002a5d5c51b");
 
     /**
-     * @hide
-     * CANDIDATE FOR PUBLIC API
      * UUID for Loudness Enhancer
      */
     public static final UUID EFFECT_TYPE_LOUDNESS_ENHANCER = UUID
diff --git a/media/java/android/media/audiofx/LoudnessEnhancer.java b/media/java/android/media/audiofx/LoudnessEnhancer.java
index eb2fb75..7dc4175 100644
--- a/media/java/android/media/audiofx/LoudnessEnhancer.java
+++ b/media/java/android/media/audiofx/LoudnessEnhancer.java
@@ -65,7 +65,6 @@
     private final Object mParamListenerLock = new Object();
 
     /**
-     * @hide
      * Class constructor.
      * @param audioSession system-wide unique audio session identifier. The LoudnessEnhancer
      * will be attached to the MediaPlayer or AudioTrack in the same audio session.
diff --git a/packages/DocumentsUI/AndroidManifest.xml b/packages/DocumentsUI/AndroidManifest.xml
index 6faf7f8..179bcd1 100644
--- a/packages/DocumentsUI/AndroidManifest.xml
+++ b/packages/DocumentsUI/AndroidManifest.xml
@@ -50,6 +50,14 @@
             android:authorities="com.android.documentsui.recents"
             android:exported="false" />
 
+        <receiver android:name=".PackageReceiver">
+            <intent-filter>
+                <action android:name="android.intent.action.PACKAGE_FULLY_REMOVED" />
+                <action android:name="android.intent.action.PACKAGE_DATA_CLEARED" />
+                <data android:scheme="package" />
+            </intent-filter>
+        </receiver>
+
         <!-- TODO: remove when we have real clients -->
         <activity android:name=".TestActivity" android:enabled="false">
             <intent-filter>
diff --git a/packages/DocumentsUI/res/layout/fragment_save.xml b/packages/DocumentsUI/res/layout/fragment_save.xml
index 891f0a0..d601194 100644
--- a/packages/DocumentsUI/res/layout/fragment_save.xml
+++ b/packages/DocumentsUI/res/layout/fragment_save.xml
@@ -51,15 +51,31 @@
             android:singleLine="true"
             android:selectAllOnFocus="true" />
 
-        <Button
-            android:id="@android:id/button1"
+        <FrameLayout
             android:layout_width="wrap_content"
-            android:layout_height="match_parent"
-            android:background="?android:attr/selectableItemBackground"
-            android:text="@string/menu_save"
-            android:textAllCaps="true"
-            android:textAppearance="?android:attr/textAppearanceSmall"
-            android:padding="8dp" />
+            android:layout_height="match_parent">
+
+            <Button
+                android:id="@android:id/button1"
+                android:layout_width="wrap_content"
+                android:layout_height="match_parent"
+                android:background="?android:attr/selectableItemBackground"
+                android:text="@string/menu_save"
+                android:textAllCaps="true"
+                android:textAppearance="?android:attr/textAppearanceSmall"
+                android:padding="8dp" />
+
+            <ProgressBar
+                android:id="@android:id/progress"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_gravity="center"
+                android:visibility="gone"
+                android:indeterminate="true"
+                android:padding="8dp"
+                style="?android:attr/progressBarStyle" />
+
+        </FrameLayout>
 
     </LinearLayout>
 
diff --git a/packages/DocumentsUI/src/com/android/documentsui/CreateDirectoryFragment.java b/packages/DocumentsUI/src/com/android/documentsui/CreateDirectoryFragment.java
index 90be197..ba8c35f 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/CreateDirectoryFragment.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/CreateDirectoryFragment.java
@@ -95,6 +95,11 @@
         }
 
         @Override
+        protected void onPreExecute() {
+            mActivity.setPending(true);
+        }
+
+        @Override
         protected DocumentInfo doInBackground(Void... params) {
             final ContentResolver resolver = mActivity.getContentResolver();
             ContentProviderClient client = null;
@@ -120,6 +125,8 @@
             } else {
                 Toast.makeText(mActivity, R.string.create_error, Toast.LENGTH_SHORT).show();
             }
+
+            mActivity.setPending(false);
         }
     }
 }
diff --git a/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java b/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java
index d675e8d..4212e96 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java
@@ -255,7 +255,9 @@
         }
 
         mState.localOnly = intent.getBooleanExtra(Intent.EXTRA_LOCAL_ONLY, false);
-        mState.showAdvanced = SettingsActivity.getDisplayAdvancedDevices(this);
+        mState.forceAdvanced = intent.getBooleanExtra(DocumentsContract.EXTRA_SHOW_ADVANCED, false);
+        mState.showAdvanced = mState.forceAdvanced
+                | SettingsActivity.getDisplayAdvancedDevices(this);
     }
 
     private class RestoreRootTask extends AsyncTask<Void, Void, RootInfo> {
@@ -661,6 +663,13 @@
         DirectoryFragment.get(getFragmentManager()).onUserModeChanged();
     }
 
+    public void setPending(boolean pending) {
+        final SaveFragment save = SaveFragment.get(getFragmentManager());
+        if (save != null) {
+            save.setPending(pending);
+        }
+    }
+
     @Override
     public void onBackPressed() {
         if (!mState.stackTouched) {
@@ -1051,6 +1060,11 @@
         }
 
         @Override
+        protected void onPreExecute() {
+            setPending(true);
+        }
+
+        @Override
         protected Uri doInBackground(Void... params) {
             final ContentResolver resolver = getContentResolver();
             final DocumentInfo cwd = getCurrentDirectory();
@@ -1083,6 +1097,8 @@
                 Toast.makeText(DocumentsActivity.this, R.string.save_error, Toast.LENGTH_SHORT)
                         .show();
             }
+
+            setPending(false);
         }
     }
 
@@ -1122,6 +1138,7 @@
         public boolean allowMultiple = false;
         public boolean showSize = false;
         public boolean localOnly = false;
+        public boolean forceAdvanced = false;
         public boolean showAdvanced = false;
         public boolean stackTouched = false;
         public boolean restored = false;
@@ -1162,6 +1179,7 @@
             out.writeInt(allowMultiple ? 1 : 0);
             out.writeInt(showSize ? 1 : 0);
             out.writeInt(localOnly ? 1 : 0);
+            out.writeInt(forceAdvanced ? 1 : 0);
             out.writeInt(showAdvanced ? 1 : 0);
             out.writeInt(stackTouched ? 1 : 0);
             out.writeInt(restored ? 1 : 0);
@@ -1181,6 +1199,7 @@
                 state.allowMultiple = in.readInt() != 0;
                 state.showSize = in.readInt() != 0;
                 state.localOnly = in.readInt() != 0;
+                state.forceAdvanced = in.readInt() != 0;
                 state.showAdvanced = in.readInt() != 0;
                 state.stackTouched = in.readInt() != 0;
                 state.restored = in.readInt() != 0;
diff --git a/packages/DocumentsUI/src/com/android/documentsui/PackageReceiver.java b/packages/DocumentsUI/src/com/android/documentsui/PackageReceiver.java
new file mode 100644
index 0000000..aef63af
--- /dev/null
+++ b/packages/DocumentsUI/src/com/android/documentsui/PackageReceiver.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.documentsui;
+
+import android.content.BroadcastReceiver;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.Intent;
+import android.net.Uri;
+
+/**
+ * Clean up {@link RecentsProvider} when packages are removed.
+ */
+public class PackageReceiver extends BroadcastReceiver {
+    @Override
+    public void onReceive(Context context, Intent intent) {
+        final ContentResolver resolver = context.getContentResolver();
+
+        final String action = intent.getAction();
+        if (Intent.ACTION_PACKAGE_FULLY_REMOVED.equals(action)) {
+            resolver.call(RecentsProvider.buildRecent(), RecentsProvider.METHOD_PURGE, null, null);
+
+        } else if (Intent.ACTION_PACKAGE_DATA_CLEARED.equals(action)) {
+            final Uri data = intent.getData();
+            if (data != null) {
+                final String packageName = data.getSchemeSpecificPart();
+                resolver.call(RecentsProvider.buildRecent(), RecentsProvider.METHOD_PURGE_PACKAGE,
+                        packageName, null);
+            }
+        }
+    }
+}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/RecentsProvider.java b/packages/DocumentsUI/src/com/android/documentsui/RecentsProvider.java
index 4313fa7..f6e4349 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/RecentsProvider.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/RecentsProvider.java
@@ -16,24 +16,40 @@
 
 package com.android.documentsui;
 
+import static com.android.documentsui.model.DocumentInfo.getCursorString;
+
 import android.content.ContentProvider;
 import android.content.ContentResolver;
 import android.content.ContentValues;
 import android.content.Context;
+import android.content.Intent;
 import android.content.UriMatcher;
+import android.content.pm.ResolveInfo;
 import android.database.Cursor;
 import android.database.sqlite.SQLiteDatabase;
 import android.database.sqlite.SQLiteOpenHelper;
 import android.net.Uri;
+import android.os.Bundle;
+import android.provider.DocumentsContract;
 import android.provider.DocumentsContract.Document;
 import android.provider.DocumentsContract.Root;
 import android.text.format.DateUtils;
 import android.util.Log;
 
+import com.android.documentsui.model.DocumentStack;
+import com.android.documentsui.model.DurableUtils;
+import com.android.internal.util.Predicate;
+import com.google.android.collect.Sets;
+
+import libcore.io.IoUtils;
+
+import java.io.IOException;
+import java.util.Set;
+
 public class RecentsProvider extends ContentProvider {
     private static final String TAG = "RecentsProvider";
 
-    public static final long MAX_HISTORY_IN_MILLIS = 45 * DateUtils.DAY_IN_MILLIS;
+    private static final long MAX_HISTORY_IN_MILLIS = 45 * DateUtils.DAY_IN_MILLIS;
 
     private static final String AUTHORITY = "com.android.documentsui.recents";
 
@@ -43,6 +59,9 @@
     private static final int URI_STATE = 2;
     private static final int URI_RESUME = 3;
 
+    public static final String METHOD_PURGE = "purge";
+    public static final String METHOD_PURGE_PACKAGE = "purgePackage";
+
     static {
         sMatcher.addURI(AUTHORITY, "recent", URI_RECENT);
         // state/authority/rootId/docId
@@ -231,4 +250,116 @@
     public int delete(Uri uri, String selection, String[] selectionArgs) {
         throw new UnsupportedOperationException("Unsupported Uri " + uri);
     }
+
+    @Override
+    public Bundle call(String method, String arg, Bundle extras) {
+        if (METHOD_PURGE.equals(method)) {
+            // Purge references to unknown authorities
+            final Intent intent = new Intent(DocumentsContract.PROVIDER_INTERFACE);
+            final Set<String> knownAuth = Sets.newHashSet();
+            for (ResolveInfo info : getContext()
+                    .getPackageManager().queryIntentContentProviders(intent, 0)) {
+                knownAuth.add(info.providerInfo.authority);
+            }
+
+            purgeByAuthority(new Predicate<String>() {
+                @Override
+                public boolean apply(String authority) {
+                    // Purge unknown authorities
+                    return !knownAuth.contains(authority);
+                }
+            });
+
+            return null;
+
+        } else if (METHOD_PURGE_PACKAGE.equals(method)) {
+            // Purge references to authorities in given package
+            final Intent intent = new Intent(DocumentsContract.PROVIDER_INTERFACE);
+            intent.setPackage(arg);
+            final Set<String> packageAuth = Sets.newHashSet();
+            for (ResolveInfo info : getContext()
+                    .getPackageManager().queryIntentContentProviders(intent, 0)) {
+                packageAuth.add(info.providerInfo.authority);
+            }
+
+            if (!packageAuth.isEmpty()) {
+                purgeByAuthority(new Predicate<String>() {
+                    @Override
+                    public boolean apply(String authority) {
+                        // Purge authority matches
+                        return packageAuth.contains(authority);
+                    }
+                });
+            }
+
+            return null;
+
+        } else {
+            return super.call(method, arg, extras);
+        }
+    }
+
+    /**
+     * Purge all internal data whose authority matches the given
+     * {@link Predicate}.
+     */
+    private void purgeByAuthority(Predicate<String> predicate) {
+        final SQLiteDatabase db = mHelper.getWritableDatabase();
+        final DocumentStack stack = new DocumentStack();
+
+        Cursor cursor = db.query(TABLE_RECENT, null, null, null, null, null, null);
+        try {
+            while (cursor.moveToNext()) {
+                try {
+                    final byte[] rawStack = cursor.getBlob(
+                            cursor.getColumnIndex(RecentColumns.STACK));
+                    DurableUtils.readFromArray(rawStack, stack);
+
+                    if (stack.root != null && predicate.apply(stack.root.authority)) {
+                        final String key = getCursorString(cursor, RecentColumns.KEY);
+                        db.delete(TABLE_RECENT, RecentColumns.KEY + "=?", new String[] { key });
+                    }
+                } catch (IOException ignored) {
+                }
+            }
+        } finally {
+            IoUtils.closeQuietly(cursor);
+        }
+
+        cursor = db.query(TABLE_STATE, new String[] {
+                StateColumns.AUTHORITY }, null, null, StateColumns.AUTHORITY, null, null);
+        try {
+            while (cursor.moveToNext()) {
+                final String authority = getCursorString(cursor, StateColumns.AUTHORITY);
+                if (predicate.apply(authority)) {
+                    db.delete(TABLE_STATE, StateColumns.AUTHORITY + "=?", new String[] {
+                            authority });
+                    Log.d(TAG, "Purged state for " + authority);
+                }
+            }
+        } finally {
+            IoUtils.closeQuietly(cursor);
+        }
+
+        cursor = db.query(TABLE_RESUME, null, null, null, null, null, null);
+        try {
+            while (cursor.moveToNext()) {
+                try {
+                    final byte[] rawStack = cursor.getBlob(
+                            cursor.getColumnIndex(ResumeColumns.STACK));
+                    DurableUtils.readFromArray(rawStack, stack);
+
+                    if (stack.root != null && predicate.apply(stack.root.authority)) {
+                        final String packageName = getCursorString(
+                                cursor, ResumeColumns.PACKAGE_NAME);
+                        db.delete(TABLE_RESUME, ResumeColumns.PACKAGE_NAME + "=?",
+                                new String[] { packageName });
+                    }
+                } catch (IOException ignored) {
+                }
+            }
+        } finally {
+            IoUtils.closeQuietly(cursor);
+        }
+    }
 }
diff --git a/packages/DocumentsUI/src/com/android/documentsui/RootsFragment.java b/packages/DocumentsUI/src/com/android/documentsui/RootsFragment.java
index fdbc3ab..931dac9 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/RootsFragment.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/RootsFragment.java
@@ -16,6 +16,8 @@
 
 package com.android.documentsui;
 
+import static com.android.documentsui.DocumentsActivity.State.ACTION_GET_CONTENT;
+
 import android.app.Fragment;
 import android.app.FragmentManager;
 import android.app.FragmentTransaction;
@@ -25,7 +27,9 @@
 import android.content.Loader;
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
+import android.net.Uri;
 import android.os.Bundle;
+import android.provider.Settings;
 import android.text.TextUtils;
 import android.text.format.Formatter;
 import android.view.LayoutInflater;
@@ -33,6 +37,7 @@
 import android.view.ViewGroup;
 import android.widget.AdapterView;
 import android.widget.AdapterView.OnItemClickListener;
+import android.widget.AdapterView.OnItemLongClickListener;
 import android.widget.ArrayAdapter;
 import android.widget.ImageView;
 import android.widget.ListView;
@@ -131,7 +136,15 @@
 
         final Context context = getActivity();
         final State state = ((DocumentsActivity) context).getDisplayState();
-        state.showAdvanced = SettingsActivity.getDisplayAdvancedDevices(context);
+        state.showAdvanced = state.forceAdvanced
+                | SettingsActivity.getDisplayAdvancedDevices(context);
+
+        if (state.action == ACTION_GET_CONTENT) {
+            mList.setOnItemLongClickListener(mItemLongClickListener);
+        } else {
+            mList.setOnItemLongClickListener(null);
+            mList.setLongClickable(false);
+        }
 
         getLoaderManager().restartLoader(2, null, mCallbacks);
     }
@@ -152,6 +165,13 @@
         }
     }
 
+    private void showAppDetails(ResolveInfo ri) {
+        final Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
+        intent.setData(Uri.fromParts("package", ri.activityInfo.packageName, null));
+        intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
+        startActivity(intent);
+    }
+
     private OnItemClickListener mItemListener = new OnItemClickListener() {
         @Override
         public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
@@ -167,6 +187,19 @@
         }
     };
 
+    private OnItemLongClickListener mItemLongClickListener = new OnItemLongClickListener() {
+        @Override
+        public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {
+            final Item item = mAdapter.getItem(position);
+            if (item instanceof AppItem) {
+                showAppDetails(((AppItem) item).info);
+                return true;
+            } else {
+                return false;
+            }
+        }
+    };
+
     private static abstract class Item {
         private final int mLayoutId;
 
diff --git a/packages/DocumentsUI/src/com/android/documentsui/SaveFragment.java b/packages/DocumentsUI/src/com/android/documentsui/SaveFragment.java
index 23e047c..9d70c51 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/SaveFragment.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/SaveFragment.java
@@ -30,6 +30,7 @@
 import android.widget.Button;
 import android.widget.EditText;
 import android.widget.ImageView;
+import android.widget.ProgressBar;
 
 import com.android.documentsui.model.DocumentInfo;
 
@@ -42,6 +43,7 @@
     private DocumentInfo mReplaceTarget;
     private EditText mDisplayName;
     private Button mSave;
+    private ProgressBar mProgress;
     private boolean mIgnoreNextEdit;
 
     private static final String EXTRA_MIME_TYPE = "mime_type";
@@ -83,6 +85,8 @@
         mSave.setOnClickListener(mSaveListener);
         mSave.setEnabled(false);
 
+        mProgress = (ProgressBar) view.findViewById(android.R.id.progress);
+
         return view;
     }
 
@@ -92,7 +96,6 @@
             if (mIgnoreNextEdit) {
                 mIgnoreNextEdit = false;
             } else {
-                Log.d(TAG, "onTextChanged!");
                 mReplaceTarget = null;
             }
         }
@@ -140,4 +143,9 @@
     public void setSaveEnabled(boolean enabled) {
         mSave.setEnabled(enabled);
     }
+
+    public void setPending(boolean pending) {
+        mSave.setVisibility(pending ? View.INVISIBLE : View.VISIBLE);
+        mProgress.setVisibility(pending ? View.VISIBLE : View.GONE);
+    }
 }
diff --git a/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java b/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java
index d42354f..65e3eee 100644
--- a/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java
+++ b/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java
@@ -394,7 +394,7 @@
     private static String getTypeForName(String name) {
         final int lastDot = name.lastIndexOf('.');
         if (lastDot >= 0) {
-            final String extension = name.substring(lastDot + 1);
+            final String extension = name.substring(lastDot + 1).toLowerCase();
             final String mime = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension);
             if (mime != null) {
                 return mime;
@@ -411,7 +411,7 @@
     private static String removeExtension(String mimeType, String name) {
         final int lastDot = name.lastIndexOf('.');
         if (lastDot >= 0) {
-            final String extension = name.substring(lastDot + 1);
+            final String extension = name.substring(lastDot + 1).toLowerCase();
             final String nameMime = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension);
             if (mimeType.equals(nameMime)) {
                 return name.substring(0, lastDot);
diff --git a/packages/ExternalStorageProvider/src/com/android/externalstorage/TestDocumentsProvider.java b/packages/ExternalStorageProvider/src/com/android/externalstorage/TestDocumentsProvider.java
index 71ce4dd..af6ff01 100644
--- a/packages/ExternalStorageProvider/src/com/android/externalstorage/TestDocumentsProvider.java
+++ b/packages/ExternalStorageProvider/src/com/android/externalstorage/TestDocumentsProvider.java
@@ -127,7 +127,7 @@
         final MatrixCursor result = new MatrixCursor(resolveRootProjection(projection));
         final RowBuilder row = result.newRow();
         row.add(Root.COLUMN_ROOT_ID, MY_ROOT_ID);
-        row.add(Root.COLUMN_FLAGS, Root.FLAG_SUPPORTS_RECENTS);
+        row.add(Root.COLUMN_FLAGS, Root.FLAG_SUPPORTS_RECENTS | Root.FLAG_SUPPORTS_CREATE);
         row.add(Root.COLUMN_TITLE, "_Test title which is really long");
         row.add(Root.COLUMN_SUMMARY,
                 SystemClock.elapsedRealtime() + " summary which is also super long text");
@@ -147,6 +147,14 @@
         return result;
     }
 
+    @Override
+    public String createDocument(String parentDocumentId, String mimeType, String displayName)
+            throws FileNotFoundException {
+        if (LAG) lagUntilCanceled(null);
+
+        return super.createDocument(parentDocumentId, mimeType, displayName);
+    }
+
     /**
      * Holds any outstanding or finished "network" fetching.
      */
@@ -386,6 +394,7 @@
 
         if (MY_DOC_ID.equals(docId)) {
             row.add(Document.COLUMN_MIME_TYPE, Document.MIME_TYPE_DIR);
+            row.add(Document.COLUMN_FLAGS, Document.FLAG_DIR_SUPPORTS_CREATE);
         } else if (MY_DOC_NULL.equals(docId)) {
             // No MIME type
         } else {
diff --git a/packages/Keyguard/res/drawable-hdpi/ic_lockscreen_forgotpassword_normal.png b/packages/Keyguard/res/drawable-hdpi/ic_lockscreen_forgotpassword_normal.png
deleted file mode 100644
index 6402d3d..0000000
--- a/packages/Keyguard/res/drawable-hdpi/ic_lockscreen_forgotpassword_normal.png
+++ /dev/null
Binary files differ
diff --git a/packages/Keyguard/res/drawable-hdpi/ic_lockscreen_forgotpassword_pressed.png b/packages/Keyguard/res/drawable-hdpi/ic_lockscreen_forgotpassword_pressed.png
deleted file mode 100644
index 83be046..0000000
--- a/packages/Keyguard/res/drawable-hdpi/ic_lockscreen_forgotpassword_pressed.png
+++ /dev/null
Binary files differ
diff --git a/packages/Keyguard/res/drawable-mdpi/ic_lockscreen_forgotpassword_normal.png b/packages/Keyguard/res/drawable-mdpi/ic_lockscreen_forgotpassword_normal.png
deleted file mode 100644
index a7e063a..0000000
--- a/packages/Keyguard/res/drawable-mdpi/ic_lockscreen_forgotpassword_normal.png
+++ /dev/null
Binary files differ
diff --git a/packages/Keyguard/res/drawable-mdpi/ic_lockscreen_forgotpassword_pressed.png b/packages/Keyguard/res/drawable-mdpi/ic_lockscreen_forgotpassword_pressed.png
deleted file mode 100644
index 53af5a5..0000000
--- a/packages/Keyguard/res/drawable-mdpi/ic_lockscreen_forgotpassword_pressed.png
+++ /dev/null
Binary files differ
diff --git a/packages/Keyguard/res/drawable-xhdpi/ic_lockscreen_forgotpassword_normal.png b/packages/Keyguard/res/drawable-xhdpi/ic_lockscreen_forgotpassword_normal.png
deleted file mode 100644
index e4172ce..0000000
--- a/packages/Keyguard/res/drawable-xhdpi/ic_lockscreen_forgotpassword_normal.png
+++ /dev/null
Binary files differ
diff --git a/packages/Keyguard/res/drawable-xhdpi/ic_lockscreen_forgotpassword_pressed.png b/packages/Keyguard/res/drawable-xhdpi/ic_lockscreen_forgotpassword_pressed.png
deleted file mode 100644
index e2c76217..0000000
--- a/packages/Keyguard/res/drawable-xhdpi/ic_lockscreen_forgotpassword_pressed.png
+++ /dev/null
Binary files differ
diff --git a/packages/Keyguard/res/drawable/lockscreen_forgot_password_button.xml b/packages/Keyguard/res/drawable/lockscreen_forgot_password_button.xml
deleted file mode 100644
index 6c081bf..0000000
--- a/packages/Keyguard/res/drawable/lockscreen_forgot_password_button.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2008 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.
--->
-
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:state_enabled="true" android:drawable="@drawable/ic_lockscreen_forgotpassword_normal" />
-    <item android:state_pressed="true" android:drawable="@drawable/ic_lockscreen_forgotpassword_pressed" />
-    <item android:drawable="@drawable/ic_lockscreen_forgotpassword_normal" />
-</selector>
diff --git a/packages/Keyguard/res/layout/keyguard_emergency_carrier_area.xml b/packages/Keyguard/res/layout/keyguard_emergency_carrier_area.xml
index 313fe9f..8be15cb 100644
--- a/packages/Keyguard/res/layout/keyguard_emergency_carrier_area.xml
+++ b/packages/Keyguard/res/layout/keyguard_emergency_carrier_area.xml
@@ -42,7 +42,7 @@
     <LinearLayout
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
-        android:layout_marginTop="-10dip"
+        android:layout_marginTop="@dimen/eca_overlap"
         style="?android:attr/buttonBarStyle"
         android:orientation="horizontal"
         android:gravity="center"
@@ -66,12 +66,10 @@
             android:layout_width="0dip"
             android:layout_height="wrap_content"
             android:layout_weight="1"
-            android:drawableLeft="@drawable/lockscreen_forgot_password_button"
             style="?android:attr/buttonBarButtonStyle"
             android:textSize="@dimen/kg_status_line_font_size"
             android:textColor="?android:attr/textColorSecondary"
             android:textAppearance="?android:attr/textAppearanceMedium"
-            android:drawablePadding="8dip"
             android:visibility="gone"
             android:textAllCaps="@bool/kg_use_all_caps" />
     </LinearLayout>
diff --git a/packages/Keyguard/res/values-sw600dp/dimens.xml b/packages/Keyguard/res/values-sw600dp/dimens.xml
index f8a1362..ea5ef27 100644
--- a/packages/Keyguard/res/values-sw600dp/dimens.xml
+++ b/packages/Keyguard/res/values-sw600dp/dimens.xml
@@ -66,4 +66,7 @@
     <dimen name="widget_label_font_size">16dp</dimen>
     <dimen name="widget_big_font_size">141dp</dimen>
 
+    <!-- EmergencyCarrierArea overlap - amount to overlap the emergency button and carrier text.
+         Should be 0 on devices with plenty of room (e.g. tablets) -->
+    <dimen name="eca_overlap">0dip</dimen>
 </resources>
diff --git a/packages/Keyguard/res/values/dimens.xml b/packages/Keyguard/res/values/dimens.xml
index a1ad120..71e9924 100644
--- a/packages/Keyguard/res/values/dimens.xml
+++ b/packages/Keyguard/res/values/dimens.xml
@@ -150,6 +150,10 @@
     security mode. -->
     <dimen name="kg_small_widget_height">160dp</dimen>
 
+    <!-- EmergencyCarrierArea overlap - amount to overlap the emergency button and carrier text.
+         Should be 0 on devices with plenty of room (e.g. tablets) -->
+    <dimen name="eca_overlap">-10dip</dimen>
+
     <!-- Default clock parameters -->
     <dimen name="bottom_text_spacing_digital">-8dp</dimen>
     <dimen name="label_font_size">14dp</dimen>
diff --git a/packages/Keyguard/res/values/strings.xml b/packages/Keyguard/res/values/strings.xml
index abc4483..4738049 100644
--- a/packages/Keyguard/res/values/strings.xml
+++ b/packages/Keyguard/res/values/strings.xml
@@ -24,12 +24,12 @@
 
     <!-- Instructions telling the user to enter their SIM PUK to unlock the keyguard.
          Displayed in one line in a large font.  -->
-    <string name="keyguard_password_enter_puk_code">Type PUK and new PIN code</string>
+    <string name="keyguard_password_enter_puk_code">Type SIM PUK and new PIN code</string>
 
     <!-- Prompt to enter SIM PUK in Edit Text Box in unlock screen -->
-    <string name="keyguard_password_enter_puk_prompt">PUK code</string>
+    <string name="keyguard_password_enter_puk_prompt">SIM PUK code</string>
     <!-- Prompt to enter New SIM PIN in Edit Text Box in unlock screen -->
-    <string name="keyguard_password_enter_pin_prompt">New PIN code</string>
+    <string name="keyguard_password_enter_pin_prompt">New SIM PIN code</string>
 
     <!-- Displayed as hint in passwordEntry EditText on PasswordUnlockScreen [CHAR LIMIT=30]-->
     <string name="keyguard_password_entry_touch_hint"><font size="17">Touch to type password</font></string>
@@ -249,8 +249,6 @@
     <string name="kg_enter_confirm_pin_hint">Confirm desired PIN code</string>
     <!-- Message shown in dialog while the device is unlocking the SIM card -->
     <string name="kg_sim_unlock_progress_dialog_message">Unlocking SIM card\u2026</string>
-    <!-- Message shown when the user enters the wrong PIN code -->
-    <string name="kg_password_wrong_pin_code">Incorrect PIN code.</string>
     <!-- Message shown when the user enters an invalid SIM pin password in PUK screen -->
     <string name="kg_invalid_sim_pin_hint">Type a PIN that is 4 to 8 numbers.</string>
     <!-- Message shown when the user enters an invalid PUK code in the PUK screen -->
@@ -333,6 +331,34 @@
     <!-- The delete-widget drop target button text -->
     <string name="kg_reordering_delete_drop_target_text">Remove</string>
 
+    <!-- Instructions telling the user that they entered the wrong SIM PIN for the last time.
+         Displayed in a dialog box.  -->
+    <string name="kg_password_wrong_pin_code_pukked">Incorrect SIM PIN code you must now contact your carrier to unlock your device.</string>
+    <!-- Instructions telling the user that they entered the wrong SIM PIN while trying
+         to unlock the keyguard.  Displayed in a dialog box.  -->
+    <plurals name="kg_password_wrong_pin_code">
+        <item quantity="one">Incorrect SIM PIN code, you have <xliff:g id="number">%d</xliff:g> remaining attempt before you must contact your carrier to unlock your device.</item>
+        <item quantity="other">Incorrect SIM PIN code, you have <xliff:g id="number">%d</xliff:g> remaining attempts.</item>
+    </plurals>
+
+    <!-- Instructions telling the user that they have exhausted SIM PUK retries and the SIM is now unusable.
+         Displayed in a dialog box.  -->
+    <string name="kg_password_wrong_puk_code_dead">SIM is unusable. Contact your carrier.</string>
+    <!-- Instructions telling the user that they entered the wrong puk while trying
+         to unlock the keyguard.  Displayed in a dialog box.  -->
+    <plurals name="kg_password_wrong_puk_code">
+        <item quantity="one">Incorrect SIM PUK code, you have <xliff:g id="number">%d</xliff:g> remaining attempt before SIM becomes permanently unusable.</item>
+        <item quantity="other">Incorrect SIM PUK code, you have <xliff:g id="number">%d</xliff:g> remaining attempts before SIM becomes permanently unusable.</item>
+    </plurals>
+    <!-- Instructions telling the user that the operation to unlock the keyguard
+         with SIM PIN failed. Displayed in one line in a large font.  -->
+    <string name="kg_password_pin_failed">SIM PIN operation failed!</string>
+    <!-- Instructions telling the user that the operation to unlock the keyguard
+         with PUK failed. Displayed in one line in a large font.  -->
+    <string name="kg_password_puk_failed">SIM PUK operation failed!</string>
+    <!-- Notification telling the user that the PIN1 they entered is valid -->
+    <string name="kg_pin_accepted">Code Accepted!</string>
+
     <!-- Transport control strings -->
     <!-- Shown on transport control of lockscreen. Pressing button goes to previous track. -->
     <string name="keyguard_transport_prev_description">Previous track button</string>
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardSimPinView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardSimPinView.java
index 5059407..e39622a 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardSimPinView.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardSimPinView.java
@@ -17,11 +17,16 @@
 package com.android.keyguard;
 
 import com.android.internal.telephony.ITelephony;
+import com.android.internal.telephony.PhoneConstants;
 
 import android.content.Context;
+import android.content.DialogInterface;
 import android.app.Activity;
+import android.app.AlertDialog;
+import android.app.AlertDialog.Builder;
 import android.app.Dialog;
 import android.app.ProgressDialog;
+import android.os.Message;
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.text.Editable;
@@ -30,6 +35,7 @@
 import android.text.method.DigitsKeyListener;
 import android.util.AttributeSet;
 import android.view.View;
+import android.util.Log;
 import android.view.WindowManager;
 import android.widget.TextView.OnEditorActionListener;
 
@@ -38,10 +44,14 @@
  */
 public class KeyguardSimPinView extends KeyguardAbsKeyInputView
         implements KeyguardSecurityView, OnEditorActionListener, TextWatcher {
+    private static final String LOG_TAG = "KeyguardSimPinView";
+    private static final boolean DEBUG = KeyguardViewMediator.DEBUG;
 
     private ProgressDialog mSimUnlockProgressDialog = null;
     private volatile boolean mSimCheckInProgress;
 
+    private AlertDialog mRemainingAttemptsDialog;
+
     public KeyguardSimPinView(Context context) {
         this(context, null);
     }
@@ -55,6 +65,23 @@
         mPasswordEntry.setEnabled(true);
     }
 
+    private String getPinPasswordErrorMessage(int attemptsRemaining) {
+        String displayMessage;
+
+        if (attemptsRemaining == 0) {
+            displayMessage = getContext().getString(R.string.kg_password_wrong_pin_code_pukked);
+        } else if (attemptsRemaining > 0) {
+            displayMessage = getContext().getResources()
+                    .getQuantityString(R.plurals.kg_password_wrong_pin_code, attemptsRemaining,
+                            attemptsRemaining);
+        } else {
+            displayMessage = getContext().getString(R.string.kg_password_pin_failed);
+        }
+        if (DEBUG) Log.d(LOG_TAG, "getPinPasswordErrorMessage:"
+                + " attemptsRemaining=" + attemptsRemaining + " displayMessage=" + displayMessage);
+        return displayMessage;
+    }
+
     @Override
     protected boolean shouldLockout(long deadline) {
         // SIM PIN doesn't have a timed lockout
@@ -109,6 +136,8 @@
                 | InputType.TYPE_NUMBER_VARIATION_PASSWORD);
 
         mPasswordEntry.requestFocus();
+
+        mSecurityMessageDisplay.setTimeout(0); // don't show ownerinfo/charging status by default
     }
 
     @Override
@@ -135,22 +164,22 @@
             mPin = pin;
         }
 
-        abstract void onSimCheckResponse(boolean success);
+        abstract void onSimCheckResponse(final int result, final int attemptsRemaining);
 
         @Override
         public void run() {
             try {
-                final boolean result = ITelephony.Stub.asInterface(ServiceManager
-                        .checkService("phone")).supplyPin(mPin);
+                final int[] result = ITelephony.Stub.asInterface(ServiceManager
+                        .checkService("phone")).supplyPinReportResult(mPin);
                 post(new Runnable() {
                     public void run() {
-                        onSimCheckResponse(result);
+                        onSimCheckResponse(result[0], result[1]);
                     }
                 });
             } catch (RemoteException e) {
                 post(new Runnable() {
                     public void run() {
-                        onSimCheckResponse(false);
+                        onSimCheckResponse(PhoneConstants.PIN_GENERAL_FAILURE, -1);
                     }
                 });
             }
@@ -164,14 +193,28 @@
                     mContext.getString(R.string.kg_sim_unlock_progress_dialog_message));
             mSimUnlockProgressDialog.setIndeterminate(true);
             mSimUnlockProgressDialog.setCancelable(false);
-            if (!(mContext instanceof Activity)) {
-                mSimUnlockProgressDialog.getWindow().setType(
-                        WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
-            }
+            mSimUnlockProgressDialog.getWindow().setType(
+                    WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
         }
         return mSimUnlockProgressDialog;
     }
 
+    private Dialog getSimRemainingAttemptsDialog(int remaining) {
+        String msg = getPinPasswordErrorMessage(remaining);
+        if (mRemainingAttemptsDialog == null) {
+            Builder builder = new AlertDialog.Builder(mContext);
+            builder.setMessage(msg);
+            builder.setCancelable(false);
+            builder.setNeutralButton(R.string.ok, null);
+            mRemainingAttemptsDialog = builder.create();
+            mRemainingAttemptsDialog.getWindow().setType(
+                    WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
+        } else {
+            mRemainingAttemptsDialog.setMessage(msg);
+        }
+        return mRemainingAttemptsDialog;
+    }
+
     @Override
     protected void verifyPasswordAndUnlock() {
         String entry = mPasswordEntry.getText().toString();
@@ -189,20 +232,34 @@
         if (!mSimCheckInProgress) {
             mSimCheckInProgress = true; // there should be only one
             new CheckSimPin(mPasswordEntry.getText().toString()) {
-                void onSimCheckResponse(final boolean success) {
+                void onSimCheckResponse(final int result, final int attemptsRemaining) {
                     post(new Runnable() {
                         public void run() {
                             if (mSimUnlockProgressDialog != null) {
                                 mSimUnlockProgressDialog.hide();
                             }
-                            if (success) {
-                                // before closing the keyguard, report back that the sim is unlocked
-                                // so it knows right away.
+                            if (result == PhoneConstants.PIN_RESULT_SUCCESS) {
                                 KeyguardUpdateMonitor.getInstance(getContext()).reportSimUnlocked();
                                 mCallback.dismiss(true);
                             } else {
-                                mSecurityMessageDisplay.setMessage
-                                    (R.string.kg_password_wrong_pin_code, true);
+                                if (result == PhoneConstants.PIN_PASSWORD_INCORRECT) {
+                                    if (attemptsRemaining <= 2) {
+                                        // this is getting critical - show dialog
+                                        getSimRemainingAttemptsDialog(attemptsRemaining).show();
+                                    } else {
+                                        // show message
+                                        mSecurityMessageDisplay.setMessage(
+                                                getPinPasswordErrorMessage(attemptsRemaining), true);
+                                    }
+                                } else {
+                                    // "PIN operation failed!" - no idea what this was and no way to
+                                    // find out. :/
+                                    mSecurityMessageDisplay.setMessage(getContext().getString(
+                                            R.string.kg_password_pin_failed), true);
+                                }
+                                if (DEBUG) Log.d(LOG_TAG, "verifyPasswordAndUnlock "
+                                        + " CheckSimPin.onSimCheckResponse: " + result
+                                        + " attemptsRemaining=" + attemptsRemaining);
                                 mPasswordEntry.setText("");
                             }
                             mCallback.userActivity(0);
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardSimPukView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardSimPukView.java
index 2ae4cc7..31518a1 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardSimPukView.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardSimPukView.java
@@ -16,10 +16,10 @@
 
 package com.android.keyguard;
 
-import com.android.internal.telephony.ITelephony;
-
 import android.content.Context;
+import android.animation.AnimatorSet.Builder;
 import android.app.Activity;
+import android.app.AlertDialog;
 import android.app.Dialog;
 import android.app.ProgressDialog;
 import android.os.RemoteException;
@@ -29,21 +29,29 @@
 import android.text.TextWatcher;
 import android.text.method.DigitsKeyListener;
 import android.util.AttributeSet;
+import android.util.Log;
 import android.view.View;
 import android.view.WindowManager;
 import android.widget.TextView.OnEditorActionListener;
 
+import com.android.internal.telephony.ITelephony;
+import com.android.internal.telephony.PhoneConstants;
+
+
 /**
  * Displays a PIN pad for entering a PUK (Pin Unlock Kode) provided by a carrier.
  */
 public class KeyguardSimPukView extends KeyguardAbsKeyInputView
         implements KeyguardSecurityView, OnEditorActionListener, TextWatcher {
+    private static final String LOG_TAG = "KeyguardSimPukView";
+    private static final boolean DEBUG = KeyguardViewMediator.DEBUG;
 
     private ProgressDialog mSimUnlockProgressDialog = null;
     private volatile boolean mCheckInProgress;
     private String mPukText;
     private String mPinText;
     private StateMachine mStateMachine = new StateMachine();
+    private AlertDialog mRemainingAttemptsDialog;
 
     private class StateMachine {
         final int ENTER_PUK = 0;
@@ -93,6 +101,23 @@
         }
     }
 
+    private String getPukPasswordErrorMessage(int attemptsRemaining) {
+        String displayMessage;
+
+        if (attemptsRemaining == 0) {
+            displayMessage = getContext().getString(R.string.kg_password_wrong_puk_code_dead);
+        } else if (attemptsRemaining > 0) {
+            displayMessage = getContext().getResources()
+                    .getQuantityString(R.plurals.kg_password_wrong_puk_code, attemptsRemaining,
+                            attemptsRemaining);
+        } else {
+            displayMessage = getContext().getString(R.string.kg_password_puk_failed);
+        }
+        if (DEBUG) Log.d(LOG_TAG, "getPukPasswordErrorMessage:"
+                + " attemptsRemaining=" + attemptsRemaining + " displayMessage=" + displayMessage);
+        return displayMessage;
+    }
+
     public KeyguardSimPukView(Context context) {
         this(context, null);
     }
@@ -190,23 +215,23 @@
             mPin = pin;
         }
 
-        abstract void onSimLockChangedResponse(boolean success);
+        abstract void onSimLockChangedResponse(final int result, final int attemptsRemaining);
 
         @Override
         public void run() {
             try {
-                final boolean result = ITelephony.Stub.asInterface(ServiceManager
-                        .checkService("phone")).supplyPuk(mPuk, mPin);
+                final int[] result = ITelephony.Stub.asInterface(ServiceManager
+                        .checkService("phone")).supplyPukReportResult(mPuk, mPin);
 
                 post(new Runnable() {
                     public void run() {
-                        onSimLockChangedResponse(result);
+                        onSimLockChangedResponse(result[0], result[1]);
                     }
                 });
             } catch (RemoteException e) {
                 post(new Runnable() {
                     public void run() {
-                        onSimLockChangedResponse(false);
+                        onSimLockChangedResponse(PhoneConstants.PIN_GENERAL_FAILURE, -1);
                     }
                 });
             }
@@ -228,6 +253,22 @@
         return mSimUnlockProgressDialog;
     }
 
+    private Dialog getPukRemainingAttemptsDialog(int remaining) {
+        String msg = getPukPasswordErrorMessage(remaining);
+        if (mRemainingAttemptsDialog == null) {
+            AlertDialog.Builder builder = new AlertDialog.Builder(mContext);
+            builder.setMessage(msg);
+            builder.setCancelable(false);
+            builder.setNeutralButton(R.string.ok, null);
+            mRemainingAttemptsDialog = builder.create();
+            mRemainingAttemptsDialog.getWindow().setType(
+                    WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
+        } else {
+            mRemainingAttemptsDialog.setMessage(msg);
+        }
+        return mRemainingAttemptsDialog;
+    }
+
     private boolean checkPuk() {
         // make sure the puk is at least 8 digits long.
         if (mPasswordEntry.getText().length() >= 8) {
@@ -257,17 +298,33 @@
         if (!mCheckInProgress) {
             mCheckInProgress = true;
             new CheckSimPuk(mPukText, mPinText) {
-                void onSimLockChangedResponse(final boolean success) {
+                void onSimLockChangedResponse(final int result, final int attemptsRemaining) {
                     post(new Runnable() {
                         public void run() {
                             if (mSimUnlockProgressDialog != null) {
                                 mSimUnlockProgressDialog.hide();
                             }
-                            if (success) {
+                            if (result == PhoneConstants.PIN_RESULT_SUCCESS) {
+                                KeyguardUpdateMonitor.getInstance(getContext()).reportSimUnlocked();
                                 mCallback.dismiss(true);
                             } else {
+                                if (result == PhoneConstants.PIN_PASSWORD_INCORRECT) {
+                                    if (attemptsRemaining <= 2) {
+                                        // this is getting critical - show dialog
+                                        getPukRemainingAttemptsDialog(attemptsRemaining).show();
+                                    } else {
+                                        // show message
+                                        mSecurityMessageDisplay.setMessage(
+                                                getPukPasswordErrorMessage(attemptsRemaining), true);
+                                    }
+                                } else {
+                                    mSecurityMessageDisplay.setMessage(getContext().getString(
+                                            R.string.kg_password_puk_failed), true);
+                                }
+                                if (DEBUG) Log.d(LOG_TAG, "verifyPasswordAndUnlock "
+                                        + " UpdateSim.onSimCheckResponse: "
+                                        + " attemptsRemaining=" + attemptsRemaining);
                                 mStateMachine.reset();
-                                mSecurityMessageDisplay.setMessage(R.string.kg_invalid_puk, true);
                             }
                             mCheckInProgress = false;
                         }
diff --git a/packages/PrintSpooler/src/com/android/printspooler/PrintJobConfigActivity.java b/packages/PrintSpooler/src/com/android/printspooler/PrintJobConfigActivity.java
index 787b59a..db3770e 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/PrintJobConfigActivity.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/PrintJobConfigActivity.java
@@ -621,7 +621,7 @@
                         .getPrintJobInfo(mPrintJobId, PrintManager.APP_ID_ANY);
                 Intent intent = new Intent(Intent.ACTION_CREATE_DOCUMENT);
                 intent.setType("application/pdf");
-                intent.putExtra(Intent.EXTRA_TITLE, printJob.getLabel());
+                intent.putExtra(Intent.EXTRA_TITLE, mDocument.info.getName());
                 intent.putExtra(DocumentsContract.EXTRA_PACKAGE_NAME, mCallingPackageName);
                 startActivityForResult(intent, ACTIVITY_REQUEST_CREATE_FILE);
             } else {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BarTransitions.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BarTransitions.java
index 1c8702a..8ad538b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BarTransitions.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BarTransitions.java
@@ -16,16 +16,20 @@
 
 package com.android.systemui.statusbar.phone;
 
-import android.animation.ArgbEvaluator;
-import android.animation.ValueAnimator;
-import android.animation.ValueAnimator.AnimatorUpdateListener;
+import android.animation.TimeInterpolator;
 import android.app.ActivityManager;
+import android.content.Context;
 import android.content.res.Resources;
-import android.graphics.drawable.ColorDrawable;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.ColorFilter;
+import android.graphics.PixelFormat;
+import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
-import android.graphics.drawable.TransitionDrawable;
+import android.os.SystemClock;
 import android.util.Log;
 import android.view.View;
+import android.view.animation.LinearInterpolator;
 
 import com.android.systemui.R;
 
@@ -45,43 +49,16 @@
     private final String mTag;
     private final View mView;
     private final boolean mSupportsTransitions = ActivityManager.isHighEndGfx();
-
-    private final int mOpaque;
-    private final int mSemiTransparent;
+    private final BarBackgroundDrawable mBarBackground;
 
     private int mMode;
-    private ValueAnimator mColorDrawableAnimator;
-    private boolean mColorDrawableShowing;
-
-    private final ColorDrawable mColorDrawable;
-    private final TransitionDrawable mTransitionDrawable;
-    private final AnimatorUpdateListener mAnimatorListener = new AnimatorUpdateListener() {
-        @Override
-        public void onAnimationUpdate(ValueAnimator animator) {
-            mColorDrawable.setColor((Integer) animator.getAnimatedValue());
-        }
-    };
 
     public BarTransitions(View view, int gradientResourceId) {
         mTag = "BarTransitions." + view.getClass().getSimpleName();
         mView = view;
-        final Resources res = mView.getContext().getResources();
-
-        if (DEBUG_COLORS) {
-            mOpaque = 0xff0000ff;
-            mSemiTransparent = 0x7f0000ff;
-        } else {
-            mOpaque = res.getColor(R.color.system_bar_background_opaque);
-            mSemiTransparent = res.getColor(R.color.system_bar_background_semi_transparent);
-        }
-
-        mColorDrawable = new ColorDrawable(mOpaque);
-        mTransitionDrawable = new TransitionDrawable(
-                new Drawable[] { res.getDrawable(gradientResourceId), mColorDrawable });
-        mTransitionDrawable.setCrossFadeEnabled(true);
-        mTransitionDrawable.resetTransition();
+        mBarBackground = new BarBackgroundDrawable(mView.getContext(), gradientResourceId);
         if (mSupportsTransitions) {
-            mView.setBackground(mTransitionDrawable);
+            mView.setBackground(mBarBackground);
         }
     }
 
@@ -100,58 +77,14 @@
         }
     }
 
-    private Integer getBackgroundColor(int mode) {
-        if (mode == MODE_SEMI_TRANSPARENT) return mSemiTransparent;
-        if (mode == MODE_OPAQUE) return mOpaque;
-        if (mode == MODE_LIGHTS_OUT) return mOpaque;
-        return null;
-    }
-
     protected void onTransition(int oldMode, int newMode, boolean animate) {
         applyModeBackground(oldMode, newMode, animate);
     }
 
     protected void applyModeBackground(int oldMode, int newMode, boolean animate) {
-        if (DEBUG) Log.d(mTag, String.format("applyModeBackground %s animate=%s",
-                modeToString(newMode), animate));
-        cancelColorAnimation();
-        Integer oldColor = getBackgroundColor(oldMode);
-        Integer newColor = getBackgroundColor(newMode);
-        if (newColor != null) {
-            if (animate && oldColor != null && !oldColor.equals(newColor)) {
-                startColorAnimation(oldColor, newColor);
-            } else if (!newColor.equals(mColorDrawable.getColor())) {
-                if (DEBUG) Log.d(mTag, String.format("setColor = %08x", newColor));
-                mColorDrawable.setColor(newColor);
-            }
-        }
-        if (newColor == null && mColorDrawableShowing) {
-            if (DEBUG) Log.d(mTag, "Hide color layer");
-            if (animate) {
-                mTransitionDrawable.reverseTransition(BACKGROUND_DURATION);
-            } else {
-                mTransitionDrawable.resetTransition();
-            }
-            mColorDrawableShowing = false;
-        } else if (newColor != null && !mColorDrawableShowing) {
-            if (DEBUG) Log.d(mTag, "Show color layer");
-            mTransitionDrawable.startTransition(animate ? BACKGROUND_DURATION : 0);
-            mColorDrawableShowing = true;
-        }
-    }
-
-    private void startColorAnimation(int from, int to) {
-        if (DEBUG) Log.d(mTag, String.format("startColorAnimation %08x -> %08x", from, to));
-        mColorDrawableAnimator = ValueAnimator.ofObject(new ArgbEvaluator(), from, to);
-        mColorDrawableAnimator.addUpdateListener(mAnimatorListener);
-        mColorDrawableAnimator.start();
-    }
-
-    private void cancelColorAnimation() {
-        if (mColorDrawableAnimator != null && mColorDrawableAnimator.isStarted()) {
-            mColorDrawableAnimator.cancel();
-            mColorDrawableAnimator = null;
-        }
+        if (DEBUG) Log.d(mTag, String.format("applyModeBackground oldMode=%s newMode=%s animate=%s",
+                modeToString(oldMode), modeToString(newMode), animate));
+        mBarBackground.applyModeBackground(oldMode, newMode, animate);
     }
 
     public static String modeToString(int mode) {
@@ -161,4 +94,123 @@
         if (mode == MODE_LIGHTS_OUT) return "MODE_LIGHTS_OUT";
         throw new IllegalArgumentException("Unknown mode " + mode);
     }
+
+    public void finishAnimations() {
+        mBarBackground.finishAnimation();
+    }
+
+    private static class BarBackgroundDrawable extends Drawable {
+        private final int mOpaque;
+        private final int mSemiTransparent;
+        private final Drawable mGradient;
+        private final TimeInterpolator mInterpolator;
+
+        private int mMode = -1;
+        private boolean mAnimating;
+        private long mStartTime;
+        private long mEndTime;
+
+        private int mGradientAlpha;
+        private int mColor;
+
+        private int mGradientAlphaStart;
+        private int mColorStart;
+
+        public BarBackgroundDrawable(Context context, int gradientResourceId) {
+            final Resources res = context.getResources();
+            if (DEBUG_COLORS) {
+                mOpaque = 0xff0000ff;
+                mSemiTransparent = 0x7f0000ff;
+            } else {
+                mOpaque = res.getColor(R.color.system_bar_background_opaque);
+                mSemiTransparent = res.getColor(R.color.system_bar_background_semi_transparent);
+            }
+            mGradient = res.getDrawable(gradientResourceId);
+            mInterpolator = new LinearInterpolator();
+        }
+
+        @Override
+        public void setAlpha(int alpha) {
+            // noop
+        }
+
+        @Override
+        public void setColorFilter(ColorFilter cf) {
+            // noop
+        }
+
+        @Override
+        protected void onBoundsChange(Rect bounds) {
+            super.onBoundsChange(bounds);
+            mGradient.setBounds(bounds);
+        }
+
+        public void applyModeBackground(int oldMode, int newMode, boolean animate) {
+            if (mMode == newMode) return;
+            mMode = newMode;
+            mAnimating = animate;
+            if (animate) {
+                long now = SystemClock.elapsedRealtime();
+                mStartTime = now;
+                mEndTime = now + BACKGROUND_DURATION;
+                mGradientAlphaStart = mGradientAlpha;
+                mColorStart = mColor;
+            }
+            invalidateSelf();
+        }
+
+        @Override
+        public int getOpacity() {
+            return PixelFormat.TRANSLUCENT;
+        }
+
+        public void finishAnimation() {
+            if (mAnimating) {
+                mAnimating = false;
+                invalidateSelf();
+            }
+        }
+
+        @Override
+        public void draw(Canvas canvas) {
+            int targetGradientAlpha = 0, targetColor = 0;
+            if (mMode == MODE_TRANSLUCENT) {
+                targetGradientAlpha = 0xff;
+            } else if (mMode == MODE_SEMI_TRANSPARENT) {
+                targetColor = mSemiTransparent;
+            } else {
+                targetColor = mOpaque;
+            }
+            if (!mAnimating) {
+                mColor = targetColor;
+                mGradientAlpha = targetGradientAlpha;
+            } else {
+                final long now = SystemClock.elapsedRealtime();
+                if (now >= mEndTime) {
+                    mAnimating = false;
+                    mColor = targetColor;
+                    mGradientAlpha = targetGradientAlpha;
+                } else {
+                    final float t = (now - mStartTime) / (float)(mEndTime - mStartTime);
+                    final float v = Math.max(0, Math.min(mInterpolator.getInterpolation(t), 1));
+                    mGradientAlpha = (int)(v * targetGradientAlpha + mGradientAlphaStart * (1 - v));
+                    mColor = Color.argb(
+                          (int)(v * Color.alpha(targetColor) + Color.alpha(mColorStart) * (1 - v)),
+                          (int)(v * Color.red(targetColor) + Color.red(mColorStart) * (1 - v)),
+                          (int)(v * Color.green(targetColor) + Color.green(mColorStart) * (1 - v)),
+                          (int)(v * Color.blue(targetColor) + Color.blue(mColorStart) * (1 - v)));
+                }
+            }
+            if (mGradientAlpha > 0) {
+                mGradient.setAlpha(mGradientAlpha);
+                mGradient.draw(canvas);
+            }
+            if (Color.alpha(mColor) > 0) {
+                canvas.drawColor(mColor);
+            }
+            if (mAnimating) {
+                invalidateSelf();  // keep going
+            }
+        }
+    }
 }
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 925179d..39a9ba7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -1945,6 +1945,13 @@
         transitions.transitionTo(mode, anim);
     }
 
+    private void finishBarAnimations() {
+        mStatusBarView.getBarTransitions().finishAnimations();
+        if (mNavigationBarView != null) {
+            mNavigationBarView.getBarTransitions().finishAnimations();
+        }
+    }
+
     private final Runnable mCheckBarModes = new Runnable() {
         @Override
         public void run() {
@@ -2449,6 +2456,7 @@
                 makeExpandedInvisible();
                 notifyNavigationBarScreenOn(false);
                 notifyHeadsUpScreenOn(false);
+                finishBarAnimations();
             }
             else if (Intent.ACTION_SCREEN_ON.equals(action)) {
                 mScreenOn = true;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
index d9ac7e4..d0e9a99 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
@@ -170,6 +170,9 @@
         mBar.makeExpandedInvisibleSoon();
         mFadingPanel = null;
         mLastFullyOpenedPanel = null;
+        if (mScrimColor != 0 && ActivityManager.isHighEndGfx()) {
+            mBar.mStatusBarWindow.setBackgroundColor(0);
+        }
     }
 
     @Override
diff --git a/services/java/com/android/server/Watchdog.java b/services/java/com/android/server/Watchdog.java
index 616090e..8054788 100644
--- a/services/java/com/android/server/Watchdog.java
+++ b/services/java/com/android/server/Watchdog.java
@@ -58,7 +58,14 @@
     // Set this to true to have the watchdog record kernel thread stacks when it fires
     static final boolean RECORD_KERNEL_THREADS = true;
 
-    static final int TIME_TO_WAIT = DB ? 5*1000 : 30*1000;
+    static final long DEFAULT_TIMEOUT = DB ? 10*1000 : 60*1000;
+    static final long CHECK_INTERVAL = DEFAULT_TIMEOUT / 2;
+
+    // These are temporally ordered: larger values as lateness increases
+    static final int COMPLETED = 0;
+    static final int WAITING = 1;
+    static final int WAITED_HALF = 2;
+    static final int OVERDUE = 3;
 
     static final String[] NATIVE_STACKS_OF_INTEREST = new String[] {
         "/system/bin/mediaserver",
@@ -87,13 +94,17 @@
     public final class HandlerChecker implements Runnable {
         private final Handler mHandler;
         private final String mName;
+        private final long mWaitMax;
         private final ArrayList<Monitor> mMonitors = new ArrayList<Monitor>();
         private boolean mCompleted;
         private Monitor mCurrentMonitor;
+        private long mStartTime;
 
-        HandlerChecker(Handler handler, String name) {
+        HandlerChecker(Handler handler, String name, long waitMaxMillis) {
             mHandler = handler;
             mName = name;
+            mWaitMax = waitMaxMillis;
+            mCompleted = true;
         }
 
         public void addMonitor(Monitor monitor) {
@@ -111,13 +122,34 @@
                 mCompleted = true;
                 return;
             }
+
+            if (!mCompleted) {
+                // we already have a check in flight, so no need
+                return;
+            }
+
             mCompleted = false;
             mCurrentMonitor = null;
+            mStartTime = SystemClock.uptimeMillis();
             mHandler.postAtFrontOfQueue(this);
         }
 
-        public boolean isCompletedLocked() {
-            return mCompleted;
+        public boolean isOverdueLocked() {
+            return (!mCompleted) && (SystemClock.uptimeMillis() > mStartTime + mWaitMax);
+        }
+
+        public int getCompletionStateLocked() {
+            if (mCompleted) {
+                return COMPLETED;
+            } else {
+                long latency = SystemClock.uptimeMillis() - mStartTime;
+                if (latency < mWaitMax/2) {
+                    return WAITING;
+                } else if (latency < mWaitMax) {
+                    return WAITED_HALF;
+                }
+            }
+            return OVERDUE;
         }
 
         public Thread getThread() {
@@ -186,16 +218,19 @@
 
         // The shared foreground thread is the main checker.  It is where we
         // will also dispatch monitor checks and do other work.
-        mMonitorChecker = new HandlerChecker(FgThread.getHandler(), "foreground thread");
+        mMonitorChecker = new HandlerChecker(FgThread.getHandler(),
+                "foreground thread", DEFAULT_TIMEOUT);
         mHandlerCheckers.add(mMonitorChecker);
         // Add checker for main thread.  We only do a quick check since there
         // can be UI running on the thread.
         mHandlerCheckers.add(new HandlerChecker(new Handler(Looper.getMainLooper()),
-                "main thread"));
+                "main thread", DEFAULT_TIMEOUT));
         // Add checker for shared UI thread.
-        mHandlerCheckers.add(new HandlerChecker(UiThread.getHandler(), "ui thread"));
+        mHandlerCheckers.add(new HandlerChecker(UiThread.getHandler(),
+                "ui thread", DEFAULT_TIMEOUT));
         // And also check IO thread.
-        mHandlerCheckers.add(new HandlerChecker(IoThread.getHandler(), "i/o thread"));
+        mHandlerCheckers.add(new HandlerChecker(IoThread.getHandler(),
+                "i/o thread", DEFAULT_TIMEOUT));
     }
 
     public void init(Context context, BatteryService battery,
@@ -242,11 +277,15 @@
     }
 
     public void addThread(Handler thread, String name) {
+        addThread(thread, name, DEFAULT_TIMEOUT);
+    }
+
+    public void addThread(Handler thread, String name, long timeoutMillis) {
         synchronized (this) {
             if (isAlive()) {
                 throw new RuntimeException("Threads can't be added once the Watchdog is running");
             }
-            mHandlerCheckers.add(new HandlerChecker(thread, name));
+            mHandlerCheckers.add(new HandlerChecker(thread, name, timeoutMillis));
         }
     }
 
@@ -259,21 +298,20 @@
         pms.reboot(false, reason, false);
     }
 
-    private boolean haveAllCheckersCompletedLocked() {
+    private int evaluateCheckerCompletionLocked() {
+        int state = COMPLETED;
         for (int i=0; i<mHandlerCheckers.size(); i++) {
             HandlerChecker hc = mHandlerCheckers.get(i);
-            if (!hc.isCompletedLocked()) {
-                return false;
-            }
+            state = Math.max(state, hc.getCompletionStateLocked());
         }
-        return true;
+        return state;
     }
 
     private ArrayList<HandlerChecker> getBlockedCheckersLocked() {
         ArrayList<HandlerChecker> checkers = new ArrayList<HandlerChecker>();
         for (int i=0; i<mHandlerCheckers.size(); i++) {
             HandlerChecker hc = mHandlerCheckers.get(i);
-            if (!hc.isCompletedLocked()) {
+            if (hc.isOverdueLocked()) {
                 checkers.add(hc);
             }
         }
@@ -299,14 +337,12 @@
             final String subject;
             final boolean allowRestart;
             synchronized (this) {
-                long timeout = TIME_TO_WAIT;
-                if (!waitedHalf) {
-                    // If we are not at the half-point of waiting, perform a
-                    // new set of checks.  Otherwise we are still waiting for a previous set.
-                    for (int i=0; i<mHandlerCheckers.size(); i++) {
-                        HandlerChecker hc = mHandlerCheckers.get(i);
-                        hc.scheduleCheckLocked();
-                    }
+                long timeout = CHECK_INTERVAL;
+                // Make sure we (re)spin the checkers that have become idle within
+                // this wait-and-check interval
+                for (int i=0; i<mHandlerCheckers.size(); i++) {
+                    HandlerChecker hc = mHandlerCheckers.get(i);
+                    hc.scheduleCheckLocked();
                 }
 
                 // NOTE: We use uptimeMillis() here because we do not want to increment the time we
@@ -320,26 +356,31 @@
                     } catch (InterruptedException e) {
                         Log.wtf(TAG, e);
                     }
-                    timeout = TIME_TO_WAIT - (SystemClock.uptimeMillis() - start);
+                    timeout = CHECK_INTERVAL - (SystemClock.uptimeMillis() - start);
                 }
 
-                if (haveAllCheckersCompletedLocked()) {
-                    // The monitors have returned.
+                final int waitState = evaluateCheckerCompletionLocked();
+                if (waitState == COMPLETED) {
+                    // The monitors have returned; reset
                     waitedHalf = false;
                     continue;
-                }
-
-                if (!waitedHalf) {
-                    // We've waited half the deadlock-detection interval.  Pull a stack
-                    // trace and wait another half.
-                    ArrayList<Integer> pids = new ArrayList<Integer>();
-                    pids.add(Process.myPid());
-                    ActivityManagerService.dumpStackTraces(true, pids, null, null,
-                            NATIVE_STACKS_OF_INTEREST);
-                    waitedHalf = true;
+                } else if (waitState == WAITING) {
+                    // still waiting but within their configured intervals; back off and recheck
+                    continue;
+                } else if (waitState == WAITED_HALF) {
+                    if (!waitedHalf) {
+                        // We've waited half the deadlock-detection interval.  Pull a stack
+                        // trace and wait another half.
+                        ArrayList<Integer> pids = new ArrayList<Integer>();
+                        pids.add(Process.myPid());
+                        ActivityManagerService.dumpStackTraces(true, pids, null, null,
+                                NATIVE_STACKS_OF_INTEREST);
+                        waitedHalf = true;
+                    }
                     continue;
                 }
 
+                // something is overdue!
                 blockedCheckers = getBlockedCheckersLocked();
                 subject = describeCheckersLocked(blockedCheckers);
                 allowRestart = mAllowRestart;
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index 8b7fd8e..ab9d9bd 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -12367,7 +12367,6 @@
         synchronized(this) {
             final int callingPid = Binder.getCallingPid();
             final int callingUid = Binder.getCallingUid();
-            checkValidCaller(callingUid, userId);
             final long origId = Binder.clearCallingIdentity();
             ComponentName res = mServices.startServiceLocked(caller, service,
                     resolvedType, callingPid, callingUid, userId);
@@ -12397,8 +12396,6 @@
             throw new IllegalArgumentException("File descriptors passed in Intent");
         }
 
-        checkValidCaller(Binder.getCallingUid(), userId);
-
         synchronized(this) {
             return mServices.stopServiceLocked(caller, service, resolvedType, userId);
         }
@@ -16389,13 +16386,6 @@
         return mUserManager;
     }
 
-    private void checkValidCaller(int uid, int userId) {
-        if (UserHandle.getUserId(uid) == userId || uid == Process.SYSTEM_UID || uid == 0) return;
-
-        throw new SecurityException("Caller uid=" + uid
-                + " is not privileged to communicate with user=" + userId);
-    }
-
     private int applyUserId(int uid, int userId) {
         return UserHandle.getUid(userId, uid);
     }
diff --git a/services/java/com/android/server/am/ActivityStack.java b/services/java/com/android/server/am/ActivityStack.java
index 497d48c5..2e5dedf 100644
--- a/services/java/com/android/server/am/ActivityStack.java
+++ b/services/java/com/android/server/am/ActivityStack.java
@@ -740,7 +740,10 @@
         prev.state = ActivityState.PAUSING;
         prev.task.touchActiveTime();
         clearLaunchTime(prev);
-        prev.updateThumbnail(screenshotActivities(prev), null);
+        final ActivityRecord next = mStackSupervisor.topRunningActivityLocked();
+        if (next == null || next.task != prev.task) {
+            prev.updateThumbnail(screenshotActivities(prev), null);
+        }
         stopFullyDrawnTraceIfNeeded();
 
         mService.updateCpuStats();
diff --git a/services/java/com/android/server/pm/PackageManagerService.java b/services/java/com/android/server/pm/PackageManagerService.java
index e075862..a781d5f 100755
--- a/services/java/com/android/server/pm/PackageManagerService.java
+++ b/services/java/com/android/server/pm/PackageManagerService.java
@@ -221,6 +221,14 @@
     static final int REMOVE_CHATTY = 1<<16;
 
     /**
+     * Timeout (in milliseconds) after which the watchdog should declare that
+     * our handler thread is wedged.  The usual default for such things is one
+     * minute but we sometimes do very lengthy I/O operations on this thread,
+     * such as installing multi-gigabyte applications, so ours needs to be longer.
+     */
+    private static final long WATCHDOG_TIMEOUT = 1000*60*10;     // ten minutes
+
+    /**
      * Whether verification is enabled by default.
      */
     private static final boolean DEFAULT_VERIFY_ENABLE = true;
@@ -1115,7 +1123,8 @@
         synchronized (mPackages) {
             mHandlerThread.start();
             mHandler = new PackageHandler(mHandlerThread.getLooper());
-            Watchdog.getInstance().addThread(mHandler, mHandlerThread.getName());
+            Watchdog.getInstance().addThread(mHandler, mHandlerThread.getName(),
+                    WATCHDOG_TIMEOUT);
 
             File dataDir = Environment.getDataDirectory();
             mAppDataDir = new File(dataDir, "data");
diff --git a/services/java/com/android/server/pm/Settings.java b/services/java/com/android/server/pm/Settings.java
index b0cfd7e..d3ccba6 100644
--- a/services/java/com/android/server/pm/Settings.java
+++ b/services/java/com/android/server/pm/Settings.java
@@ -2070,8 +2070,10 @@
                 if (intent.getAction() != null) {
                     filter.addAction(intent.getAction());
                 }
-                for (String cat : intent.getCategories()) {
-                    filter.addCategory(cat);
+                if (intent.getCategories() != null) {
+                    for (String cat : intent.getCategories()) {
+                        filter.addCategory(cat);
+                    }
                 }
                 if ((flags&PackageManager.MATCH_DEFAULT_ONLY) != 0) {
                     filter.addCategory(Intent.CATEGORY_DEFAULT);
@@ -2088,6 +2090,13 @@
                 if (path != null) {
                     filter.addDataPath(path);
                 }
+                if (intent.getType() != null) {
+                    try {
+                        filter.addDataType(intent.getType());
+                    } catch (IntentFilter.MalformedMimeTypeException ex) {
+                        Slog.w(TAG, "Malformed mimetype " + intent.getType() + " for " + cn);
+                    }
+                }
                 PreferredActivity pa = new PreferredActivity(filter, match, set, cn, true);
                 editPreferredActivitiesLPw(userId).addFilter(pa);
             } else if (!haveNonSys) {
diff --git a/services/java/com/android/server/power/PowerManagerService.java b/services/java/com/android/server/power/PowerManagerService.java
index 8fbde14..da9548f 100644
--- a/services/java/com/android/server/power/PowerManagerService.java
+++ b/services/java/com/android/server/power/PowerManagerService.java
@@ -747,6 +747,21 @@
     }
 
     @Override // Binder call
+    public void updateWakeLockUids(IBinder lock, int[] uids) {
+        WorkSource ws = null;
+
+        if (uids != null) {
+            ws = new WorkSource();
+            // XXX should WorkSource have a way to set uids as an int[] instead of adding them
+            // one at a time?
+            for (int i = 0; i < uids.length; i++) {
+                ws.add(uids[i]);
+            }
+        }
+        updateWakeLockWorkSource(lock, ws);
+    }
+
+    @Override // Binder call
     public void updateWakeLockWorkSource(IBinder lock, WorkSource ws) {
         if (lock == null) {
             throw new IllegalArgumentException("lock must not be null");
diff --git a/services/java/com/android/server/wm/DisplayContent.java b/services/java/com/android/server/wm/DisplayContent.java
index afa4f78..52f2325 100644
--- a/services/java/com/android/server/wm/DisplayContent.java
+++ b/services/java/com/android/server/wm/DisplayContent.java
@@ -107,7 +107,7 @@
     Region mTouchExcludeRegion = new Region();
 
     /** Save allocating when retrieving tasks */
-    ArrayList<Task> mTmpTasks = new ArrayList<Task>();
+    ArrayList<Task> mTaskHistory = new ArrayList<Task>();
 
     /** Save allocating when calculating rects */
     Rect mTmpRect = new Rect();
@@ -163,7 +163,7 @@
     void moveStack(TaskStack stack, boolean toTop) {
         mStackHistory.remove(stack);
         mStackHistory.add(toTop ? mStackHistory.size() : 0, stack);
-        mService.moveStackWindowsLocked(stack);
+        mService.moveStackWindowsLocked(this);
     }
 
     public boolean isPrivate() {
@@ -175,14 +175,35 @@
      * @return All the Tasks, in order, on this display.
      */
     ArrayList<Task> getTasks() {
-        mTmpTasks.clear();
-        final int numStacks = mStackHistory.size();
-        for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) {
-            mTmpTasks.addAll(mStackHistory.get(stackNdx).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;
+                }
+            }
         }
-        if (WindowManagerService.DEBUG_LAYERS) Slog.i(TAG, "getTasks: mStackHistory=" +
-                mStackHistory);
-        return mTmpTasks;
+
+        mTaskHistory.add(taskNdx, task);
+    }
+
+    void removeTask(Task task) {
+        mTaskHistory.remove(task);
     }
 
     TaskStack getHomeStack() {
@@ -205,10 +226,9 @@
 
     /** @return The number of tokens in all of the Tasks on this display. */
     int numTokens() {
-        getTasks();
         int count = 0;
-        for (int taskNdx = mTmpTasks.size() - 1; taskNdx >= 0; --taskNdx) {
-            count += mTmpTasks.get(taskNdx).mAppTokens.size();
+        for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
+            count += mTaskHistory.get(taskNdx).mAppTokens.size();
         }
         return count;
     }
@@ -469,8 +489,8 @@
             pw.println();
             pw.println("  Application tokens in Z order:");
             getTasks();
-            for (int taskNdx = mTmpTasks.size() - 1; taskNdx >= 0; --taskNdx) {
-                AppTokenList tokens = mTmpTasks.get(taskNdx).mAppTokens;
+            for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
+                AppTokenList tokens = mTaskHistory.get(taskNdx).mAppTokens;
                 for (int tokenNdx = tokens.size() - 1; tokenNdx >= 0; --tokenNdx) {
                     final AppWindowToken wtoken = tokens.get(tokenNdx);
                     pw.print("  App #"); pw.print(ndx--);
diff --git a/services/java/com/android/server/wm/TaskStack.java b/services/java/com/android/server/wm/TaskStack.java
index 2347a19..34bef68 100644
--- a/services/java/com/android/server/wm/TaskStack.java
+++ b/services/java/com/android/server/wm/TaskStack.java
@@ -120,6 +120,7 @@
         mTasks.add(stackNdx, task);
 
         task.mStack = this;
+        mDisplayContent.addTask(task, toTop);
         return mDisplayContent.moveHomeStackBox(mStackId == HOME_STACK_ID);
     }
 
@@ -145,6 +146,7 @@
         if (DEBUG_TASK_MOVEMENT) Slog.d(TAG, "removeTask: task=" + task);
         mStackBox.makeDirty();
         mTasks.remove(task);
+        mDisplayContent.removeTask(task);
     }
 
     int remove() {
diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java
index abc2b2b..63e09db 100644
--- a/services/java/com/android/server/wm/WindowManagerService.java
+++ b/services/java/com/android/server/wm/WindowManagerService.java
@@ -4733,11 +4733,9 @@
         return index;
     }
 
-    void moveStackWindowsLocked(TaskStack stack) {
-        DisplayContent displayContent = stack.getDisplayContent();
-
+    void moveStackWindowsLocked(DisplayContent displayContent) {
         // First remove all of the windows from the list.
-        final ArrayList<Task> tasks = stack.getTasks();
+        final ArrayList<Task> tasks = displayContent.getTasks();
         final int numTasks = tasks.size();
         for (int taskNdx = 0; taskNdx < numTasks; ++taskNdx) {
             AppTokenList tokens = tasks.get(taskNdx).mAppTokens;
@@ -4813,7 +4811,7 @@
                 }
                 final TaskStack stack = task.mStack;
                 stack.moveTaskToBottom(task);
-                moveStackWindowsLocked(stack);
+                moveStackWindowsLocked(stack.getDisplayContent());
             }
         } finally {
             Binder.restoreCallingIdentity(origId);
@@ -5724,7 +5722,7 @@
         canvas.drawBitmap(rawss, matrix, null);
         canvas.setBitmap(null);
 
-        if (true || DEBUG_SCREENSHOT) {
+        if (DEBUG_SCREENSHOT) {
             // TEST IF IT's ALL BLACK
             int[] buffer = new int[bm.getWidth() * bm.getHeight()];
             bm.getPixels(buffer, 0, bm.getWidth(), 0, 0, bm.getWidth(), bm.getHeight());
@@ -8434,20 +8432,6 @@
                         && !mWallpaperTarget.mWinAnimator.isDummyAnimation()
                     ? null : mWallpaperTarget;
 
-            // If there is a wallpaper target and the target is neither opening nor closing, then
-            // there exists an app on top of the wallpaper target that has a translucent
-            // background.
-            // If the pending transition is an exit, we should add the wallpaper target to the list
-            // of opening apps so that the translucent app on top of it will animate correctly.
-            final AppWindowToken wallpaperTargetAppToken =
-                    mWallpaperTarget != null ? mWallpaperTarget.mAppToken : null;
-            if (wallpaperTargetAppToken != null
-                    && !mClosingApps.contains(wallpaperTargetAppToken)
-                    && !mOpeningApps.contains(wallpaperTargetAppToken)
-                    && (transit & AppTransition.TRANSIT_EXIT_MASK) != 0) {
-                mOpeningApps.add(wallpaperTargetAppToken);
-                NN++;
-            }
             mInnerFields.mWallpaperMayChange = false;
 
             // The top-most window will supply the layout params,
@@ -8533,7 +8517,8 @@
                         break;
                 }
                 if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "New transit: " + transit);
-            } else if ((oldWallpaper != null) && !mOpeningApps.contains(oldWallpaper.mAppToken)) {
+            } else if ((oldWallpaper != null) && !mOpeningApps.isEmpty()
+                    && !mOpeningApps.contains(oldWallpaper.mAppToken)) {
                 // We are transitioning from an activity with
                 // a wallpaper to one without.
                 transit = AppTransition.TRANSIT_WALLPAPER_CLOSE;
@@ -8602,8 +8587,7 @@
                 wtoken.mAppAnimator.clearThumbnail();
                 wtoken.inPendingTransaction = false;
                 wtoken.mAppAnimator.animation = null;
-                setTokenVisibilityLocked(wtoken, animLp, false,
-                        transit, false);
+                setTokenVisibilityLocked(wtoken, animLp, false, transit, false);
                 wtoken.updateReportedVisibilityLocked();
                 wtoken.waitingToHide = false;
                 // Force the allDrawn flag, because we want to start
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index 584411b..7bd2c84 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -155,6 +155,26 @@
     boolean supplyPuk(String puk, String pin);
 
     /**
+     * Supply a pin to unlock the SIM.  Blocks until a result is determined.
+     * Returns a specific success/error code.
+     * @param pin The pin to check.
+     * @return retValue[0] = Phone.PIN_RESULT_SUCCESS on success. Otherwise error code
+     *         retValue[1] = number of attempts remaining if known otherwise -1
+     */
+    int[] supplyPinReportResult(String pin);
+
+    /**
+     * Supply puk to unlock the SIM and set SIM pin to new pin.
+     * Blocks until a result is determined.
+     * Returns a specific success/error code
+     * @param puk The puk to check
+     *        pin The pin to check.
+     * @return retValue[0] = Phone.PIN_RESULT_SUCCESS on success. Otherwise error code
+     *         retValue[1] = number of attempts remaining if known otherwise -1
+     */
+    int[] supplyPukReportResult(String puk, String pin);
+
+    /**
      * Handles PIN MMI commands (PIN/PIN2/PUK/PUK2), which are initiated
      * without SEND (so <code>dial</code> is not appropriate).
      *
diff --git a/telephony/java/com/android/internal/telephony/PhoneConstants.java b/telephony/java/com/android/internal/telephony/PhoneConstants.java
index 4a4a62b..4163255 100644
--- a/telephony/java/com/android/internal/telephony/PhoneConstants.java
+++ b/telephony/java/com/android/internal/telephony/PhoneConstants.java
@@ -86,6 +86,14 @@
     public static final String REASON_LINK_PROPERTIES_CHANGED = "linkPropertiesChanged";
 
     /**
+     * Return codes for supplyPinReturnResult and
+     * supplyPukReturnResult APIs
+     */
+    public static final int PIN_RESULT_SUCCESS = 0;
+    public static final int PIN_PASSWORD_INCORRECT = 1;
+    public static final int PIN_GENERAL_FAILURE = 2;
+
+    /**
      * Return codes for <code>enableApnType()</code>
      */
     public static final int APN_ALREADY_ACTIVE     = 0;
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePowerManager.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePowerManager.java
index a8b58aa..281337c 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePowerManager.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePowerManager.java
@@ -81,6 +81,11 @@
     }
 
     @Override
+    public void updateWakeLockUids(IBinder arg0, int[] arg1) throws RemoteException {
+        // pass for now.
+    }
+
+    @Override
     public void setAttentionLight(boolean arg0, int arg1) throws RemoteException {
         // pass for now.
     }