Merge "Setting MTU size for specific network" into klp-dev
diff --git a/api/current.txt b/api/current.txt
index a8b5efd..dc21e90 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -10693,10 +10693,6 @@
     method public int getMinFrequency();
   }
 
-  public abstract interface FlushCompleteListener {
-    method public abstract void onFlushCompleted(android.hardware.Sensor);
-  }
-
   public class GeomagneticField {
     ctor public GeomagneticField(float, float, float, long);
     method public float getDeclination();
@@ -10754,6 +10750,10 @@
     method public abstract void onSensorChanged(android.hardware.SensorEvent);
   }
 
+  public abstract interface SensorEventListener2 implements android.hardware.SensorEventListener {
+    method public abstract void onFlushCompleted(android.hardware.Sensor);
+  }
+
   public abstract deprecated interface SensorListener {
     method public abstract void onAccuracyChanged(int, int);
     method public abstract void onSensorChanged(int, float[]);
@@ -10761,7 +10761,7 @@
 
   public abstract class SensorManager {
     method public boolean cancelTriggerSensor(android.hardware.TriggerEventListener, android.hardware.Sensor);
-    method public boolean flush(android.hardware.Sensor);
+    method public boolean flush(android.hardware.SensorEventListener);
     method public static float getAltitude(float, float);
     method public static void getAngleChange(float[], float[], float[]);
     method public android.hardware.Sensor getDefaultSensor(int);
@@ -10775,9 +10775,9 @@
     method public deprecated boolean registerListener(android.hardware.SensorListener, int);
     method public deprecated boolean registerListener(android.hardware.SensorListener, int, int);
     method public boolean registerListener(android.hardware.SensorEventListener, android.hardware.Sensor, int);
-    method public boolean registerListener(android.hardware.SensorEventListener, android.hardware.Sensor, int, int, int, android.hardware.FlushCompleteListener);
+    method public boolean registerListener(android.hardware.SensorEventListener, android.hardware.Sensor, int, int);
     method public boolean registerListener(android.hardware.SensorEventListener, android.hardware.Sensor, int, android.os.Handler);
-    method public boolean registerListener(android.hardware.SensorEventListener, android.hardware.Sensor, int, int, int, android.os.Handler, android.hardware.FlushCompleteListener);
+    method public boolean registerListener(android.hardware.SensorEventListener, android.hardware.Sensor, int, int, android.os.Handler);
     method public static boolean remapCoordinateSystem(float[], int, int, float[]);
     method public boolean requestTriggerSensor(android.hardware.TriggerEventListener, android.hardware.Sensor);
     method public deprecated void unregisterListener(android.hardware.SensorListener);
diff --git a/core/java/android/bluetooth/BluetoothA2dp.java b/core/java/android/bluetooth/BluetoothA2dp.java
index e7e4a0f..6f929f2 100644
--- a/core/java/android/bluetooth/BluetoothA2dp.java
+++ b/core/java/android/bluetooth/BluetoothA2dp.java
@@ -513,7 +513,7 @@
         }
     }
 
-    private ServiceConnection mConnection = new ServiceConnection() {
+    private final ServiceConnection mConnection = new ServiceConnection() {
         public void onServiceConnected(ComponentName className, IBinder service) {
             if (DBG) Log.d(TAG, "Proxy object connected");
             mService = IBluetoothA2dp.Stub.asInterface(service);
diff --git a/core/java/android/bluetooth/BluetoothDevice.java b/core/java/android/bluetooth/BluetoothDevice.java
index 5eb642c..5822e46 100644
--- a/core/java/android/bluetooth/BluetoothDevice.java
+++ b/core/java/android/bluetooth/BluetoothDevice.java
@@ -322,7 +322,8 @@
 
     /**
      * Broadcast Action: This intent is used to broadcast PAIRING REQUEST
-     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive.
+     * <p>Requires {@link android.Manifest.permission#BLUETOOTH_PRIVILEGED} to
+     * receive.
      */
     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
     public static final String ACTION_PAIRING_REQUEST =
diff --git a/core/java/android/bluetooth/BluetoothHeadset.java b/core/java/android/bluetooth/BluetoothHeadset.java
index 1962514..8ee955d 100644
--- a/core/java/android/bluetooth/BluetoothHeadset.java
+++ b/core/java/android/bluetooth/BluetoothHeadset.java
@@ -885,7 +885,7 @@
         return false;
     }
 
-    private ServiceConnection mConnection = new ServiceConnection() {
+    private final ServiceConnection mConnection = new ServiceConnection() {
         public void onServiceConnected(ComponentName className, IBinder service) {
             if (DBG) Log.d(TAG, "Proxy object connected");
             mService = IBluetoothHeadset.Stub.asInterface(service);
diff --git a/core/java/android/bluetooth/BluetoothHealth.java b/core/java/android/bluetooth/BluetoothHealth.java
index b1a084a..2e950fa 100644
--- a/core/java/android/bluetooth/BluetoothHealth.java
+++ b/core/java/android/bluetooth/BluetoothHealth.java
@@ -519,7 +519,7 @@
         mServiceListener = null;
     }
 
-    private ServiceConnection mConnection = new ServiceConnection() {
+    private final ServiceConnection mConnection = new ServiceConnection() {
         public void onServiceConnected(ComponentName className, IBinder service) {
             if (DBG) Log.d(TAG, "Proxy object connected");
             mService = IBluetoothHealth.Stub.asInterface(service);
diff --git a/core/java/android/bluetooth/BluetoothInputDevice.java b/core/java/android/bluetooth/BluetoothInputDevice.java
index f9c789c..844f432 100644
--- a/core/java/android/bluetooth/BluetoothInputDevice.java
+++ b/core/java/android/bluetooth/BluetoothInputDevice.java
@@ -458,7 +458,7 @@
         return BluetoothProfile.PRIORITY_OFF;
     }
 
-    private ServiceConnection mConnection = new ServiceConnection() {
+    private final ServiceConnection mConnection = new ServiceConnection() {
         public void onServiceConnected(ComponentName className, IBinder service) {
             if (DBG) Log.d(TAG, "Proxy object connected");
             mService = IBluetoothInputDevice.Stub.asInterface(service);
diff --git a/core/java/android/bluetooth/BluetoothMap.java b/core/java/android/bluetooth/BluetoothMap.java
index fac8fd5..92a2f1e 100644
--- a/core/java/android/bluetooth/BluetoothMap.java
+++ b/core/java/android/bluetooth/BluetoothMap.java
@@ -142,7 +142,6 @@
                 try {
                     mService = null;
                     mContext.unbindService(mConnection);
-                    mConnection = null;
                 } catch (Exception re) {
                     Log.e(TAG,"",re);
                 }
@@ -370,7 +369,7 @@
         return PRIORITY_OFF;
     }
 
-    private ServiceConnection mConnection = new ServiceConnection() {
+    private final ServiceConnection mConnection = new ServiceConnection() {
         public void onServiceConnected(ComponentName className, IBinder service) {
             if (DBG) log("Proxy object connected");
             mService = IBluetoothMap.Stub.asInterface(service);
diff --git a/core/java/android/bluetooth/BluetoothPan.java b/core/java/android/bluetooth/BluetoothPan.java
index 83d4329..b7a37f4 100644
--- a/core/java/android/bluetooth/BluetoothPan.java
+++ b/core/java/android/bluetooth/BluetoothPan.java
@@ -155,23 +155,34 @@
 
     /*package*/ void close() {
         if (VDBG) log("close()");
-        if (mConnection != null) {
-            mContext.unbindService(mConnection);
-            mConnection = null;
+
+        IBluetoothManager mgr = mAdapter.getBluetoothManager();
+        if (mgr != null) {
+            try {
+                mgr.unregisterStateChangeCallback(mStateChangeCallback);
+            } catch (RemoteException re) {
+                Log.w(TAG,"Unable to unregister BluetoothStateChangeCallback",re);
+            }
+        }
+
+        synchronized (mConnection) {
+            if (mPanService != null) {
+                try {
+                    mPanService = null;
+                    mContext.unbindService(mConnection);
+                } catch (Exception re) {
+                    Log.e(TAG,"",re);
+                }
+            }
         }
         mServiceListener = null;
-        try {
-            mAdapter.getBluetoothManager().unregisterStateChangeCallback(mStateChangeCallback);
-        } catch (RemoteException re) {
-            Log.w(TAG,"Unable to register BluetoothStateChangeCallback",re);
-        }
     }
 
     protected void finalize() {
         close();
     }
 
-    private IBluetoothStateChangeCallback mStateChangeCallback = new IBluetoothStateChangeCallback.Stub() {
+    final private IBluetoothStateChangeCallback mStateChangeCallback = new IBluetoothStateChangeCallback.Stub() {
 
         @Override
         public void onBluetoothStateChange(boolean on) throws RemoteException {
@@ -339,7 +350,7 @@
         return false;
     }
 
-    private ServiceConnection mConnection = new ServiceConnection() {
+    private final ServiceConnection mConnection = new ServiceConnection() {
         public void onServiceConnected(ComponentName className, IBinder service) {
             if (DBG) Log.d(TAG, "BluetoothPAN Proxy object connected");
             mPanService = IBluetoothPan.Stub.asInterface(service);
diff --git a/core/java/android/bluetooth/BluetoothPbap.java b/core/java/android/bluetooth/BluetoothPbap.java
index c42251f..7f45652 100644
--- a/core/java/android/bluetooth/BluetoothPbap.java
+++ b/core/java/android/bluetooth/BluetoothPbap.java
@@ -197,7 +197,6 @@
                 try {
                     mService = null;
                     mContext.unbindService(mConnection);
-                    mConnection = null;
                 } catch (Exception re) {
                     Log.e(TAG,"",re);
                 }
@@ -300,7 +299,7 @@
         }
     }
 
-    private ServiceConnection mConnection = new ServiceConnection() {
+    private final ServiceConnection mConnection = new ServiceConnection() {
         public void onServiceConnected(ComponentName className, IBinder service) {
             if (DBG) log("Proxy object connected");
             mService = IBluetoothPbap.Stub.asInterface(service);
diff --git a/core/java/android/hardware/FlushCompleteListener.java b/core/java/android/hardware/SensorEventListener2.java
similarity index 89%
rename from core/java/android/hardware/FlushCompleteListener.java
rename to core/java/android/hardware/SensorEventListener2.java
index fbdf4c8..4c3b429 100644
--- a/core/java/android/hardware/FlushCompleteListener.java
+++ b/core/java/android/hardware/SensorEventListener2.java
@@ -19,7 +19,7 @@
 /**
  * Used for receiving a notification when a flush() has been successfully completed.
  */
-public interface FlushCompleteListener {
+public interface SensorEventListener2 extends SensorEventListener {
     /**
      * Called after flush() is completed. This flush() could have been initiated by this application
      * or some other application. All the events in the batch at the point when the flush was called
@@ -28,7 +28,7 @@
      *
      * @param sensor The {@link android.hardware.Sensor Sensor} on which flush was called.
      *
-     * @see android.hardware.SensorManager#flush(Sensor)
+     * @see android.hardware.SensorManager#flush(SensorEventListener)
      */
     public void onFlushCompleted(Sensor sensor);
 }
diff --git a/core/java/android/hardware/SensorManager.java b/core/java/android/hardware/SensorManager.java
index 8a4aa1d..b931313 100644
--- a/core/java/android/hardware/SensorManager.java
+++ b/core/java/android/hardware/SensorManager.java
@@ -533,8 +533,6 @@
      *
      * @see #unregisterListener(SensorEventListener)
      * @see #registerListener(SensorEventListener, Sensor, int)
-     *
-     * @throws IllegalArgumentException when sensor is a trigger sensor.
      */
     public void unregisterListener(SensorEventListener listener, Sensor sensor) {
         if (listener == null || sensor == null) {
@@ -601,7 +599,6 @@
      * @see #unregisterListener(SensorEventListener)
      * @see #unregisterListener(SensorEventListener, Sensor)
      *
-     * @throws IllegalArgumentException when sensor is null or a trigger sensor
      */
     public boolean registerListener(SensorEventListener listener, Sensor sensor, int rateUs) {
         return registerListener(listener, sensor, rateUs, null);
@@ -638,7 +635,9 @@
      * {@link #requestTriggerSensor(TriggerEventListener, Sensor)} instead. </p>
      *
      * @param listener A {@link android.hardware.SensorEventListener SensorEventListener} object
-     *            that will receive the sensor events.
+     *            that will receive the sensor events. If the application is interested in receiving
+     *            flush complete notifications, it should register with
+     *            {@link android.hardware.SensorEventListener SensorEventListener2} instead.
      * @param sensor The {@link android.hardware.Sensor Sensor} to register to.
      * @param rateUs The desired delay between two consecutive events in microseconds. This is only
      *            a hint to the system. Events may be received faster or slower than the specified
@@ -651,30 +650,23 @@
      *            large. If this is set to zero, batch mode is disabled and events are delivered in
      *            continuous mode as soon as they are available which is equivalent to calling
      *            {@link #registerListener(SensorEventListener, Sensor, int)}.
-     * @param reservedFlags Always set to Zero.
-     * @param flushCompleteListener A {@link android.hardware.FlushCompleteListener
-     *            FlushCompleteListener} object which is called when any application calls flush()
-     *            on this sensor and all the events in the batch at the time of calling flush() are
-     *            successfully delivered to the listeners.
-     * @return true if batch mode is successfully enabled for this sensor, false otherwise.
+     * @return <code>true</code> if batch mode is successfully enabled for this sensor,
+     *         <code>false</code> otherwise.
      * @see #registerListener(SensorEventListener, Sensor, int)
      * @see #unregisterListener(SensorEventListener)
-     * @see #flush(Sensor)
-     * @throws IllegalArgumentException when sensor or listener is null or a trigger sensor.
+     * @see #flush(SensorEventListener)
      */
     public boolean registerListener(SensorEventListener listener, Sensor sensor, int rateUs,
-            int maxBatchReportLatencyUs, int reservedFlags,
-            FlushCompleteListener flushCompleteListener) {
+            int maxBatchReportLatencyUs) {
         int delay = getDelay(rateUs);
-        return registerListenerImpl(listener, sensor, delay, null, maxBatchReportLatencyUs,
-                                        reservedFlags, flushCompleteListener);
+        return registerListenerImpl(listener, sensor, delay, null, maxBatchReportLatencyUs, 0);
     }
 
     /**
      * Registers a {@link android.hardware.SensorEventListener SensorEventListener} for the given
      * sensor. Events are delivered in continuous mode as soon as they are available. To reduce the
-     * battery usage, use {@link #registerListener(SensorEventListener, Sensor, int, int, int,
-     * FlushCompleteListener)} which enables batch mode for the sensor.
+     * battery usage, use {@link #registerListener(SensorEventListener, Sensor, int, int)} which
+     * enables batch mode for the sensor.
      *
      * <p class="note"></p>
      * Note: Don't use this method with a one shot trigger sensor such as
@@ -706,67 +698,80 @@
      *        {@link android.hardware.SensorEvent sensor events} will be
      *        delivered to.
      *
-     * @return true if the sensor is supported and successfully enabled.
+     * @return <code>true</code> if the sensor is supported and successfully enabled.
      *
      * @see #registerListener(SensorEventListener, Sensor, int)
      * @see #unregisterListener(SensorEventListener)
      * @see #unregisterListener(SensorEventListener, Sensor)
-     *
-     * @throws IllegalArgumentException when sensor is null or a trigger sensor
      */
     public boolean registerListener(SensorEventListener listener, Sensor sensor, int rateUs,
             Handler handler) {
-        if (listener == null || sensor == null) {
-            return false;
-        }
-
         int delay = getDelay(rateUs);
-        return registerListenerImpl(listener, sensor, delay, handler, 0, 0, null);
+        return registerListenerImpl(listener, sensor, delay, handler, 0, 0);
     }
 
     /**
      * Enables batch mode for a sensor with the given rate and maxBatchReportLatency.
-     * @param handler
-     *        The {@link android.os.Handler Handler} the
-     *        {@link android.hardware.SensorEvent sensor events} will be
-     *        delivered to.
+     * @param listener A {@link android.hardware.SensorEventListener SensorEventListener} object
+     *            that will receive the sensor events. If the application is interested in receiving
+     *            flush complete notifications, it should register with
+     *            {@link android.hardware.SensorEventListener SensorEventListener2} instead.
+     * @param sensor The {@link android.hardware.Sensor Sensor} to register to.
+     * @param rateUs The desired delay between two consecutive events in microseconds. This is only
+     *            a hint to the system. Events may be received faster or slower than the specified
+     *            rate. Usually events are received faster. Can be one of
+     *            {@link #SENSOR_DELAY_NORMAL}, {@link #SENSOR_DELAY_UI},
+     *            {@link #SENSOR_DELAY_GAME}, {@link #SENSOR_DELAY_FASTEST} or the delay in
+     *            microseconds.
+     * @param maxBatchReportLatencyUs An event in the batch can be delayed by at most
+     *            maxBatchReportLatency microseconds. More events can be batched if this value is
+     *            large. If this is set to zero, batch mode is disabled and events are delivered in
+     *            continuous mode as soon as they are available which is equivalent to calling
+     *            {@link #registerListener(SensorEventListener, Sensor, int)}.
+     * @param handler The {@link android.os.Handler Handler} the
+     *        {@link android.hardware.SensorEvent sensor events} will be delivered to.
      *
-     * @see #registerListener(SensorEventListener, Sensor, int, int, int, FlushCompleteListener)
+     * @return <code>true</code> if batch mode is successfully enabled for this sensor,
+     *         <code>false</code> otherwise.
+     * @see #registerListener(SensorEventListener, Sensor, int, int)
      */
     public boolean registerListener(SensorEventListener listener, Sensor sensor, int rateUs,
-            int maxBatchReportLatencyUs, int reservedFlags, Handler handler,
-            FlushCompleteListener flushCompleteListener) {
+            int maxBatchReportLatencyUs, Handler handler) {
         int delayUs = getDelay(rateUs);
-        return registerListenerImpl(listener, sensor, delayUs, handler, maxBatchReportLatencyUs,
-                                        reservedFlags, flushCompleteListener);
+        return registerListenerImpl(listener, sensor, delayUs, handler, maxBatchReportLatencyUs, 0);
     }
 
     /** @hide */
     protected abstract boolean registerListenerImpl(SensorEventListener listener, Sensor sensor,
-            int delayUs, Handler handler, int maxBatchReportLatencyUs, int reservedFlags,
-            FlushCompleteListener flushCompleteListener);
+            int delayUs, Handler handler, int maxBatchReportLatencyUs, int reservedFlags);
 
 
     /**
-     * Flushes the batch FIFO of the given sensor. If there are events in the FIFO of this sensor,
-     * they are returned as if the batch timeout has expired. Events are returned in the
-     * usual way through the SensorEventListener. This call doesn't effect the batch timeout for
-     * this sensor. This call is asynchronous and returns immediately. FlushCompleteListener is
-     * called after all the events in the batch at the time of calling this method have been
-     * delivered successfully.
-     * @param sensor
-     *        The {@link android.hardware.Sensor Sensor} to flush.
-     * @return true if the flush is initiated successfully. false if the sensor isn't active
-     *         i.e no application is registered for updates from this sensor.
-     * @see #registerListener(SensorEventListener, Sensor, int, int, int, FlushCompleteListener)
-     * @throws IllegalArgumentException when sensor is null or a trigger sensor.
+     * Flushes the batch FIFO of all the sensors registered for this listener. If there are events
+     * in the FIFO of the sensor, they are returned as if the batch timeout in the FIFO of the
+     * sensors had expired. Events are returned in the usual way through the SensorEventListener.
+     * This call doesn't affect the batch timeout for this sensor. This call is asynchronous and
+     * returns immediately.
+     * {@link android.hardware.SensorEventListener2#onFlushCompleted onFlushCompleted} is called
+     * after all the events in the batch at the time of calling this method have been delivered
+     * successfully. If the hardware doesn't support flush, it still returns true and a trivial
+     * flush complete event is sent after the current event for all the clients registered for this
+     * sensor.
+     *
+     * @param listener A {@link android.hardware.SensorEventListener SensorEventListener} object
+     *        which was previously used in a registerListener call.
+     * @return <code>true</code> if the flush is initiated successfully on all the sensors
+     *         registered for this listener, false if no sensor is previously registered for this
+     *         listener or flush on one of the sensors fails.
+     * @see #registerListener(SensorEventListener, Sensor, int, int)
+     * @throws IllegalArgumentException when listener is null.
      */
-    public boolean flush(Sensor sensor) {
-        return flushImpl(sensor);
+    public boolean flush(SensorEventListener listener) {
+        return flushImpl(listener);
     }
 
     /** @hide */
-    protected abstract boolean flushImpl(Sensor sensor);
+    protected abstract boolean flushImpl(SensorEventListener listener);
 
     /**
      * <p>
diff --git a/core/java/android/hardware/SystemSensorManager.java b/core/java/android/hardware/SystemSensorManager.java
index 9747f0d..14f67c5 100644
--- a/core/java/android/hardware/SystemSensorManager.java
+++ b/core/java/android/hardware/SystemSensorManager.java
@@ -93,17 +93,20 @@
     /** @hide */
     @Override
     protected boolean registerListenerImpl(SensorEventListener listener, Sensor sensor,
-            int delayUs, Handler handler, int maxBatchReportLatencyUs, int reservedFlags,
-            FlushCompleteListener flushCompleteListener) {
-        if (sensor == null) throw new IllegalArgumentException("sensor cannot be null");
-        if (listener == null) throw new IllegalArgumentException("listener cannot be null");
-        if (reservedFlags != 0) throw new IllegalArgumentException("reservedFlags should be zero");
-        if (delayUs < 0) throw new IllegalArgumentException("rateUs should be positive");
-        if (maxBatchReportLatencyUs < 0)
-            throw new IllegalArgumentException("maxBatchReportLatencyUs should be positive");
+            int delayUs, Handler handler, int maxBatchReportLatencyUs, int reservedFlags) {
+        if (listener == null || sensor == null) {
+            Log.e(TAG, "sensor or listener is null");
+            return false;
+        }
         // Trigger Sensors should use the requestTriggerSensor call.
-        if (Sensor.getReportingMode(sensor) == Sensor.REPORTING_MODE_ONE_SHOT)
-            throw new IllegalArgumentException("Trigger Sensors cannot use registerListener");
+        if (Sensor.getReportingMode(sensor) == Sensor.REPORTING_MODE_ONE_SHOT) {
+            Log.e(TAG, "Trigger Sensors should use the requestTriggerSensor.");
+            return false;
+        }
+        if (maxBatchReportLatencyUs < 0 || delayUs < 0) {
+            Log.e(TAG, "maxBatchReportLatencyUs and delayUs should be non-negative");
+            return false;
+        }
 
         // Invariants to preserve:
         // - one Looper per SensorEventListener
@@ -113,7 +116,7 @@
             SensorEventQueue queue = mSensorListeners.get(listener);
             if (queue == null) {
                 Looper looper = (handler != null) ? handler.getLooper() : mMainLooper;
-                queue = new SensorEventQueue(listener, looper, this, flushCompleteListener);
+                queue = new SensorEventQueue(listener, looper, this);
                 if (!queue.addSensor(sensor, delayUs, maxBatchReportLatencyUs, reservedFlags)) {
                     queue.dispose();
                     return false;
@@ -200,16 +203,17 @@
         }
     }
 
-    protected boolean flushImpl(Sensor sensor) {
-        if (sensor == null) throw new IllegalArgumentException("sensor cannot be null");
-        if(Sensor.getReportingMode(sensor) == Sensor.REPORTING_MODE_ONE_SHOT)
-            throw new IllegalArgumentException("Trigger Sensors cannot call flush");
+    protected boolean flushImpl(SensorEventListener listener) {
+        if (listener == null) throw new IllegalArgumentException("listener cannot be null");
 
-        FlushEventQueue queue = new FlushEventQueue(mMainLooper, this);
-        if (queue.flushSensor(sensor) != 0) {
-            return false;
+        synchronized (mSensorListeners) {
+            SensorEventQueue queue = mSensorListeners.get(listener);
+            if (queue == null) {
+                return false;
+            } else {
+                return (queue.flush() == 0);
+            }
         }
-        return true;
     }
 
     /*
@@ -224,7 +228,7 @@
                 int maxBatchReportLatencyUs, int reservedFlags);
         private static native int nativeDisableSensor(int eventQ, int handle);
         private static native void nativeDestroySensorEventQueue(int eventQ);
-        private static native int nativeFlushSensor(int eventQ, int handle);
+        private static native int nativeFlushSensor(int eventQ);
         private int nSensorEventQueue;
         private final SparseBooleanArray mActiveSensors = new SparseBooleanArray();
         protected final SparseIntArray mSensorAccuracies = new SparseIntArray();
@@ -291,10 +295,9 @@
             return false;
         }
 
-        public int flushSensor(Sensor sensor) {
+        public int flush() {
             if (nSensorEventQueue == 0) throw new NullPointerException();
-            if (sensor == null) throw new NullPointerException();
-            return nativeFlushSensor(nSensorEventQueue, sensor.getHandle());
+            return nativeFlushSensor(nSensorEventQueue);
         }
 
         public boolean hasSensors() {
@@ -347,14 +350,12 @@
 
     static final class SensorEventQueue extends BaseEventQueue {
         private final SensorEventListener mListener;
-        private final FlushCompleteListener mFlushCompleteListener;
         private final SparseArray<SensorEvent> mSensorsEvents = new SparseArray<SensorEvent>();
 
         public SensorEventQueue(SensorEventListener listener, Looper looper,
-                SystemSensorManager manager, FlushCompleteListener flushCompleteListener) {
+                SystemSensorManager manager) {
             super(looper, manager);
             mListener = listener;
-            mFlushCompleteListener = flushCompleteListener;
         }
 
         public void addSensorEvent(Sensor sensor) {
@@ -408,9 +409,9 @@
 
         @SuppressWarnings("unused")
         protected void dispatchFlushCompleteEvent(int handle) {
-            final Sensor sensor = sHandleToSensor.get(handle);
-            if (mFlushCompleteListener != null) {
-                mFlushCompleteListener.onFlushCompleted(sensor);
+            if (mListener instanceof SensorEventListener2) {
+                final Sensor sensor = sHandleToSensor.get(handle);
+                ((SensorEventListener2)mListener).onFlushCompleted(sensor);
             }
             return;
         }
@@ -464,30 +465,4 @@
         protected void dispatchFlushCompleteEvent(int handle) {
         }
     }
-
-    static final class FlushEventQueue extends BaseEventQueue {
-        public FlushEventQueue(Looper looper, SystemSensorManager manager) {
-            super(looper, manager);
-        }
-
-        @SuppressWarnings("unused")
-        @Override
-        protected void dispatchSensorEvent(int handle, float[] values, int accuracy,
-                long timestamp) {
-        }
-
-        @Override
-        @SuppressWarnings("unused")
-        protected void addSensorEvent(Sensor sensor) {
-        }
-
-        @Override
-        @SuppressWarnings("unused")
-        protected void removeSensorEvent(Sensor sensor) {
-        }
-
-        @SuppressWarnings("unused")
-        protected void dispatchFlushCompleteEvent(int handle) {
-        }
-    }
 }
diff --git a/core/java/android/net/ProxyProperties.java b/core/java/android/net/ProxyProperties.java
index 648a4b3..78ac75f 100644
--- a/core/java/android/net/ProxyProperties.java
+++ b/core/java/android/net/ProxyProperties.java
@@ -178,7 +178,7 @@
         // If PAC URL is present in either then they must be equal.
         // Other parameters will only be for fall back.
         if (!TextUtils.isEmpty(mPacFileUrl)) {
-            return mPacFileUrl.equals(p.getPacFileUrl());
+            return mPacFileUrl.equals(p.getPacFileUrl()) && mPort == p.mPort;
         }
         if (!TextUtils.isEmpty(p.getPacFileUrl())) {
             return false;
@@ -219,6 +219,7 @@
         if (mPacFileUrl != null) {
             dest.writeByte((byte)1);
             dest.writeString(mPacFileUrl);
+            dest.writeInt(mPort);
             return;
         } else {
             dest.writeByte((byte)0);
@@ -244,7 +245,9 @@
                 String host = null;
                 int port = 0;
                 if (in.readByte() != 0) {
-                    return new ProxyProperties(in.readString());
+                    String url = in.readString();
+                    int localPort = in.readInt();
+                    return new ProxyProperties(url, localPort);
                 }
                 if (in.readByte() != 0) {
                     host = in.readString();
diff --git a/core/java/com/android/internal/view/menu/ActionMenuPresenter.java b/core/java/com/android/internal/view/menu/ActionMenuPresenter.java
index 23ed019..44e7ec1 100644
--- a/core/java/com/android/internal/view/menu/ActionMenuPresenter.java
+++ b/core/java/com/android/internal/view/menu/ActionMenuPresenter.java
@@ -160,8 +160,7 @@
     public View getItemView(final MenuItemImpl item, View convertView, ViewGroup parent) {
         View actionView = item.getActionView();
         if (actionView == null || item.hasCollapsibleActionView()) {
-            // Don't recycle existing item views for action buttons; it interferes with transitions.
-            actionView = super.getItemView(item, null, parent);
+            actionView = super.getItemView(item, convertView, parent);
         }
         actionView.setVisibility(item.isActionViewExpanded() ? View.GONE : View.VISIBLE);
 
diff --git a/core/java/com/android/internal/widget/SubtitleView.java b/core/java/com/android/internal/widget/SubtitleView.java
index ccedf63..071193c 100644
--- a/core/java/com/android/internal/widget/SubtitleView.java
+++ b/core/java/com/android/internal/widget/SubtitleView.java
@@ -180,7 +180,9 @@
             mInnerPaddingX = (int) (size * INNER_PADDING_RATIO + 0.5f);
 
             mHasMeasurements = false;
-            forceLayout();
+
+            requestLayout();
+            invalidate();
         }
     }
 
@@ -189,7 +191,9 @@
             mTextPaint.setTypeface(typeface);
 
             mHasMeasurements = false;
-            forceLayout();
+
+            requestLayout();
+            invalidate();
         }
     }
 
@@ -198,7 +202,9 @@
             mAlignment = textAlignment;
 
             mHasMeasurements = false;
-            forceLayout();
+
+            requestLayout();
+            invalidate();
         }
     }
 
diff --git a/core/jni/android_hardware_SensorManager.cpp b/core/jni/android_hardware_SensorManager.cpp
index 4290a6e..793d1bf 100644
--- a/core/jni/android_hardware_SensorManager.cpp
+++ b/core/jni/android_hardware_SensorManager.cpp
@@ -220,9 +220,9 @@
     receiver->decStrong((void*)nativeInitSensorEventQueue);
 }
 
-static jint nativeFlushSensor(JNIEnv *env, jclass clazz, jint eventQ, jint handle) {
+static jint nativeFlushSensor(JNIEnv *env, jclass clazz, jint eventQ) {
     sp<Receiver> receiver(reinterpret_cast<Receiver *>(eventQ));
-    return receiver->getSensorEventQueue()->flushSensor(handle);
+    return receiver->getSensorEventQueue()->flush();
 }
 
 //----------------------------------------------------------------------------
@@ -255,7 +255,7 @@
             (void*)nativeDestroySensorEventQueue },
 
     {"nativeFlushSensor",
-            "(II)I",
+            "(I)I",
             (void*)nativeFlushSensor },
 };
 
diff --git a/core/res/res/drawable-hdpi/stat_sys_gps_on.png b/core/res/res/drawable-hdpi/stat_sys_gps_on.png
index cb8a1e8..e0f7740 100644
--- a/core/res/res/drawable-hdpi/stat_sys_gps_on.png
+++ b/core/res/res/drawable-hdpi/stat_sys_gps_on.png
Binary files differ
diff --git a/core/res/res/drawable-ldpi/stat_sys_gps_on.png b/core/res/res/drawable-ldpi/stat_sys_gps_on.png
index 8915c59..77776f5 100644
--- a/core/res/res/drawable-ldpi/stat_sys_gps_on.png
+++ b/core/res/res/drawable-ldpi/stat_sys_gps_on.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/stat_sys_gps_on.png b/core/res/res/drawable-mdpi/stat_sys_gps_on.png
index 2c98972..311a1de 100644
--- a/core/res/res/drawable-mdpi/stat_sys_gps_on.png
+++ b/core/res/res/drawable-mdpi/stat_sys_gps_on.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/stat_sys_gps_on.png b/core/res/res/drawable-xhdpi/stat_sys_gps_on.png
index a7408d4..8a6edfb 100644
--- a/core/res/res/drawable-xhdpi/stat_sys_gps_on.png
+++ b/core/res/res/drawable-xhdpi/stat_sys_gps_on.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/stat_sys_gps_on.png b/core/res/res/drawable-xxhdpi/stat_sys_gps_on.png
index 81fb04a..063f614 100755
--- a/core/res/res/drawable-xxhdpi/stat_sys_gps_on.png
+++ b/core/res/res/drawable-xxhdpi/stat_sys_gps_on.png
Binary files differ
diff --git a/docs/html/distribute/googleplay/spotlight/games.jd b/docs/html/distribute/googleplay/spotlight/games.jd
index 4e356db..1fbc03f 100644
--- a/docs/html/distribute/googleplay/spotlight/games.jd
+++ b/docs/html/distribute/googleplay/spotlight/games.jd
@@ -102,7 +102,7 @@
   width: 78px;
   float: left;
   margin: 12px 20px 30px 20px;"
-  src="//lh5.ggpht.com/l20dR2HYLV8vECoC35q_0NdfaAGTe4lZIFy_wCJRDqZjeQqSgneLRpXi3qOnnCaLXA=w124">
+  src="//lh4.ggpht.com/Q7mQJsdhulW4_s039R9aaRhQkGnyzLkhF00j5EnyhHOivijnyi7P7b5A8qG0xk1r-jQ=w124">
           
 <div style="list-style: none;height:100%;
   float: right;
diff --git a/docs/html/distribute/googleplay/spotlight/tablets.jd b/docs/html/distribute/googleplay/spotlight/tablets.jd
index cfea29a..7a98755 100644
--- a/docs/html/distribute/googleplay/spotlight/tablets.jd
+++ b/docs/html/distribute/googleplay/spotlight/tablets.jd
@@ -17,7 +17,90 @@
 expand their offering to include Android tablets.</p>
 
 
-<div style="margin-bottom:2em;"><!-- START STORY -->
+<div style="margin-bottom:2em;" id="rememberthemilk"><!-- START STORY -->
+
+<h3>Remember The Milk: Lifting installs with tablet design</h3>
+
+  <img alt="" class="screenshot thumbnail" style="-webkit-border-radius: 5px;
+            -moz-border-radius: 5px;
+            border-radius: 5px height:78px;
+            width: 78px;
+            float: left;
+            margin: 12px 20px 9px 20px;" src=
+            "//lh3.ggpht.com/xmnal18taauP2mjQFEhr1PhcItQ_W32IRuaD86IoL2U_4E-mfeKiliKtkISgOuA6Ln9n=w124">
+          
+  <div style="list-style: none;height:100%;
+  float: right;
+  border-top: 1px solid #9C0;
+  width: 220px;
+  margin: 4px 20px;padding: .5em;">
+  
+
+    <h5>About the app</h5> 
+    
+    
+    <ul>
+      <li><a href="//play.google.com/store/apps/details?id=com.rememberthemilk.MobileRTM">Remember The Milk</a></li>
+      <li>A feature-packed to-do list app; never forget the milk (or anything else) again</li>
+    </ul>
+
+    <h5>Tablet Results</h5> 
+
+    <ul>
+      <li>83% jump in tablet installs following update </li>
+      <li>Nexus 7 is most popular Android device for app </li>
+      <li>Single APK for phones and tablets</li>
+      </ul>
+    
+    <div style="padding:.5em 0 0 1em;">
+      <a href="//play.google.com/store/apps/details?id=com.rememberthemilk.MobileRTM">
+        <img alt="Android app on Google Play"
+         src="//developer.android.com/images/brand/en_generic_rgb_wo_45.png" />
+      </a>
+      
+    </div>
+  </div>
+
+  <div style="line-height:1.4em;">
+    <p style="margin-top:0;margin-bottom:12px;">When the Android tablet guidelines
+      came out in 2012, the team at Remember The Milk had already been thinking about
+      a redesign for their <a href="//play.google.com/store/apps/details?id=com.rememberthemilk.MobileRTM">feature-packed
+      to-do list app</a>. Omar Kilani, Co-founder of Remember The Milk, explains how
+      <a href="//blog.rememberthemilk.com/2013/04/the-all-new-remember-the-milk-for-android-and-tablets-too/">updating</a>
+      their app to meet the tablet guidelines lead to an 83% jump in tablet installs: </p>
+
+    <p>“We took this as an opportunity to think about how we were going to approach
+      Android tablets differently from a user experience perspective. The guidelines
+      were a helpful resource, and with the extra screen real estate tablets afford,
+      users have the opportunity to see all of their data in context and drill down
+      on more items. All of this is accomplished using a single APK on Play, even though
+      the phone and tablet versions each capture completely different use cases for us.”</p>
+
+    <p>“In the month after updating, we saw our tablet installs on Google Play jump 83%,
+      and the Nexus 7 is now the most popular Android device amongst our users. For us,
+      designing for tablets was an investment that has really paid off.”</p>
+
+    <p>The team also came out with a number of other goodies &mdash; including a new set of
+      widgets and richer notifications, and more ways to provide an immersive experience
+      for their users.</p>
+  </div>
+
+  <div style="clear:both;margin-top:30px;width:auto;">
+  
+    <img src="{@docRoot}images/distribute/rememberthemilk.png">
+
+    <div style="width:600px;margin-top:0px;padding:0 90px;">
+      <p class="image-caption"><span style="font-weight:500;">Tablet redesign led to lift
+      in installs</span>: Following the redesign of the Android app, in part to meet the tablet
+      design criteria, Remember The Milk saw an 83% increase in tablet installs.</p>
+    </div>
+
+  </div>
+
+</div> <!-- END STORY -->
+
+
+<div style="margin-bottom:2em;" id="mint"><!-- START STORY -->
 
 <h3>Mint: More screen real estate = more engagement</h3>
 
@@ -96,7 +179,7 @@
 
   <div style="clear:both;margin-top:40px;width:auto;">
   
-    <a href=""><img src="{@docRoot}images/distribute/mint.png"></a>
+    <img src="{@docRoot}images/distribute/mint.png">
 
     <div style="width:600px;margin-top:0px;padding:0 90px;">
       <p class="image-caption"><span style="font-weight:500;">Making the most of tablet screens</span>: Mint used the extra screen area on tablets to offer quick access to additional tools and information.</p>
@@ -184,7 +267,7 @@
 
   <div style="clear:both;margin-top:40px;width:auto;">
   
-    <a href=""><img src="{@docRoot}images/distribute/tinyvillage.png"></a>
+    <img src="{@docRoot}images/distribute/tinyvillage.png">
 
     <div style="width:600px;margin-top:0px;padding:0 90px;">
       <p class="image-caption"><span style="font-weight:500;">More monetization
@@ -268,7 +351,7 @@
 
   <div style="clear:both;margin-top:40px;width:auto;">
   
-    <a href=""><img src="{@docRoot}images/distribute/instapaper.png"></a>
+    <img src="{@docRoot}images/distribute/instapaper.png">
 
     <div style="width:600px;margin-top:0px;padding:0 90px;">
       <p class="image-caption"><span style="font-weight:500;">Popular with
diff --git a/docs/html/images/distribute/rememberthemilk.png b/docs/html/images/distribute/rememberthemilk.png
new file mode 100644
index 0000000..b170cf3
--- /dev/null
+++ b/docs/html/images/distribute/rememberthemilk.png
Binary files differ
diff --git a/docs/html/training/articles/security-tips.jd b/docs/html/training/articles/security-tips.jd
index 1ac56b9..54aebac 100644
--- a/docs/html/training/articles/security-tips.jd
+++ b/docs/html/training/articles/security-tips.jd
@@ -553,7 +553,7 @@
 or an explicit intent to a specific application component.</p>
 
 <p>Note that ordered broadcasts can be “consumed” by a recipient, so they
-may not be delivered to all applications.  If you are sending an intent that muse be delivered
+may not be delivered to all applications.  If you are sending an intent that must be delivered
 to a specific receiver, then you must use an explicit intent that declares the receiver
 by nameintent.</p>
 
diff --git a/packages/Keyguard/res/values-mcc262-mnc07/bools.xml b/packages/Keyguard/res/values-mcc262-mnc07/bools.xml
new file mode 100644
index 0000000..6cd4c55
--- /dev/null
+++ b/packages/Keyguard/res/values-mcc262-mnc07/bools.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2013 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<resources>
+    <!-- Carriers in this locale are sensitive to capitalization of carrier text. 
+         This makes the entire interface consistent by switching back to normal case. -->
+    <bool name="kg_use_all_caps">false</bool>
+</resources>
diff --git a/packages/Keyguard/src/com/android/keyguard/CameraWidgetFrame.java b/packages/Keyguard/src/com/android/keyguard/CameraWidgetFrame.java
index 146c092..7d1f24f 100644
--- a/packages/Keyguard/src/com/android/keyguard/CameraWidgetFrame.java
+++ b/packages/Keyguard/src/com/android/keyguard/CameraWidgetFrame.java
@@ -19,11 +19,13 @@
 import android.content.Context;
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.graphics.Color;
+import android.graphics.Paint;
 import android.graphics.Point;
 import android.graphics.Rect;
 import android.os.Handler;
 import android.os.SystemClock;
 import android.util.Log;
+import android.view.Gravity;
 import android.view.LayoutInflater;
 import android.view.MotionEvent;
 import android.view.View;
@@ -55,15 +57,17 @@
     private final WindowManager mWindowManager;
     private final Point mRenderedSize = new Point();
     private final int[] mTmpLoc = new int[2];
-    private final Rect mTmpRect = new Rect();
 
     private long mLaunchCameraStart;
     private boolean mActive;
     private boolean mTransitioning;
     private boolean mDown;
 
+    private final Rect mInsets = new Rect();
+
     private FixedSizeFrameLayout mPreview;
     private View mFullscreenPreview;
+    private View mFakeNavBar;
 
     private final Runnable mTransitionToCameraRunnable = new Runnable() {
         @Override
@@ -211,10 +215,11 @@
 
     private void render() {
         final View root = getRootView();
-        final int width = root.getWidth();
-        final int height = root.getHeight();
+        final int width = root.getWidth() - mInsets.right;    // leave room
+        final int height = root.getHeight() - mInsets.bottom; // for bars
         if (mRenderedSize.x == width && mRenderedSize.y == height) {
-            if (DEBUG) Log.d(TAG, String.format("Already rendered at size=%sx%s", width, height));
+            if (DEBUG) Log.d(TAG, String.format("Already rendered at size=%sx%s %d%%",
+                    width, height, (int)(100*mPreview.getScaleX())));
             return;
         }
         if (width == 0 || height == 0) {
@@ -246,8 +251,8 @@
         mPreview.setTranslationY(pvTransY);
 
         mRenderedSize.set(width, height);
-        if (DEBUG) Log.d(TAG, String.format("Rendered camera widget size=%sx%s instance=%s",
-                width, height, instanceId()));
+        if (DEBUG) Log.d(TAG, String.format("Rendered camera widget size=%sx%s %d%% instance=%s",
+                width, height, (int)(100*mPreview.getScaleX()), instanceId()));
     }
 
     private void transitionToCamera() {
@@ -257,24 +262,34 @@
 
         enableWindowExitAnimation(false);
 
+        final int navHeight = mInsets.bottom;
+        final int navWidth = mInsets.right;
+
         mPreview.getLocationInWindow(mTmpLoc);
         final float pvHeight = mPreview.getHeight() * mPreview.getScaleY();
         final float pvCenter = mTmpLoc[1] + pvHeight / 2f;
 
         final ViewGroup root = (ViewGroup) getRootView();
+
+        if (DEBUG) {
+            Log.d(TAG, "root = " + root.getLeft() + "," + root.getTop() + " "
+                    + root.getWidth() + "x" + root.getHeight());
+        }
+
         if (mFullscreenPreview == null) {
             mFullscreenPreview = getPreviewWidget(mContext, mWidgetInfo);
             mFullscreenPreview.setClickable(false);
-            root.addView(mFullscreenPreview);
+            root.addView(mFullscreenPreview, new FrameLayout.LayoutParams(
+                        root.getWidth() - navWidth,
+                        root.getHeight() - navHeight));
         }
 
-        root.getWindowVisibleDisplayFrame(mTmpRect);
-        final float fsHeight = mTmpRect.height();
-        final float fsCenter = mTmpRect.top + fsHeight / 2;
+        final float fsHeight = root.getHeight() - navHeight;
+        final float fsCenter = root.getTop() + fsHeight / 2;
 
-        final float fsScaleY = pvHeight / fsHeight;
+        final float fsScaleY = mPreview.getScaleY();
         final float fsTransY = pvCenter - fsCenter;
-        final float fsScaleX = mPreview.getScaleX();
+        final float fsScaleX = fsScaleY;
 
         mPreview.setVisibility(View.GONE);
         mFullscreenPreview.setVisibility(View.VISIBLE);
@@ -290,6 +305,36 @@
             .setDuration(WIDGET_ANIMATION_DURATION)
             .withEndAction(mPostTransitionToCameraEndAction)
             .start();
+
+        if (navHeight > 0 || navWidth > 0) {
+            final boolean atBottom = navHeight > 0;
+            if (mFakeNavBar == null) {
+                mFakeNavBar = new View(mContext);
+                mFakeNavBar.setBackgroundColor(Color.BLACK);
+                root.addView(mFakeNavBar, new FrameLayout.LayoutParams(
+                            atBottom ? FrameLayout.LayoutParams.MATCH_PARENT
+                                     : navWidth,
+                            atBottom ? navHeight
+                                     : FrameLayout.LayoutParams.MATCH_PARENT,
+                            atBottom ? Gravity.BOTTOM|Gravity.FILL_HORIZONTAL
+                                     : Gravity.RIGHT|Gravity.FILL_VERTICAL));
+                mFakeNavBar.setPivotY(navHeight);
+                mFakeNavBar.setPivotX(navWidth);
+            }
+            mFakeNavBar.setAlpha(0f);
+            if (atBottom) {
+                mFakeNavBar.setScaleY(0.5f);
+            } else {
+                mFakeNavBar.setScaleX(0.5f);
+            }
+            mFakeNavBar.setVisibility(View.VISIBLE);
+            mFakeNavBar.animate()
+                .alpha(1f)
+                .scaleY(1f)
+                .scaleY(1f)
+                .setDuration(WIDGET_ANIMATION_DURATION)
+                .start();
+        }
         mCallbacks.onLaunchingCamera();
     }
 
@@ -397,6 +442,10 @@
             mFullscreenPreview.animate().cancel();
             mFullscreenPreview.setVisibility(View.GONE);
         }
+        if (mFakeNavBar != null) {
+            mFakeNavBar.animate().cancel();
+            mFakeNavBar.setVisibility(View.GONE);
+        }
         enableWindowExitAnimation(true);
     }
 
@@ -404,6 +453,10 @@
     protected void onSizeChanged(int w, int h, int oldw, int oldh) {
         if (DEBUG) Log.d(TAG, String.format("onSizeChanged new=%sx%s old=%sx%s at %s",
                 w, h, oldw, oldh, SystemClock.uptimeMillis()));
+        if ((w != oldw && oldw > 0) || (h != oldh && oldh > 0)) {
+            // we can't trust the old geometry anymore; force a re-render
+            mRenderedSize.x = mRenderedSize.y = -1;
+        }
         mHandler.post(mRenderRunnable);
         super.onSizeChanged(w, h, oldw, oldh);
     }
@@ -454,4 +507,9 @@
     private String instanceId() {
         return Integer.toHexString(hashCode());
     }
+
+    public void setInsets(Rect insets) {
+        if (DEBUG) Log.d(TAG, "setInsets: " + insets);
+        mInsets.set(insets);
+    }
 }
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardHostView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardHostView.java
index c4be72f..ef3d712 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardHostView.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardHostView.java
@@ -1454,6 +1454,9 @@
         mInsets.set(insets);
         if (mSlidingChallengeLayout != null) mSlidingChallengeLayout.setInsets(mInsets);
         if (mMultiPaneChallengeLayout != null) mMultiPaneChallengeLayout.setInsets(mInsets);
+
+        final CameraWidgetFrame cameraWidget = findCameraPage();
+        if (cameraWidget != null) cameraWidget.setInsets(mInsets);
     }
 
     @Override
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardViewManager.java b/packages/Keyguard/src/com/android/keyguard/KeyguardViewManager.java
index 58ca0b0..d37aaaf 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardViewManager.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardViewManager.java
@@ -85,6 +85,7 @@
         public void onSetBackground(Bitmap bmp) {
             mKeyguardHost.setCustomBackground(bmp != null ?
                     new BitmapDrawable(mContext.getResources(), bmp) : null);
+            updateShowWallpaper(bmp == null);
         }
     };
 
@@ -379,6 +380,16 @@
         mViewManager.updateViewLayout(mKeyguardHost, mWindowLayoutParams);
     }
 
+    void updateShowWallpaper(boolean show) {
+        if (show) {
+            mWindowLayoutParams.flags |= WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
+        } else {
+            mWindowLayoutParams.flags &= ~WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
+        }
+
+        mViewManager.updateViewLayout(mKeyguardHost, mWindowLayoutParams);
+    }
+
     public void setNeedsInput(boolean needsInput) {
         mNeedsInput = needsInput;
         if (mWindowLayoutParams != null) {
@@ -489,6 +500,7 @@
                             lastView.cleanUp();
                             // Let go of any large bitmaps.
                             mKeyguardHost.setCustomBackground(null);
+                            updateShowWallpaper(true);
                             mKeyguardHost.removeView(lastView);
                         }
                     }
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardViewStateManager.java b/packages/Keyguard/src/com/android/keyguard/KeyguardViewStateManager.java
index d1862cd..7039218 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardViewStateManager.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardViewStateManager.java
@@ -17,12 +17,14 @@
 
 import android.os.Handler;
 import android.os.Looper;
+import android.util.Log;
 import android.view.View;
 
 public class KeyguardViewStateManager implements
         SlidingChallengeLayout.OnChallengeScrolledListener,
         ChallengeLayout.OnBouncerStateChangedListener {
 
+    private static final String TAG = "KeyguardViewStateManager";
     private KeyguardWidgetPager mKeyguardWidgetPager;
     private ChallengeLayout mChallengeLayout;
     private KeyguardHostView mKeyguardHostView;
@@ -100,18 +102,20 @@
     }
 
     public void fadeOutSecurity(int duration) {
-        ((View) mKeyguardSecurityContainer).animate().alpha(0).setDuration(duration);
+        ((View) mKeyguardSecurityContainer).animate().alpha(0f).setDuration(duration).start();
     }
 
     public void fadeInSecurity(int duration) {
-        ((View) mKeyguardSecurityContainer).animate().alpha(1f).setDuration(duration);
+        ((View) mKeyguardSecurityContainer).animate().alpha(1f).setDuration(duration).start();
     }
 
     public void onPageBeginMoving() {
         if (mChallengeLayout.isChallengeOverlapping() &&
                 mChallengeLayout instanceof SlidingChallengeLayout) {
             SlidingChallengeLayout scl = (SlidingChallengeLayout) mChallengeLayout;
-            scl.fadeOutChallenge();
+            if (!mKeyguardWidgetPager.isWarping()) {
+                scl.fadeOutChallenge();
+            }
             mPageIndexOnPageBeginMoving = mKeyguardWidgetPager.getCurrentPage();
         }
         // We use mAppWidgetToShow to show a particular widget after you add it--
@@ -133,7 +137,9 @@
     public void onPageSwitching(View newPage, int newPageIndex) {
         if (mKeyguardWidgetPager != null && mChallengeLayout instanceof SlidingChallengeLayout) {
             boolean isCameraPage = newPage instanceof CameraWidgetFrame;
-            ((SlidingChallengeLayout) mChallengeLayout).setChallengeInteractive(!isCameraPage);
+            SlidingChallengeLayout scl = (SlidingChallengeLayout) mChallengeLayout;
+            scl.setChallengeInteractive(!isCameraPage);
+            if (isCameraPage) scl.fadeOutChallenge();
         }
 
         // If the page we're settling to is the same as we started on, and the action of
@@ -174,13 +180,15 @@
     }
 
     public void onPageBeginWarp() {
-        // fadeOutSecurity(WARP_FADE_DURATION);
-        // mKeyguardWidgetPager.showNonWarpViews(WARP_FADE_DURATION, false);
+        fadeOutSecurity(SlidingChallengeLayout.CHALLENGE_FADE_OUT_DURATION);
+        View frame = mKeyguardWidgetPager.getPageAt(mKeyguardWidgetPager.getPageWarpIndex());
+        ((KeyguardWidgetFrame)frame).showFrame(this);
     }
 
     public void onPageEndWarp() {
-        // fadeInSecurity(WARP_FADE_DURATION);
-        // mKeyguardWidgetPager.showNonWarpViews(WARP_FADE_DURATION, true);
+        fadeInSecurity(SlidingChallengeLayout.CHALLENGE_FADE_IN_DURATION);
+        View frame = mKeyguardWidgetPager.getPageAt(mKeyguardWidgetPager.getPageWarpIndex());
+        ((KeyguardWidgetFrame)frame).hideFrame(this);
     }
 
     private int getChallengeTopRelativeToFrame(KeyguardWidgetFrame frame, int top) {
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardWidgetPager.java b/packages/Keyguard/src/com/android/keyguard/KeyguardWidgetPager.java
index f8857ab..704af6e 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardWidgetPager.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardWidgetPager.java
@@ -188,11 +188,13 @@
 
     @Override
     public void onPageBeginWarp() {
+        showOutlinesAndSidePages();
         mViewStateManager.onPageBeginWarp();
     }
 
     @Override
     public void onPageEndWarp() {
+        hideOutlinesAndSidePages();
         mViewStateManager.onPageEndWarp();
     }
 
@@ -495,7 +497,7 @@
     }
 
     public float getAlphaForPage(int screenCenter, int index, boolean showSidePages) {
-        if (getPageWarpIndex() != -1) {
+        if (isWarping()) {
             return index == getPageWarpIndex() ? 1.0f : 0.0f;
         }
         if (showSidePages) {
@@ -949,17 +951,17 @@
                     // to keep event dispatch happy.
                     mCameraEventInProgress = true;
                     userActivity();
-                    startWarp(cameraPage);
+                    startPageWarp(cameraPage);
                     break;
                 case MotionEvent.ACTION_UP:
                 case MotionEvent.ACTION_CANCEL:
                     mCameraEventInProgress = false;
-                    endWarp = true;
+                    endWarp = isWarping();
                     break;
             }
             dispatchTouchEvent(event);
             // This has to happen after the event has been handled by the real widget pager
-            if (endWarp) endWarp();
+            if (endWarp) stopPageWarp();
         }
         endCameraEvent();
     }
diff --git a/packages/Keyguard/src/com/android/keyguard/PagedView.java b/packages/Keyguard/src/com/android/keyguard/PagedView.java
index 666227c..6cf6953 100644
--- a/packages/Keyguard/src/com/android/keyguard/PagedView.java
+++ b/packages/Keyguard/src/com/android/keyguard/PagedView.java
@@ -47,6 +47,7 @@
 import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.AccessibilityManager;
 import android.view.accessibility.AccessibilityNodeInfo;
+import android.view.animation.AccelerateInterpolator;
 import android.view.animation.AnimationUtils;
 import android.view.animation.DecelerateInterpolator;
 import android.view.animation.Interpolator;
@@ -60,12 +61,13 @@
  * sequential list of "pages"
  */
 public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarchyChangeListener {
+    private static final int WARP_SNAP_DURATION = 160;
     private static final String TAG = "WidgetPagedView";
     private static final boolean DEBUG = false;
     private static final boolean DEBUG_WARP = false;
     protected static final int INVALID_PAGE = -1;
-    private static final int WARP_PEEK_ANIMATION_DURATION = 250;
-    private static final float WARP_ANIMATE_AMOUNT = -40.0f; // in dip
+    private static final int WARP_PEEK_ANIMATION_DURATION = 150;
+    private static final float WARP_ANIMATE_AMOUNT = -75.0f; // in dip
 
     // the min drag distance for a fling to register, to prevent random page shifts
     private static final int MIN_LENGTH_FOR_FLING = 25;
@@ -261,6 +263,8 @@
 
     private boolean mIsCameraEvent;
     private float mWarpPeekAmount;
+    private boolean mAnimatingWarp; // true while warped page is being animated
+    private boolean mFingerDown;
 
     public interface PageSwitchListener {
         void onPageSwitching(View newPage, int newPageIndex);
@@ -484,7 +488,7 @@
         if (DEBUG_WARP) Log.v(TAG, "pageBeginMoving(" + mIsPageMoving + ")");
         if (!mIsPageMoving) {
             mIsPageMoving = true;
-            if (mPageWarpIndex != -1) {
+            if (isWarping()) {
                 onPageBeginWarp();
                 if (mPageSwapIndex != -1) {
                     swapPages(mPageSwapIndex, mPageWarpIndex);
@@ -498,12 +502,12 @@
         if (DEBUG_WARP) Log.v(TAG, "pageEndMoving(" + mIsPageMoving + ")");
         if (mIsPageMoving) {
             mIsPageMoving = false;
-            if (mPageWarpIndex != -1) {
+            if (isWarping()) {
                 if (mPageSwapIndex != -1) {
                     swapPages(mPageSwapIndex, mPageWarpIndex);
-                    resetPageWarp();
                 }
                 onPageEndWarp();
+                resetPageWarp();
             }
             onPageEndMoving();
         }
@@ -1124,8 +1128,8 @@
             }
 
             case MotionEvent.ACTION_DOWN: {
-                if (mIsCameraEvent) {
-                    animateWarpPageOnScreen();
+                if (mIsCameraEvent && !mAnimatingWarp) {
+                    animateWarpPageOnScreen("interceptTouch(): DOWN");
                 }
                 // Remember where the motion event started
                 saveDownState(ev);
@@ -1219,6 +1223,8 @@
         mTotalMotionX = 0;
         mActivePointerId = ev.getPointerId(0);
 
+        mFingerDown = true;
+
         // Determine if the down event is within the threshold to be an edge swipe
         int leftEdgeBoundary = getViewportOffsetX() + mEdgeSwipeRegionSize;
         int rightEdgeBoundary = getMeasuredWidth() - getViewportOffsetX() - mEdgeSwipeRegionSize;
@@ -1393,8 +1399,10 @@
 
             if (mTouchState == TOUCH_STATE_SCROLLING) {
                 pageBeginMoving();
-            } else {
-                animateWarpPageOnScreen();
+            }
+
+            if (mIsCameraEvent && !mAnimatingWarp) {
+                animateWarpPageOnScreen("onTouch(): DOWN");
             }
             break;
 
@@ -1571,7 +1579,8 @@
                 // move to the left and fling to the right will register as a fling to the right.
                 if (((isSignificantMove && deltaX > 0 && !isFling) ||
                         (isFling && velocityX > 0)) && mCurrentPage > 0) {
-                    finalPage = returnToOriginalPage ? mCurrentPage : mCurrentPage - 1;
+                    finalPage = returnToOriginalPage || isWarping()
+                            ? mCurrentPage : mCurrentPage - 1;
                     snapToPageWithVelocity(finalPage, velocityX);
                 } else if (((isSignificantMove && deltaX < 0 && !isFling) ||
                         (isFling && velocityX < 0)) &&
@@ -1661,6 +1670,7 @@
         setTouchState(TOUCH_STATE_REST);
         mActivePointerId = INVALID_POINTER;
         mDownEventOnEdge = false;
+        mFingerDown = false;
     }
 
     protected void onUnhandledTap(MotionEvent ev) {}
@@ -1790,7 +1800,14 @@
     }
 
     protected void snapToDestination() {
-        snapToPage(getPageNearestToCenterOfScreen(), PAGE_SNAP_ANIMATION_DURATION);
+        if (isWarping()) {
+            cancelWarpAnimation("snapToDestination");
+        }
+        snapToPage(getPageNearestToCenterOfScreen(), getPageSnapDuration());
+    }
+
+    private int getPageSnapDuration() {
+        return isWarping() ? WARP_SNAP_DURATION : PAGE_SNAP_ANIMATION_DURATION;
     }
 
     private static class ScrollInterpolator implements Interpolator {
@@ -1817,6 +1834,10 @@
         whichPage = Math.max(0, Math.min(whichPage, getChildCount() - 1));
         int halfScreenSize = getViewportWidth() / 2;
 
+        if (isWarping()) {
+            cancelWarpAnimation("snapToPageWithVelocity");
+        }
+
         if (DEBUG) Log.d(TAG, "snapToPage.getChildOffset(): " + getChildOffset(whichPage));
         if (DEBUG) Log.d(TAG, "snapToPageWithVelocity.getRelativeChildOffset(): "
                 + getViewportWidth() + ", " + getChildWidth(whichPage));
@@ -1827,7 +1848,7 @@
         if (Math.abs(velocity) < mMinFlingVelocity) {
             // If the velocity is low enough, then treat this more as an automatic page advance
             // as opposed to an apparent physical response to flinging
-            snapToPage(whichPage, PAGE_SNAP_ANIMATION_DURATION);
+            snapToPage(whichPage, getPageSnapDuration());
             return;
         }
 
@@ -1851,10 +1872,10 @@
     }
 
     protected void snapToPage(int whichPage) {
-        snapToPage(whichPage, PAGE_SNAP_ANIMATION_DURATION);
+        snapToPage(whichPage, getPageSnapDuration());
     }
     protected void snapToPageImmediately(int whichPage) {
-        snapToPage(whichPage, PAGE_SNAP_ANIMATION_DURATION, true);
+        snapToPage(whichPage, getPageSnapDuration(), true);
     }
 
     protected void snapToPage(int whichPage, int duration) {
@@ -1884,8 +1905,8 @@
             mNextPage = whichPage;
         }
 
-        if (mPageWarpIndex != -1) {
-            animateWarpPageOffScreen();
+        if (isWarping()) {
+            onPageEndWarp();
             resetPageWarp();
         }
 
@@ -1918,6 +1939,10 @@
         invalidate();
     }
 
+    protected boolean isWarping() {
+        return mPageWarpIndex != -1;
+    }
+
     public void scrollLeft() {
         if (mScroller.isFinished()) {
             if (mCurrentPage > 0) snapToPage(mCurrentPage - 1);
@@ -2650,21 +2675,53 @@
         mIsCameraEvent = false;
     }
 
-    private void animateWarpPageOnScreen() {
-        if (DEBUG_WARP) Log.v(TAG, "animateWarpPageOnScreen()");
-        if (mPageWarpIndex != -1) {
+    AnimatorListenerAdapter mFinishWarpAnimationListener = new AnimatorListenerAdapter() {
+        @Override
+        public void onAnimationEnd(Animator animation) {
+            mAnimatingWarp = false;
+            if (!mFingerDown) {
+                animateWarpPageOffScreen("animation end", true);
+            }
+        }
+    };
+
+    private void cancelWarpAnimation(String msg) {
+        if (DEBUG_WARP) Log.v(TAG, "cancelWarpAnimation(" + msg + ")");
+        // We're done with the animation, let the scroller take over the positioning
+        KeyguardWidgetFrame v = (KeyguardWidgetFrame) getPageAt(mPageWarpIndex);
+        v.animate().cancel();
+        v.setTranslationX(0f);
+        scrollBy((int) Math.round(v.getTranslationX() - mWarpPeekAmount), 0);
+    }
+
+    private void animateWarpPageOnScreen(String reason) {
+        if (DEBUG_WARP) Log.v(TAG, "animateWarpPageOnScreen(" + reason + ")");
+        if (isWarping()) {
+            onPageBeginWarp();
             KeyguardWidgetFrame v = (KeyguardWidgetFrame) getPageAt(mPageWarpIndex);
             if (DEBUG_WARP) Log.v(TAG, "moving page on screen: Tx=" + v.getTranslationX());
-            v.animate().translationX(mWarpPeekAmount).setDuration(WARP_PEEK_ANIMATION_DURATION);
+            DecelerateInterpolator interp = new DecelerateInterpolator(1.5f);
+            v.animate().translationX(mWarpPeekAmount)
+                    .setInterpolator(interp)
+                    .setDuration(WARP_PEEK_ANIMATION_DURATION)
+                    .setListener(mFinishWarpAnimationListener);
+            mAnimatingWarp = true;
         }
     }
 
-    private void animateWarpPageOffScreen() {
-        if (DEBUG_WARP) Log.v(TAG, "animateWarpPageOffScreen()");
-        if (mPageWarpIndex != -1) {
+    private void animateWarpPageOffScreen(String reason, boolean animate) {
+        if (DEBUG_WARP) Log.v(TAG, "animateWarpPageOffScreen(" + reason + " anim:" + animate + ")");
+        if (isWarping()) {
+            onPageEndWarp();
             KeyguardWidgetFrame v = (KeyguardWidgetFrame) getPageAt(mPageWarpIndex);
             if (DEBUG_WARP) Log.v(TAG, "moving page off screen: Tx=" + v.getTranslationX());
-            v.animate().translationX(0.0f).setDuration(WARP_PEEK_ANIMATION_DURATION);
+            AccelerateInterpolator interp = new AccelerateInterpolator(1.5f);
+            v.animate().translationX(0.0f)
+                    .setInterpolator(interp)
+                    .setDuration(animate ? WARP_PEEK_ANIMATION_DURATION : 0)
+                    .setListener(null);
+        } else {
+            if (DEBUG_WARP) Log.e(TAG, "animateWarpPageOffScreen(): not warping", new Exception());
         }
     }
 
@@ -2681,7 +2738,7 @@
         }
     }
 
-    public void startWarp(int pageIndex) {
+    public void startPageWarp(int pageIndex) {
         if (DEBUG_WARP) Log.v(TAG, "START WARP");
         if (pageIndex != mCurrentPage + 1) {
             mPageSwapIndex = mCurrentPage + 1;
@@ -2693,7 +2750,7 @@
         return mPageWarpIndex;
     }
 
-    public void endWarp() {
+    public void stopPageWarp() {
         if (DEBUG_WARP) Log.v(TAG, "END WARP");
         // mPageSwapIndex is reset in snapToPage() after the scroll animation completes
     }
diff --git a/packages/Keyguard/src/com/android/keyguard/SlidingChallengeLayout.java b/packages/Keyguard/src/com/android/keyguard/SlidingChallengeLayout.java
index 5e7816c..1036c83 100644
--- a/packages/Keyguard/src/com/android/keyguard/SlidingChallengeLayout.java
+++ b/packages/Keyguard/src/com/android/keyguard/SlidingChallengeLayout.java
@@ -88,8 +88,8 @@
     public static final int SCROLL_STATE_SETTLING = 2;
     public static final int SCROLL_STATE_FADING = 3;
 
-    private static final int CHALLENGE_FADE_OUT_DURATION = 100;
-    private static final int CHALLENGE_FADE_IN_DURATION = 160;
+    public static final int CHALLENGE_FADE_OUT_DURATION = 100;
+    public static final int CHALLENGE_FADE_IN_DURATION = 160;
 
     private static final int MAX_SETTLE_DURATION = 600; // ms
 
diff --git a/packages/PrintSpooler/res/layout/print_job_config_activity_container.xml b/packages/PrintSpooler/res/layout/print_job_config_activity_container.xml
index 98b5cfe..d503216 100644
--- a/packages/PrintSpooler/res/layout/print_job_config_activity_container.xml
+++ b/packages/PrintSpooler/res/layout/print_job_config_activity_container.xml
@@ -15,9 +15,12 @@
 -->
 
 <com.android.printspooler.PrintDialogFrame xmlns:android="http://schemas.android.com/apk/res/android"
-    android:id="@+id/content_container"
-    android:layout_width="wrap_content"
-    android:layout_height="wrap_content"
-    android:layout_gravity="center"
-    android:background="@color/container_background">
+    android:layout_width="fill_parent"
+    android:layout_height="fill_parent">
+    <FrameLayout
+        android:id="@+id/content_container"
+        android:layout_width="fill_parent"
+        android:layout_height="fill_parent"
+        android:background="@color/container_background">
+    </FrameLayout>
 </com.android.printspooler.PrintDialogFrame>
diff --git a/packages/PrintSpooler/res/values-be/arrays.xml b/packages/PrintSpooler/res/values-be/arrays.xml
new file mode 100644
index 0000000..d40278c
--- /dev/null
+++ b/packages/PrintSpooler/res/values-be/arrays.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2013 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<resources>
+
+    <string-array name="pdf_printer_media_sizes" translatable="false">
+        <item>NA_LETTER</item>
+        <item>NA_GOVT_LETTER</item>
+        <item>NA_LEGAL</item>
+        <item>NA_JUNIOR_LEGAL</item>
+        <item>NA_LEDGER</item>
+        <item>NA_TABLOID</item>
+        <item>NA_INDEX_3X5</item>
+        <item>NA_INDEX_4X6</item>
+        <item>NA_INDEX_5X8</item>
+        <item>NA_MONARCH</item>
+        <item>NA_QUARTO</item>
+        <item>NA_FOOLSCAP</item>
+    </string-array>
+
+</resources>
diff --git a/packages/PrintSpooler/res/values-ca/arrays.xml b/packages/PrintSpooler/res/values-ca/arrays.xml
new file mode 100644
index 0000000..d40278c
--- /dev/null
+++ b/packages/PrintSpooler/res/values-ca/arrays.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2013 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<resources>
+
+    <string-array name="pdf_printer_media_sizes" translatable="false">
+        <item>NA_LETTER</item>
+        <item>NA_GOVT_LETTER</item>
+        <item>NA_LEGAL</item>
+        <item>NA_JUNIOR_LEGAL</item>
+        <item>NA_LEDGER</item>
+        <item>NA_TABLOID</item>
+        <item>NA_INDEX_3X5</item>
+        <item>NA_INDEX_4X6</item>
+        <item>NA_INDEX_5X8</item>
+        <item>NA_MONARCH</item>
+        <item>NA_QUARTO</item>
+        <item>NA_FOOLSCAP</item>
+    </string-array>
+
+</resources>
diff --git a/packages/PrintSpooler/res/values-ca/donottranslate.xml b/packages/PrintSpooler/res/values-ca/donottranslate.xml
new file mode 100644
index 0000000..7537aa5
--- /dev/null
+++ b/packages/PrintSpooler/res/values-ca/donottranslate.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2013 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<resources>
+
+    <string name="mediasize_default">NA_LETTER</string>
+    <string name="mediasize_standard">@string/mediasize_standard_north_america</string>
+
+</resources>
diff --git a/packages/PrintSpooler/res/values-es-rUS/arrays.xml b/packages/PrintSpooler/res/values-es-rUS/arrays.xml
new file mode 100644
index 0000000..d40278c
--- /dev/null
+++ b/packages/PrintSpooler/res/values-es-rUS/arrays.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2013 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<resources>
+
+    <string-array name="pdf_printer_media_sizes" translatable="false">
+        <item>NA_LETTER</item>
+        <item>NA_GOVT_LETTER</item>
+        <item>NA_LEGAL</item>
+        <item>NA_JUNIOR_LEGAL</item>
+        <item>NA_LEDGER</item>
+        <item>NA_TABLOID</item>
+        <item>NA_INDEX_3X5</item>
+        <item>NA_INDEX_4X6</item>
+        <item>NA_INDEX_5X8</item>
+        <item>NA_MONARCH</item>
+        <item>NA_QUARTO</item>
+        <item>NA_FOOLSCAP</item>
+    </string-array>
+
+</resources>
diff --git a/packages/PrintSpooler/res/values-ja/arrays.xml b/packages/PrintSpooler/res/values-ja/arrays.xml
new file mode 100644
index 0000000..3187cbe
--- /dev/null
+++ b/packages/PrintSpooler/res/values-ja/arrays.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2013 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<resources>
+
+    <string-array name="pdf_printer_media_sizes" translatable="false">
+        <item>JIS_B10</item>
+        <item>JIS_B9</item>
+        <item>JIS_B8</item>
+        <item>JIS_B7</item>
+        <item>JIS_B6</item>
+        <item>JIS_B5</item>
+        <item>JIS_B4</item>
+        <item>JIS_B3</item>
+        <item>JIS_B2</item>
+        <item>JIS_B1</item>
+        <item>JIS_B0</item>
+        <item>JIS_EXEC</item>
+        <item>JPN_CHOU4</item>
+        <item>JPN_CHOU3</item>
+        <item>JPN_CHOU2</item>
+        <item>JPN_HAGAKI</item>
+        <item>JPN_OUFUKU</item>
+        <item>JPN_KAHU</item>
+        <item>JPN_KAKU2</item>
+        <item>JPN_YOU4</item>
+    </string-array>
+
+</resources>
diff --git a/packages/PrintSpooler/res/values-zh-rCN/arrays.xml b/packages/PrintSpooler/res/values-zh-rCN/arrays.xml
new file mode 100644
index 0000000..4fc75db
--- /dev/null
+++ b/packages/PrintSpooler/res/values-zh-rCN/arrays.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2013 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<resources>
+
+    <string-array name="pdf_printer_media_sizes" translatable="false">
+        <item>ROC_8K</item>
+        <item>ROC_16K</item>
+        <item>PRC_1</item>
+        <item>PRC_2</item>
+        <item>PRC_3</item>
+        <item>PRC_4</item>
+        <item>PRC_5</item>
+        <item>PRC_6</item>
+        <item>PRC_7</item>
+        <item>PRC_8</item>
+        <item>PRC_9</item>
+        <item>PRC_10</item>
+        <item>PRC_16K</item>
+        <item>OM_PA_KAI</item>
+        <item>OM_DAI_PA_KAI</item>
+        <item>OM_JUURO_KU_KAI</item>
+    </string-array>
+
+</resources>
diff --git a/packages/PrintSpooler/src/com/android/printspooler/PrintDialogFrame.java b/packages/PrintSpooler/src/com/android/printspooler/PrintDialogFrame.java
index 6dd8aa0..c1c4d21 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/PrintDialogFrame.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/PrintDialogFrame.java
@@ -24,6 +24,8 @@
 
     public final int mMaxWidth;
 
+    public int mHeight;
+
     public PrintDialogFrame(Context context, AttributeSet attrs) {
         super(context, attrs);
         mMaxWidth = context.getResources().getDimensionPixelSize(
@@ -32,13 +34,36 @@
 
     @Override
     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
-        final int widthMode = MeasureSpec.getMode(widthMeasureSpec);
-        if (widthMode == MeasureSpec.AT_MOST) {
-            final int receivedWidth = MeasureSpec.getSize(widthMeasureSpec);
-            final int computedWidth = Math.min(mMaxWidth, receivedWidth);
-            widthMeasureSpec = MeasureSpec.makeMeasureSpec(computedWidth,
-                    MeasureSpec.EXACTLY);
-        }
         super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+
+        int measuredWidth  = getMeasuredWidth();
+        final int widthMode = MeasureSpec.getMode(widthMeasureSpec);
+        switch (widthMode) {
+            case MeasureSpec.UNSPECIFIED: {
+                measuredWidth = mMaxWidth;
+            } break;
+
+            case MeasureSpec.AT_MOST: {
+                final int receivedWidth = MeasureSpec.getSize(widthMeasureSpec);
+                measuredWidth = Math.min(mMaxWidth, receivedWidth);
+            } break;
+        }
+
+        mHeight = Math.max(mHeight, getMeasuredHeight());
+
+        int measuredHeight  = getMeasuredHeight();
+        final int heightMode = MeasureSpec.getMode(heightMeasureSpec);
+        switch (heightMode) {
+            case MeasureSpec.UNSPECIFIED: {
+                measuredHeight = mHeight;
+            } break;
+
+             case MeasureSpec.AT_MOST: {
+                final int receivedHeight = MeasureSpec.getSize(heightMeasureSpec);
+                measuredHeight = Math.min(mHeight, receivedHeight);
+            } break;
+        }
+
+        setMeasuredDimension(measuredWidth, measuredHeight);
     }
 }
diff --git a/packages/PrintSpooler/src/com/android/printspooler/PrintJobConfigActivity.java b/packages/PrintSpooler/src/com/android/printspooler/PrintJobConfigActivity.java
index d6ebc2d..2922dd1 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/PrintJobConfigActivity.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/PrintJobConfigActivity.java
@@ -59,12 +59,14 @@
 import android.util.ArrayMap;
 import android.util.AttributeSet;
 import android.util.Log;
+import android.view.Gravity;
 import android.view.KeyEvent;
 import android.view.MotionEvent;
 import android.view.View;
 import android.view.View.MeasureSpec;
 import android.view.View.OnAttachStateChangeListener;
 import android.view.View.OnClickListener;
+import android.view.ViewGroup.LayoutParams;
 import android.view.ViewConfiguration;
 import android.view.ViewGroup;
 import android.view.ViewPropertyAnimator;
@@ -75,6 +77,7 @@
 import android.widget.BaseAdapter;
 import android.widget.Button;
 import android.widget.EditText;
+import android.widget.FrameLayout;
 import android.widget.ImageView;
 import android.widget.Spinner;
 import android.widget.TextView;
@@ -1409,7 +1412,9 @@
                                         postSwitchCallback.run();
                                     }
                                 }
-                            });
+                            },
+                            new FrameLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
+                                    ViewGroup.LayoutParams.WRAP_CONTENT, Gravity.CENTER));
                         } break;
                     }
                 } break;
@@ -1426,7 +1431,9 @@
                                         postSwitchCallback.run();
                                     }
                                 }
-                            });
+                            },
+                            new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
+                                    ViewGroup.LayoutParams.MATCH_PARENT, Gravity.CENTER));
                         } break;
                     }
                 } break;
@@ -1474,7 +1481,8 @@
             getLayoutInflater().inflate(showLayoutId, contentContainer, true);
         }
 
-        private void animateUiSwitch(int showLayoutId, final Runnable postAnimateCommand) {
+        private void animateUiSwitch(int showLayoutId, final Runnable postAnimateCommand,
+                final LayoutParams containerParams) {
             // Find everything we will shuffle around.
             final ViewGroup contentContainer = (ViewGroup) findViewById(R.id.content_container);
             final View hidingView = contentContainer.getChildAt(0);
@@ -1511,6 +1519,8 @@
                             contentContainer.setScaleY(1.0f);
                             contentContainer.addView(showingView);
 
+                            contentContainer.setLayoutParams(containerParams);
+
                             // Third animation - show the new content.
                             AutoCancellingAnimator.animate(showingView).withLayer().alpha(1.0f)
                                     .withEndAction(new Runnable() {
diff --git a/packages/SystemUI/res/drawable-hdpi/nav_background.9.png b/packages/SystemUI/res/drawable-hdpi/nav_background.9.png
index db36d2b..a09e654 100644
--- a/packages/SystemUI/res/drawable-hdpi/nav_background.9.png
+++ b/packages/SystemUI/res/drawable-hdpi/nav_background.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_device_access_location_found.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_device_access_location_found.png
index 9befc34..d43d1dc 100644
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_device_access_location_found.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_device_access_location_found.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/nav_background.9.png b/packages/SystemUI/res/drawable-mdpi/nav_background.9.png
index 45e6e8f..aa74153 100644
--- a/packages/SystemUI/res/drawable-mdpi/nav_background.9.png
+++ b/packages/SystemUI/res/drawable-mdpi/nav_background.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_device_access_location_found.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_device_access_location_found.png
index 2e24f6f..61d7511 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_device_access_location_found.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_device_access_location_found.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/nav_background.9.png b/packages/SystemUI/res/drawable-xhdpi/nav_background.9.png
index 152e4ac..3b52195 100644
--- a/packages/SystemUI/res/drawable-xhdpi/nav_background.9.png
+++ b/packages/SystemUI/res/drawable-xhdpi/nav_background.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_device_access_location_found.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_device_access_location_found.png
index a7f0017..192d3f7 100644
--- a/packages/SystemUI/res/drawable-xhdpi/stat_sys_device_access_location_found.png
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_device_access_location_found.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/nav_background.9.png b/packages/SystemUI/res/drawable-xxhdpi/nav_background.9.png
index cce2e06..b35183c 100644
--- a/packages/SystemUI/res/drawable-xxhdpi/nav_background.9.png
+++ b/packages/SystemUI/res/drawable-xxhdpi/nav_background.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/stat_sys_device_access_location_found.png b/packages/SystemUI/res/drawable-xxhdpi/stat_sys_device_access_location_found.png
index ad34d49..1e5f15f 100644
--- a/packages/SystemUI/res/drawable-xxhdpi/stat_sys_device_access_location_found.png
+++ b/packages/SystemUI/res/drawable-xxhdpi/stat_sys_device_access_location_found.png
Binary files differ
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettingsModel.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettingsModel.java
index 9d0418d..e6823ac 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettingsModel.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettingsModel.java
@@ -34,6 +34,7 @@
 import android.provider.Settings;
 import android.provider.Settings.SettingNotFoundException;
 import android.text.TextUtils;
+import android.view.LayoutInflater;
 import android.view.View;
 import android.view.inputmethod.InputMethodInfo;
 import android.view.inputmethod.InputMethodManager;
@@ -308,6 +309,7 @@
         refreshBluetoothTile();
         refreshBrightnessTile();
         refreshRotationLockTile();
+        refreshRssiTile();
     }
 
     // Settings
@@ -501,6 +503,14 @@
         }
     }
 
+    void refreshRssiTile() {
+        if (mRSSITile != null) {
+            // We reinflate the original view due to potential styling changes that may have
+            // taken place due to a configuration change.
+            mRSSITile.reinflateContent(LayoutInflater.from(mContext));
+        }
+    }
+
     // Bluetooth
     void addBluetoothTile(QuickSettingsTileView view, RefreshCallback cb) {
         mBluetoothTile = view;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettingsTileView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettingsTileView.java
index 9cff242..3d520f7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettingsTileView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettingsTileView.java
@@ -18,6 +18,7 @@
 
 import android.content.Context;
 import android.util.AttributeSet;
+import android.util.Log;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.widget.FrameLayout;
@@ -26,13 +27,16 @@
  *
  */
 class QuickSettingsTileView extends FrameLayout {
+    private static final String TAG = "QuickSettingsTileView";
 
+    private int mContentLayoutId;
     private int mColSpan;
     private int mRowSpan;
 
     public QuickSettingsTileView(Context context, AttributeSet attrs) {
         super(context, attrs);
 
+        mContentLayoutId = -1;
         mColSpan = 1;
         mRowSpan = 1;
     }
@@ -46,9 +50,19 @@
     }
 
     void setContent(int layoutId, LayoutInflater inflater) {
+        mContentLayoutId = layoutId;
         inflater.inflate(layoutId, this);
     }
 
+    void reinflateContent(LayoutInflater inflater) {
+        if (mContentLayoutId != -1) {
+            removeAllViews();
+            setContent(mContentLayoutId, inflater);
+        } else {
+            Log.e(TAG, "Not reinflating content: No layoutId set");
+        }
+    }
+
     @Override
     public void setVisibility(int vis) {
         if (QuickSettings.DEBUG_GONE_TILES) {
diff --git a/services/java/com/android/server/BluetoothManagerService.java b/services/java/com/android/server/BluetoothManagerService.java
index d2d5280..546324a 100644
--- a/services/java/com/android/server/BluetoothManagerService.java
+++ b/services/java/com/android/server/BluetoothManagerService.java
@@ -766,13 +766,17 @@
                 case MESSAGE_REGISTER_STATE_CHANGE_CALLBACK:
                 {
                     IBluetoothStateChangeCallback callback = (IBluetoothStateChangeCallback) msg.obj;
-                    mStateChangeCallbacks.register(callback);
+                    if (callback != null) {
+                        mStateChangeCallbacks.register(callback);
+                    }
                     break;
                 }
                 case MESSAGE_UNREGISTER_STATE_CHANGE_CALLBACK:
                 {
                     IBluetoothStateChangeCallback callback = (IBluetoothStateChangeCallback) msg.obj;
-                    mStateChangeCallbacks.unregister(callback);
+                    if (callback != null) {
+                        mStateChangeCallbacks.unregister(callback);
+                    }
                     break;
                 }
                 case MESSAGE_BLUETOOTH_SERVICE_CONNECTED:
diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java
index 5695ee5..70418e8 100644
--- a/services/java/com/android/server/ConnectivityService.java
+++ b/services/java/com/android/server/ConnectivityService.java
@@ -353,6 +353,11 @@
      */
     private static final int EVENT_SAMPLE_INTERVAL_ELAPSED = 15;
 
+    /**
+     * PAC manager has received new port.
+     */
+    private static final int EVENT_PROXY_HAS_CHANGED = 16;
+
     /** Handler used for internal events. */
     private InternalHandler mHandler;
     /** Handler used for incoming {@link NetworkStateTracker} events. */
@@ -679,7 +684,7 @@
                 },
                 new IntentFilter(filter));
 
-        mPacManager = new PacManager(mContext);
+        mPacManager = new PacManager(mContext, mHandler, EVENT_PROXY_HAS_CHANGED);
 
         filter = new IntentFilter();
         filter.addAction(CONNECTED_TO_PROVISIONING_NETWORK_ACTION);
@@ -3124,6 +3129,10 @@
                     handleNetworkSamplingTimeout();
                     break;
                 }
+                case EVENT_PROXY_HAS_CHANGED: {
+                    handleApplyDefaultProxy((ProxyProperties)msg.obj);
+                    break;
+                }
             }
         }
     }
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index aae4cb8..4fbbb78 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -14267,6 +14267,8 @@
             }
         }
 
+        boolean mayBeTop = false;
+
         for (int is = app.services.size()-1;
                 is >= 0 && (adj > ProcessList.FOREGROUND_APP_ADJ
                         || schedGroup == Process.THREAD_GROUP_BG_NONINTERACTIVE
@@ -14427,18 +14429,27 @@
                             if (client.curSchedGroup == Process.THREAD_GROUP_DEFAULT) {
                                 schedGroup = Process.THREAD_GROUP_DEFAULT;
                             }
-                            if (clientProcState <=
-                                    ActivityManager.PROCESS_STATE_PERSISTENT_UI &&
-                                    clientProcState >=
-                                            ActivityManager.PROCESS_STATE_PERSISTENT) {
-                                // Persistent processes don't allow us to become top.
-                                // However the top process DOES allow us to become top,
-                                // because in that case we are running because the current
-                                // top process wants us, so we should be counted as part
-                                // of the top set and not just running for some random
-                                // unknown reason in the background.
-                                clientProcState =
-                                        ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND;
+                            if (clientProcState <= ActivityManager.PROCESS_STATE_TOP) {
+                                if (clientProcState == ActivityManager.PROCESS_STATE_TOP) {
+                                    // Special handling of clients who are in the top state.
+                                    // We *may* want to consider this process to be in the
+                                    // top state as well, but only if there is not another
+                                    // reason for it to be running.  Being on the top is a
+                                    // special state, meaning you are specifically running
+                                    // for the current top app.  If the process is already
+                                    // running in the background for some other reason, it
+                                    // is more important to continue considering it to be
+                                    // in the background state.
+                                    mayBeTop = true;
+                                    clientProcState = ActivityManager.PROCESS_STATE_CACHED_EMPTY;
+                                } else {
+                                    // Special handling for above-top states (persistent
+                                    // processes).  These should not bring the current process
+                                    // into the top state, since they are not on top.  Instead
+                                    // give them the best state after that.
+                                    clientProcState =
+                                            ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND;
+                                }
                             }
                         } else {
                             if (clientProcState <
@@ -14526,18 +14537,27 @@
                     app.adjSourceOom = clientAdj;
                     app.adjTarget = cpr.name;
                 }
-                if (clientProcState <=
-                        ActivityManager.PROCESS_STATE_PERSISTENT_UI &&
-                        clientProcState >=
-                                ActivityManager.PROCESS_STATE_PERSISTENT) {
-                    // Persistent processes don't allow us to become top.
-                    // However the top process DOES allow us to become top,
-                    // because in that case we are running because the current
-                    // top process wants us, so we should be counted as part
-                    // of the top set and not just running for some random
-                    // unknown reason in the background.
-                    clientProcState =
-                            ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND;
+                if (clientProcState <= ActivityManager.PROCESS_STATE_TOP) {
+                    if (clientProcState == ActivityManager.PROCESS_STATE_TOP) {
+                        // Special handling of clients who are in the top state.
+                        // We *may* want to consider this process to be in the
+                        // top state as well, but only if there is not another
+                        // reason for it to be running.  Being on the top is a
+                        // special state, meaning you are specifically running
+                        // for the current top app.  If the process is already
+                        // running in the background for some other reason, it
+                        // is more important to continue considering it to be
+                        // in the background state.
+                        mayBeTop = true;
+                        clientProcState = ActivityManager.PROCESS_STATE_CACHED_EMPTY;
+                    } else {
+                        // Special handling for above-top states (persistent
+                        // processes).  These should not bring the current process
+                        // into the top state, since they are not on top.  Instead
+                        // give them the best state after that.
+                        clientProcState =
+                                ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND;
+                    }
                 }
                 if (procState > clientProcState) {
                     procState = clientProcState;
@@ -14564,6 +14584,28 @@
             }
         }
 
+        if (mayBeTop && procState > ActivityManager.PROCESS_STATE_TOP) {
+            // A client of one of our services or providers is in the top state.  We
+            // *may* want to be in the top state, but not if we are already running in
+            // the background for some other reason.  For the decision here, we are going
+            // to pick out a few specific states that we want to remain in when a client
+            // is top (states that tend to be longer-term) and otherwise allow it to go
+            // to the top state.
+            switch (procState) {
+                case ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND:
+                case ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND:
+                case ActivityManager.PROCESS_STATE_SERVICE:
+                    // These all are longer-term states, so pull them up to the top
+                    // of the background states, but not all the way to the top state.
+                    procState = ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND;
+                    break;
+                default:
+                    // Otherwise, top is a better choice, so take it.
+                    procState = ActivityManager.PROCESS_STATE_TOP;
+                    break;
+            }
+        }
+
         if (adj == ProcessList.SERVICE_ADJ) {
             if (doingAll) {
                 app.serviceb = mNewNumAServiceProcs > (mNumServiceProcs/3);
diff --git a/services/java/com/android/server/am/ProcessStatsService.java b/services/java/com/android/server/am/ProcessStatsService.java
index a6375e1..50a7b5c 100644
--- a/services/java/com/android/server/am/ProcessStatsService.java
+++ b/services/java/com/android/server/am/ProcessStatsService.java
@@ -473,11 +473,11 @@
                     current.setDataPosition(0);
                     ProcessStats stats = ProcessStats.CREATOR.createFromParcel(current);
                     current.recycle();
-                    int i = 0;
-                    while (i < files.size() && (stats.mTimePeriodEndRealtime
+                    int i = files.size()-1;
+                    while (i >= 0 && (stats.mTimePeriodEndRealtime
                             - stats.mTimePeriodStartRealtime) < minTime) {
                         AtomicFile file = new AtomicFile(new File(files.get(i)));
-                        i++;
+                        i--;
                         ProcessStats moreStats = new ProcessStats(false);
                         readLocked(moreStats, file);
                         if (moreStats.mReadError == null) {
@@ -490,7 +490,7 @@
                                     - moreStats.mTimePeriodStartRealtime, sb);
                             Slog.i(TAG, sb.toString());
                         } else {
-                            Slog.w(TAG, "Failure reading " + files.get(i-1) + "; "
+                            Slog.w(TAG, "Failure reading " + files.get(i+1) + "; "
                                     + moreStats.mReadError);
                             continue;
                         }
diff --git a/services/java/com/android/server/connectivity/PacManager.java b/services/java/com/android/server/connectivity/PacManager.java
index 1cb2fe3..837fb05 100644
--- a/services/java/com/android/server/connectivity/PacManager.java
+++ b/services/java/com/android/server/connectivity/PacManager.java
@@ -27,6 +27,7 @@
 import android.net.Proxy;
 import android.net.ProxyProperties;
 import android.os.Binder;
+import android.os.Handler;
 import android.os.IBinder;
 import android.os.RemoteException;
 import android.os.ServiceManager;
@@ -89,6 +90,9 @@
     private boolean mHasSentBroadcast;
     private boolean mHasDownloaded;
 
+    private Handler mConnectivityHandler;
+    private int mProxyMessage;
+
     /**
      * Used for locking when setting mProxyService and all references to mPacUrl or mCurrentPac.
      */
@@ -128,7 +132,7 @@
         }
     }
 
-    public PacManager(Context context) {
+    public PacManager(Context context, Handler handler, int proxyMessage) {
         mContext = context;
         mLastPort = -1;
 
@@ -136,6 +140,8 @@
                 context, 0, new Intent(ACTION_PAC_REFRESH), 0);
         context.registerReceiver(new PacRefreshIntentReceiver(),
                 new IntentFilter(ACTION_PAC_REFRESH));
+        mConnectivityHandler = handler;
+        mProxyMessage = proxyMessage;
     }
 
     private AlarmManager getAlarmManager() {
@@ -156,6 +162,10 @@
      */
     public synchronized boolean setCurrentProxyScriptUrl(ProxyProperties proxy) {
         if (!TextUtils.isEmpty(proxy.getPacFileUrl())) {
+            if (proxy.getPacFileUrl().equals(mPacUrl)) {
+                // Allow to send broadcast, nothing to do.
+                return false;
+            }
             synchronized (mProxyLock) {
                 mPacUrl = proxy.getPacFileUrl();
             }
@@ -356,16 +366,7 @@
     }
 
     private void sendPacBroadcast(ProxyProperties proxy) {
-        Intent intent = new Intent(Proxy.PROXY_CHANGE_ACTION);
-        intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING |
-            Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
-        intent.putExtra(Proxy.EXTRA_PROXY_INFO, proxy);
-        final long ident = Binder.clearCallingIdentity();
-        try {
-            mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
-        } finally {
-            Binder.restoreCallingIdentity(ident);
-        }
+        mConnectivityHandler.sendMessage(mConnectivityHandler.obtainMessage(mProxyMessage, proxy));
     }
 
     private synchronized void sendProxyIfNeeded() {
diff --git a/telephony/java/com/android/internal/telephony/ISms.aidl b/telephony/java/com/android/internal/telephony/ISms.aidl
index 647f014..3e8db06 100644
--- a/telephony/java/com/android/internal/telephony/ISms.aidl
+++ b/telephony/java/com/android/internal/telephony/ISms.aidl
@@ -215,4 +215,26 @@
      * Requires system permission.
      */
     void setPremiumSmsPermission(String packageName, int permission);
+
+    /**
+     * SMS over IMS is supported if IMS is registered and SMS is supported
+     * on IMS.
+     *
+     * @return true if SMS over IMS is supported, false otherwise
+     *
+     * @see #getImsSmsFormat()
+     */
+    boolean isImsSmsSupported();
+
+    /**
+     * Gets SMS format supported on IMS.  SMS over IMS format is
+     * either 3GPP or 3GPP2.
+     *
+     * @return android.telephony.SmsMessage.FORMAT_3GPP,
+     *         android.telephony.SmsMessage.FORMAT_3GPP2
+     *      or android.telephony.SmsMessage.FORMAT_UNKNOWN
+     *
+     * @see #isImsSmsSupported()
+     */
+    String getImsSmsFormat();
 }
diff --git a/telephony/java/com/android/internal/telephony/RILConstants.java b/telephony/java/com/android/internal/telephony/RILConstants.java
index 923fef2..821a11c 100644
--- a/telephony/java/com/android/internal/telephony/RILConstants.java
+++ b/telephony/java/com/android/internal/telephony/RILConstants.java
@@ -263,6 +263,8 @@
     int RIL_REQUEST_GET_CELL_INFO_LIST = 109;
     int RIL_REQUEST_SET_UNSOL_CELL_INFO_LIST_RATE = 110;
     int RIL_REQUEST_SET_INITIAL_ATTACH_APN = 111;
+    int RIL_REQUEST_IMS_REGISTRATION_STATE = 112;
+    int RIL_REQUEST_IMS_SEND_SMS = 113;
     int RIL_UNSOL_RESPONSE_BASE = 1000;
     int RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED = 1000;
     int RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED = 1001;
@@ -301,4 +303,5 @@
     int RIL_UNSOL_RIL_CONNECTED = 1034;
     int RIL_UNSOL_VOICE_RADIO_TECH_CHANGED = 1035;
     int RIL_UNSOL_CELL_INFO_LIST = 1036;
+    int RIL_UNSOL_RESPONSE_IMS_NETWORK_STATE_CHANGED = 1037;
 }
diff --git a/telephony/java/com/android/internal/telephony/SmsConstants.java b/telephony/java/com/android/internal/telephony/SmsConstants.java
index 1ccdc3b..2449108 100644
--- a/telephony/java/com/android/internal/telephony/SmsConstants.java
+++ b/telephony/java/com/android/internal/telephony/SmsConstants.java
@@ -62,6 +62,12 @@
     }
 
     /**
+     * Indicates unknown format SMS message.
+     * @hide pending API council approval
+     */
+    public static final String FORMAT_UNKNOWN = "unknown";
+
+    /**
      * Indicates a 3GPP format SMS message.
      * @hide pending API council approval
      */