Merge "Don't recycle action button views" into klp-dev
diff --git a/Android.mk b/Android.mk
index 7ba8ddc..14d1a02 100644
--- a/Android.mk
+++ b/Android.mk
@@ -265,6 +265,8 @@
 	wifi/java/android/net/wifi/IWifiManager.aidl \
 	wifi/java/android/net/wifi/p2p/IWifiP2pManager.aidl \
 	packages/services/PacProcessor/com/android/net/IProxyService.aidl \
+	packages/services/Proxy/com/android/net/IProxyCallback.aidl \
+	packages/services/Proxy/com/android/net/IProxyPortListener.aidl \
 
 # FRAMEWORKS_BASE_JAVA_SRC_DIRS comes from build/core/pathmap.mk
 LOCAL_AIDL_INCLUDES += $(FRAMEWORKS_BASE_JAVA_SRC_DIRS)
diff --git a/api/current.txt b/api/current.txt
index ac3948f..fab32e8 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -10822,7 +10822,6 @@
     method public abstract void setRepeatingRequest(android.hardware.camera2.CaptureRequest, android.hardware.camera2.CameraDevice.CaptureListener, android.os.Handler) throws android.hardware.camera2.CameraAccessException;
     method public abstract void stopRepeating() throws android.hardware.camera2.CameraAccessException;
     method public abstract void waitUntilIdle() throws android.hardware.camera2.CameraAccessException;
-    field public static final int TEMPLATE_MANUAL = 5; // 0x5
     field public static final int TEMPLATE_PREVIEW = 1; // 0x1
     field public static final int TEMPLATE_RECORD = 3; // 0x3
     field public static final int TEMPLATE_STILL_CAPTURE = 2; // 0x2
@@ -17974,6 +17973,7 @@
     method public static boolean isExternalStorageRemovable();
     field public static java.lang.String DIRECTORY_ALARMS;
     field public static java.lang.String DIRECTORY_DCIM;
+    field public static java.lang.String DIRECTORY_DOCUMENTS;
     field public static java.lang.String DIRECTORY_DOWNLOADS;
     field public static java.lang.String DIRECTORY_MOVIES;
     field public static java.lang.String DIRECTORY_MUSIC;
@@ -20811,10 +20811,10 @@
     field public static final java.lang.String COLUMN_MIME_TYPE = "mime_type";
     field public static final java.lang.String COLUMN_SIZE = "_size";
     field public static final java.lang.String COLUMN_SUMMARY = "summary";
-    field public static final int FLAG_DIR_PREFERS_GRID = 32; // 0x20
-    field public static final int FLAG_DIR_PREFERS_LAST_MODIFIED = 64; // 0x40
+    field public static final int FLAG_DIR_HIDE_GRID_TITLES = 64; // 0x40
+    field public static final int FLAG_DIR_PREFERS_GRID = 16; // 0x10
+    field public static final int FLAG_DIR_PREFERS_LAST_MODIFIED = 32; // 0x20
     field public static final int FLAG_DIR_SUPPORTS_CREATE = 8; // 0x8
-    field public static final int FLAG_DIR_SUPPORTS_SEARCH = 16; // 0x10
     field public static final int FLAG_SUPPORTS_DELETE = 4; // 0x4
     field public static final int FLAG_SUPPORTS_THUMBNAIL = 1; // 0x1
     field public static final int FLAG_SUPPORTS_WRITE = 2; // 0x2
@@ -20832,9 +20832,11 @@
     field public static final java.lang.String COLUMN_SUMMARY = "summary";
     field public static final java.lang.String COLUMN_TITLE = "title";
     field public static final int FLAG_ADVANCED = 4; // 0x4
+    field public static final int FLAG_EMPTY = 32; // 0x20
     field public static final int FLAG_LOCAL_ONLY = 2; // 0x2
     field public static final int FLAG_SUPPORTS_CREATE = 1; // 0x1
     field public static final int FLAG_SUPPORTS_RECENTS = 8; // 0x8
+    field public static final int FLAG_SUPPORTS_SEARCH = 16; // 0x10
     field public static final int ROOT_TYPE_DEVICE = 3; // 0x3
     field public static final int ROOT_TYPE_SERVICE = 1; // 0x1
     field public static final int ROOT_TYPE_SHORTCUT = 2; // 0x2
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index e522b78..55c66726 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -1251,6 +1251,16 @@
     }
 
     @Override
+    public ComponentName getHomeActivities(List<ResolveInfo> outActivities) {
+        try {
+            return mPM.getHomeActivities(outActivities);
+        } catch (RemoteException e) {
+            // Should never happen!
+        }
+        return null;
+    }
+
+    @Override
     public void setComponentEnabledSetting(ComponentName componentName,
                                            int newState, int flags) {
         try {
diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java
index 676fd1f..2172a7b 100644
--- a/core/java/android/bluetooth/BluetoothAdapter.java
+++ b/core/java/android/bluetooth/BluetoothAdapter.java
@@ -27,7 +27,6 @@
 import android.os.ServiceManager;
 import android.util.Log;
 import android.util.Pair;
-
 import java.io.IOException;
 import java.lang.ref.WeakReference;
 import java.util.ArrayList;
@@ -51,7 +50,7 @@
  * devices, and start a scan for Bluetooth LE devices.
  *
  * <p>To get a {@link BluetoothAdapter} representing the local Bluetooth
- * adapter, when running on JELLY_BEAN_MR1 and below, call the 
+ * adapter, when running on JELLY_BEAN_MR1 and below, call the
  * static {@link #getDefaultAdapter} method; when running on JELLY_BEAN_MR2 and
  * higher, retrieve it through
  * {@link android.content.Context#getSystemService} with
@@ -1229,6 +1228,9 @@
         } else if (profile == BluetoothProfile.HEALTH) {
             BluetoothHealth health = new BluetoothHealth(context, listener);
             return true;
+        } else if (profile == BluetoothProfile.MAP) {
+            BluetoothMap map = new BluetoothMap(context, listener);
+            return true;
         } else {
             return false;
         }
@@ -1277,6 +1279,10 @@
                 BluetoothGattServer gattServer = (BluetoothGattServer)proxy;
                 gattServer.close();
                 break;
+            case BluetoothProfile.MAP:
+                BluetoothMap map = (BluetoothMap)proxy;
+                map.close();
+                break;
         }
     }
 
diff --git a/core/java/android/bluetooth/BluetoothMap.java b/core/java/android/bluetooth/BluetoothMap.java
index 7de309f..fac8fd5 100644
--- a/core/java/android/bluetooth/BluetoothMap.java
+++ b/core/java/android/bluetooth/BluetoothMap.java
@@ -16,6 +16,8 @@
 
 package android.bluetooth;
 
+import java.util.List;
+import java.util.ArrayList;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
@@ -30,25 +32,14 @@
  * Profile.
  *@hide
  */
-public class BluetoothMap {
+public final class BluetoothMap implements BluetoothProfile {
 
     private static final String TAG = "BluetoothMap";
     private static final boolean DBG = true;
     private static final boolean VDBG = false;
 
-    /** int extra for MAP_STATE_CHANGED_ACTION */
-    public static final String MAP_STATE =
-        "android.bluetooth.map.intent.MAP_STATE";
-    /** int extra for MAP_STATE_CHANGED_ACTION */
-    public static final String MAP_PREVIOUS_STATE =
-        "android.bluetooth.map.intent.MAP_PREVIOUS_STATE";
-
-    /** Indicates the state of a Map connection state has changed.
-     *  This intent will always contain MAP_STATE, MAP_PREVIOUS_STATE and
-     *  BluetoothIntent.ADDRESS extras.
-     */
-    public static final String MAP_STATE_CHANGED_ACTION =
-        "android.bluetooth.map.intent.action.MAP_STATE_CHANGED";
+    public static final String ACTION_CONNECTION_STATE_CHANGED =
+        "android.bluetooth.map.profile.action.CONNECTION_STATE_CHANGED";
 
     private IBluetoothMap mService;
     private final Context mContext;
@@ -57,41 +48,12 @@
 
     /** There was an error trying to obtain the state */
     public static final int STATE_ERROR        = -1;
-    /** No client currently connected */
-    public static final int STATE_DISCONNECTED = 0;
-    /** Connection attempt in progress */
-    public static final int STATE_CONNECTING   = 1;
-    /** Client is currently connected */
-    public static final int STATE_CONNECTED    = 2;
 
     public static final int RESULT_FAILURE = 0;
     public static final int RESULT_SUCCESS = 1;
     /** Connection canceled before completion. */
     public static final int RESULT_CANCELED = 2;
 
-    /**
-     * An interface for notifying Bluetooth PCE IPC clients when they have
-     * been connected to the BluetoothMap service.
-     */
-    public interface ServiceListener {
-        /**
-         * Called to notify the client when this proxy object has been
-         * connected to the BluetoothMap service. Clients must wait for
-         * this callback before making IPC calls on the BluetoothMap
-         * service.
-         */
-        public void onServiceConnected(BluetoothMap proxy);
-
-        /**
-         * Called to notify the client that this proxy object has been
-         * disconnected from the BluetoothMap service. Clients must not
-         * make IPC calls on the BluetoothMap service after this callback.
-         * This callback will currently only occur if the application hosting
-         * the BluetoothMap service, but may be called more often in future.
-         */
-        public void onServiceDisconnected();
-    }
-
     final private IBluetoothStateChangeCallback mBluetoothStateChangeCallback =
             new IBluetoothStateChangeCallback.Stub() {
                 public void onBluetoothStateChange(boolean up) {
@@ -111,11 +73,7 @@
                             try {
                                 if (mService == null) {
                                     if (VDBG) Log.d(TAG,"Binding service...");
-                                    if (!mContext.bindService(
-                                                        new Intent(IBluetoothMap.class.getName()),
-                                                        mConnection, 0)) {
-                                        Log.e(TAG, "Could not bind to Bluetooth MAP Service");
-                                    }
+                                    doBind();
                                 }
                             } catch (Exception re) {
                                 Log.e(TAG,"",re);
@@ -128,7 +86,8 @@
     /**
      * Create a BluetoothMap proxy object.
      */
-    public BluetoothMap(Context context, ServiceListener l) {
+    /*package*/ BluetoothMap(Context context, ServiceListener l) {
+        if (DBG) Log.d(TAG, "Create BluetoothMap proxy object");
         mContext = context;
         mServiceListener = l;
         mAdapter = BluetoothAdapter.getDefaultAdapter();
@@ -140,9 +99,18 @@
                 Log.e(TAG,"",e);
             }
         }
-        if (!context.bindService(new Intent(IBluetoothMap.class.getName()), mConnection, 0)) {
-            Log.e(TAG, "Could not bind to Bluetooth Map Service");
+        doBind();
+    }
+
+    boolean doBind() {
+        Intent intent = new Intent(IBluetoothMap.class.getName());
+        ComponentName comp = intent.resolveSystemService(mContext.getPackageManager(), 0);
+        intent.setComponent(comp);
+        if (comp == null || !mContext.bindService(intent, mConnection, 0)) {
+            Log.e(TAG, "Could not bind to Bluetooth MAP Service with " + intent);
+            return false;
         }
+        return true;
     }
 
     protected void finalize() throws Throwable {
@@ -221,9 +189,9 @@
     }
 
     /**
-     * Returns true if the specified Bluetooth device is connected (does not
-     * include connecting). Returns false if not connected, or if this proxy
-     * object is not currently connected to the Map service.
+     * Returns true if the specified Bluetooth device is connected.
+     * Returns false if not connected, or if this proxy object is not
+     * currently connected to the Map service.
      */
     public boolean isConnected(BluetoothDevice device) {
         if (VDBG) log("isConnected(" + device + ")");
@@ -239,21 +207,33 @@
     }
 
     /**
-     * Disconnects the current Map Client. Currently this call blocks,
-     * it may soon be made asynchronous. Returns false if this proxy object is
-     * not currently connected to the Map service.
+     * Initiate connection. Initiation of outgoing connections is not
+     * supported for MAP server.
      */
-    public boolean disconnect() {
-        if (DBG) log("disconnect()");
-        if (mService != null) {
+    public boolean connect(BluetoothDevice device) {
+        if (DBG) log("connect(" + device + ")" + "not supported for MAPS");
+        return false;
+    }
+
+    /**
+     * Initiate disconnect.
+     *
+     * @param device Remote Bluetooth Device
+     * @return false on error,
+     *               true otherwise
+     */
+    public boolean disconnect(BluetoothDevice device) {
+        if (DBG) log("disconnect(" + device + ")");
+        if (mService != null && isEnabled() &&
+            isValidDevice(device)) {
             try {
-                mService.disconnect();
-                return true;
-            } catch (RemoteException e) {Log.e(TAG, e.toString());}
-        } else {
-            Log.w(TAG, "Proxy not attached to service");
-            if (DBG) log(Log.getStackTraceString(new Throwable()));
+                return mService.disconnect(device);
+            } catch (RemoteException e) {
+              Log.e(TAG, Log.getStackTraceString(new Throwable()));
+              return false;
+            }
         }
+        if (mService == null) Log.w(TAG, "Proxy not attached to service");
         return false;
     }
 
@@ -277,19 +257,132 @@
         }
     }
 
+    /**
+     * Get the list of connected devices. Currently at most one.
+     *
+     * @return list of connected devices
+     */
+    public List<BluetoothDevice> getConnectedDevices() {
+        if (DBG) log("getConnectedDevices()");
+        if (mService != null && isEnabled()) {
+            try {
+                return mService.getConnectedDevices();
+            } catch (RemoteException e) {
+                Log.e(TAG, Log.getStackTraceString(new Throwable()));
+                return new ArrayList<BluetoothDevice>();
+            }
+        }
+        if (mService == null) Log.w(TAG, "Proxy not attached to service");
+        return new ArrayList<BluetoothDevice>();
+    }
+
+    /**
+     * Get the list of devices matching specified states. Currently at most one.
+     *
+     * @return list of matching devices
+     */
+    public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
+        if (DBG) log("getDevicesMatchingStates()");
+        if (mService != null && isEnabled()) {
+            try {
+                return mService.getDevicesMatchingConnectionStates(states);
+            } catch (RemoteException e) {
+                Log.e(TAG, Log.getStackTraceString(new Throwable()));
+                return new ArrayList<BluetoothDevice>();
+            }
+        }
+        if (mService == null) Log.w(TAG, "Proxy not attached to service");
+        return new ArrayList<BluetoothDevice>();
+    }
+
+    /**
+     * Get connection state of device
+     *
+     * @return device connection state
+     */
+    public int getConnectionState(BluetoothDevice device) {
+        if (DBG) log("getConnectionState(" + device + ")");
+        if (mService != null && isEnabled() &&
+            isValidDevice(device)) {
+            try {
+                return mService.getConnectionState(device);
+            } catch (RemoteException e) {
+                Log.e(TAG, Log.getStackTraceString(new Throwable()));
+                return BluetoothProfile.STATE_DISCONNECTED;
+            }
+        }
+        if (mService == null) Log.w(TAG, "Proxy not attached to service");
+        return BluetoothProfile.STATE_DISCONNECTED;
+    }
+
+    /**
+     * Set priority of the profile
+     *
+     * <p> The device should already be paired.
+     *  Priority can be one of {@link #PRIORITY_ON} or
+     * {@link #PRIORITY_OFF},
+     *
+     * @param device Paired bluetooth device
+     * @param priority
+     * @return true if priority is set, false on error
+     */
+    public boolean setPriority(BluetoothDevice device, int priority) {
+        if (DBG) log("setPriority(" + device + ", " + priority + ")");
+        if (mService != null && isEnabled() &&
+            isValidDevice(device)) {
+            if (priority != BluetoothProfile.PRIORITY_OFF &&
+                priority != BluetoothProfile.PRIORITY_ON) {
+              return false;
+            }
+            try {
+                return mService.setPriority(device, priority);
+            } catch (RemoteException e) {
+                Log.e(TAG, Log.getStackTraceString(new Throwable()));
+                return false;
+            }
+        }
+        if (mService == null) Log.w(TAG, "Proxy not attached to service");
+        return false;
+    }
+
+    /**
+     * Get the priority of the profile.
+     *
+     * <p> The priority can be any of:
+     * {@link #PRIORITY_AUTO_CONNECT}, {@link #PRIORITY_OFF},
+     * {@link #PRIORITY_ON}, {@link #PRIORITY_UNDEFINED}
+     *
+     * @param device Bluetooth device
+     * @return priority of the device
+     */
+    public int getPriority(BluetoothDevice device) {
+        if (VDBG) log("getPriority(" + device + ")");
+        if (mService != null && isEnabled() &&
+            isValidDevice(device)) {
+            try {
+                return mService.getPriority(device);
+            } catch (RemoteException e) {
+                Log.e(TAG, Log.getStackTraceString(new Throwable()));
+                return PRIORITY_OFF;
+            }
+        }
+        if (mService == null) Log.w(TAG, "Proxy not attached to service");
+        return PRIORITY_OFF;
+    }
+
     private ServiceConnection mConnection = new ServiceConnection() {
         public void onServiceConnected(ComponentName className, IBinder service) {
             if (DBG) log("Proxy object connected");
             mService = IBluetoothMap.Stub.asInterface(service);
             if (mServiceListener != null) {
-                mServiceListener.onServiceConnected(BluetoothMap.this);
+                mServiceListener.onServiceConnected(BluetoothProfile.MAP, BluetoothMap.this);
             }
         }
         public void onServiceDisconnected(ComponentName className) {
             if (DBG) log("Proxy object disconnected");
             mService = null;
             if (mServiceListener != null) {
-                mServiceListener.onServiceDisconnected();
+                mServiceListener.onServiceDisconnected(BluetoothProfile.MAP);
             }
         }
     };
@@ -297,4 +390,19 @@
     private static void log(String msg) {
         Log.d(TAG, msg);
     }
+
+   private boolean isEnabled() {
+        BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
+        if (adapter != null && adapter.getState() == BluetoothAdapter.STATE_ON) return true;
+        log("Bluetooth is Not enabled");
+        return false;
+    }
+    private boolean isValidDevice(BluetoothDevice device) {
+       if (device == null) return false;
+
+       if (BluetoothAdapter.checkBluetoothAddress(device.getAddress())) return true;
+       return false;
+    }
+
+
 }
diff --git a/core/java/android/bluetooth/BluetoothUuid.java b/core/java/android/bluetooth/BluetoothUuid.java
index 6609b98..abdf949e 100644
--- a/core/java/android/bluetooth/BluetoothUuid.java
+++ b/core/java/android/bluetooth/BluetoothUuid.java
@@ -67,13 +67,16 @@
     public static final ParcelUuid PBAP_PSE =
             ParcelUuid.fromString("0000112f-0000-1000-8000-00805F9B34FB");
     public static final ParcelUuid MAP =
-            ParcelUuid.fromString("00001132-0000-1000-8000-00805F9B34FB");
+            ParcelUuid.fromString("00001134-0000-1000-8000-00805F9B34FB");
     public static final ParcelUuid MNS =
             ParcelUuid.fromString("00001133-0000-1000-8000-00805F9B34FB");
+    public static final ParcelUuid MAS =
+            ParcelUuid.fromString("00001132-0000-1000-8000-00805F9B34FB");
+
 
     public static final ParcelUuid[] RESERVED_UUIDS = {
         AudioSink, AudioSource, AdvAudioDist, HSP, Handsfree, AvrcpController, AvrcpTarget,
-        ObexObjectPush, PANU, NAP, MAP, MNS};
+        ObexObjectPush, PANU, NAP, MAP, MNS, MAS};
 
     public static boolean isAudioSource(ParcelUuid uuid) {
         return uuid.equals(AudioSource);
@@ -124,6 +127,9 @@
     public static boolean isMns(ParcelUuid uuid) {
         return uuid.equals(MNS);
     }
+    public static boolean isMas(ParcelUuid uuid) {
+        return uuid.equals(MAS);
+    }
 
     /**
      * Returns true if ParcelUuid is present in uuidArray
diff --git a/core/java/android/bluetooth/IBluetoothMap.aidl b/core/java/android/bluetooth/IBluetoothMap.aidl
index 0c18e06..d4af63d 100644
--- a/core/java/android/bluetooth/IBluetoothMap.aidl
+++ b/core/java/android/bluetooth/IBluetoothMap.aidl
@@ -27,6 +27,11 @@
     int getState();
     BluetoothDevice getClient();
     boolean connect(in BluetoothDevice device);
-    void disconnect();
+    boolean disconnect(in BluetoothDevice device);
     boolean isConnected(in BluetoothDevice device);
+    List<BluetoothDevice> getConnectedDevices();
+    List<BluetoothDevice> getDevicesMatchingConnectionStates(in int[] states);
+    int getConnectionState(in BluetoothDevice device);
+    boolean setPriority(in BluetoothDevice device, int priority);
+    int getPriority(in BluetoothDevice device);
 }
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index 2b0c896..acd4ffa 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -234,6 +234,12 @@
             out List<ComponentName> outActivities, String packageName);
 
     /**
+     * Report the set of 'Home' activity candidates, plus (if any) which of them
+     * is the current "always use this one" setting.
+     */
+     ComponentName getHomeActivities(out List<ResolveInfo> outHomeCandidates);
+
+    /**
      * As per {@link android.content.pm.PackageManager#setComponentEnabledSetting}.
      */
     void setComponentEnabledSetting(in ComponentName componentName,
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index d58b14c..416f489 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -3027,6 +3027,13 @@
             List<ComponentName> outActivities, String packageName);
 
     /**
+     * Ask for the set of available 'home' activities and the current explicit
+     * default, if any.
+     * @hide
+     */
+    public abstract ComponentName getHomeActivities(List<ResolveInfo> outActivities);
+
+    /**
      * Set the enabled setting for a package component (activity, receiver, service, provider).
      * This setting will override any enabled state which may have been set by the component in its
      * manifest.
diff --git a/core/java/android/hardware/camera2/CameraDevice.java b/core/java/android/hardware/camera2/CameraDevice.java
index 75c0f7d..0c13b0f 100644
--- a/core/java/android/hardware/camera2/CameraDevice.java
+++ b/core/java/android/hardware/camera2/CameraDevice.java
@@ -89,6 +89,16 @@
     public static final int TEMPLATE_VIDEO_SNAPSHOT = 4;
 
     /**
+     * Create a request suitable for zero shutter lag still capture. This means
+     * means maximizing image quality without compromising preview frame rate.
+     * AE/AWB/AF should be on auto mode.
+     *
+     * @see #createCaptureRequest
+     * @hide
+     */
+    public static final int TEMPLATE_ZERO_SHUTTER_LAG = 5;
+
+    /**
      * A basic template for direct application control of capture
      * parameters. All automatic control is disabled (auto-exposure, auto-white
      * balance, auto-focus), and post-processing parameters are set to preview
@@ -97,8 +107,9 @@
      * application depending on the intended use case.
      *
      * @see #createCaptureRequest
+     * @hide
      */
-    public static final int TEMPLATE_MANUAL = 5;
+    public static final int TEMPLATE_MANUAL = 6;
 
     /**
      * Get the ID of this camera device.
diff --git a/core/java/android/net/ProxyProperties.java b/core/java/android/net/ProxyProperties.java
index 76aea9f..648a4b3 100644
--- a/core/java/android/net/ProxyProperties.java
+++ b/core/java/android/net/ProxyProperties.java
@@ -38,7 +38,7 @@
 
     private String mPacFileUrl;
     public static final String LOCAL_EXCL_LIST = "";
-    public static final int LOCAL_PORT = 8182;
+    public static final int LOCAL_PORT = -1;
     public static final String LOCAL_HOST = "localhost";
 
     public ProxyProperties(String host, int port, String exclList) {
@@ -54,6 +54,14 @@
         mPacFileUrl = pacFileUrl;
     }
 
+    // Only used in PacManager after Local Proxy is bound.
+    public ProxyProperties(String pacFileUrl, int localProxyPort) {
+        mHost = LOCAL_HOST;
+        mPort = localProxyPort;
+        setExclusionList(LOCAL_EXCL_LIST);
+        mPacFileUrl = pacFileUrl;
+    }
+
     private ProxyProperties(String host, int port, String exclList, String[] parsedExclList) {
         mHost = host;
         mPort = port;
diff --git a/core/java/android/os/Debug.java b/core/java/android/os/Debug.java
index 8f68fc1..eb91238 100644
--- a/core/java/android/os/Debug.java
+++ b/core/java/android/os/Debug.java
@@ -1018,6 +1018,28 @@
      */
     public static native long getPss(int pid, long[] outUss);
 
+    /** @hide */
+    public static final int MEMINFO_TOTAL = 0;
+    /** @hide */
+    public static final int MEMINFO_FREE = 1;
+    /** @hide */
+    public static final int MEMINFO_BUFFERS = 2;
+    /** @hide */
+    public static final int MEMINFO_CACHED = 3;
+    /** @hide */
+    public static final int MEMINFO_SHMEM = 4;
+    /** @hide */
+    public static final int MEMINFO_SLAB = 5;
+    /** @hide */
+    public static final int MEMINFO_COUNT = 6;
+
+    /**
+     * Retrieves /proc/meminfo.  outSizes is filled with fields
+     * as defined by MEMINFO_* offsets.
+     * @hide
+     */
+    public static native void getMemInfo(long[] outSizes);
+
     /**
      * Establish an object allocation limit in the current thread.
      * This feature was never enabled in release builds.  The
diff --git a/core/java/android/os/Environment.java b/core/java/android/os/Environment.java
index c6e8c3e..5b36bca 100644
--- a/core/java/android/os/Environment.java
+++ b/core/java/android/os/Environment.java
@@ -460,7 +460,13 @@
      * top-level public directory, as this convention makes no sense elsewhere.
      */
     public static String DIRECTORY_DCIM = "DCIM";
-    
+
+    /**
+     * Standard directory in which to place documents that have been created by
+     * the user.
+     */
+    public static String DIRECTORY_DOCUMENTS = "Documents";
+
     /**
      * Get a top-level public external storage directory for placing files of
      * a particular type.  This is where the user will typically place and
diff --git a/core/java/android/provider/DocumentsContract.java b/core/java/android/provider/DocumentsContract.java
index 37ce065..3f33e80 100644
--- a/core/java/android/provider/DocumentsContract.java
+++ b/core/java/android/provider/DocumentsContract.java
@@ -64,9 +64,9 @@
     // content://com.example/root/
     // content://com.example/root/sdcard/
     // content://com.example/root/sdcard/recent/
+    // content://com.example/root/sdcard/search/?query=pony
     // content://com.example/document/12/
     // content://com.example/document/12/children/
-    // content://com.example/document/12/search/?query=pony
 
     private DocumentsContract() {
     }
@@ -174,7 +174,6 @@
          * @see #FLAG_SUPPORTS_THUMBNAIL
          * @see #FLAG_DIR_PREFERS_GRID
          * @see #FLAG_DIR_SUPPORTS_CREATE
-         * @see #FLAG_DIR_SUPPORTS_SEARCH
          */
         public static final String COLUMN_FLAGS = "flags";
 
@@ -241,16 +240,6 @@
         public static final int FLAG_DIR_SUPPORTS_CREATE = 1 << 3;
 
         /**
-         * Flag indicating that a directory supports search. Only valid when
-         * {@link #COLUMN_MIME_TYPE} is {@link #MIME_TYPE_DIR}.
-         *
-         * @see #COLUMN_FLAGS
-         * @see DocumentsProvider#querySearchDocuments(String, String,
-         *      String[])
-         */
-        public static final int FLAG_DIR_SUPPORTS_SEARCH = 1 << 4;
-
-        /**
          * Flag indicating that a directory prefers its contents be shown in a
          * larger format grid. Usually suitable when a directory contains mostly
          * pictures. Only valid when {@link #COLUMN_MIME_TYPE} is
@@ -258,7 +247,7 @@
          *
          * @see #COLUMN_FLAGS
          */
-        public static final int FLAG_DIR_PREFERS_GRID = 1 << 5;
+        public static final int FLAG_DIR_PREFERS_GRID = 1 << 4;
 
         /**
          * Flag indicating that a directory prefers its contents be sorted by
@@ -267,7 +256,19 @@
          *
          * @see #COLUMN_FLAGS
          */
-        public static final int FLAG_DIR_PREFERS_LAST_MODIFIED = 1 << 6;
+        public static final int FLAG_DIR_PREFERS_LAST_MODIFIED = 1 << 5;
+
+        /**
+         * Flag indicating that document titles should be hidden when viewing
+         * this directory in a larger format grid. For example, a directory
+         * containing only images may want the image thumbnails to speak for
+         * themselves. Only valid when {@link #COLUMN_MIME_TYPE} is
+         * {@link #MIME_TYPE_DIR}.
+         *
+         * @see #COLUMN_FLAGS
+         * @see #FLAG_DIR_PREFERS_GRID
+         */
+        public static final int FLAG_DIR_HIDE_GRID_TITLES = 1 << 6;
     }
 
     /**
@@ -306,9 +307,12 @@
          * <p>
          * Type: INTEGER (int)
          *
+         * @see #FLAG_ADVANCED
+         * @see #FLAG_EMPTY
          * @see #FLAG_LOCAL_ONLY
          * @see #FLAG_SUPPORTS_CREATE
-         * @see #FLAG_ADVANCED
+         * @see #FLAG_SUPPORTS_RECENTS
+         * @see #FLAG_SUPPORTS_SEARCH
          */
         public static final String COLUMN_FLAGS = "flags";
 
@@ -422,6 +426,27 @@
          * @see DocumentsContract#buildRecentDocumentsUri(String, String)
          */
         public static final int FLAG_SUPPORTS_RECENTS = 1 << 3;
+
+        /**
+         * Flag indicating that this root supports search.
+         *
+         * @see #COLUMN_FLAGS
+         * @see DocumentsProvider#querySearchDocuments(String, String,
+         *      String[])
+         */
+        public static final int FLAG_SUPPORTS_SEARCH = 1 << 4;
+
+        /**
+         * Flag indicating that this root is currently empty. This may be used
+         * to hide the root when opening documents, but the root will still be
+         * shown when creating documents and {@link #FLAG_SUPPORTS_CREATE} is
+         * also set.
+         *
+         * @see #COLUMN_FLAGS
+         * @see DocumentsProvider#querySearchDocuments(String, String,
+         *      String[])
+         */
+        public static final int FLAG_EMPTY = 1 << 5;
     }
 
     /**
@@ -493,9 +518,9 @@
     }
 
     /**
-     * Build Uri representing the recently modified documents of a specific
-     * root. When queried, a provider will return zero or more rows with columns
-     * defined by {@link Document}.
+     * Build Uri representing the recently modified documents of a specific root
+     * in a document provider. When queried, a provider will return zero or more
+     * rows with columns defined by {@link Document}.
      *
      * @see DocumentsProvider#queryRecentDocuments(String, String[])
      * @see #getRootId(Uri)
@@ -538,21 +563,17 @@
 
     /**
      * Build Uri representing a search for matching documents under a specific
-     * directory in a document provider. When queried, a provider will return
-     * zero or more rows with columns defined by {@link Document}.
+     * root in a document provider. When queried, a provider will return zero or
+     * more rows with columns defined by {@link Document}.
      *
-     * @param parentDocumentId the document to return children for, which must
-     *            be both a directory with MIME type of
-     *            {@link Document#MIME_TYPE_DIR} and have
-     *            {@link Document#FLAG_DIR_SUPPORTS_SEARCH} set.
      * @see DocumentsProvider#querySearchDocuments(String, String, String[])
-     * @see #getDocumentId(Uri)
+     * @see #getRootId(Uri)
      * @see #getSearchDocumentsQuery(Uri)
      */
     public static Uri buildSearchDocumentsUri(
-            String authority, String parentDocumentId, String query) {
+            String authority, String rootId, String query) {
         return new Uri.Builder().scheme(ContentResolver.SCHEME_CONTENT).authority(authority)
-                .appendPath(PATH_DOCUMENT).appendPath(parentDocumentId).appendPath(PATH_SEARCH)
+                .appendPath(PATH_ROOT).appendPath(rootId).appendPath(PATH_SEARCH)
                 .appendQueryParameter(PARAM_QUERY, query).build();
     }
 
diff --git a/core/java/android/provider/DocumentsProvider.java b/core/java/android/provider/DocumentsProvider.java
index d801827..bc4e28b 100644
--- a/core/java/android/provider/DocumentsProvider.java
+++ b/core/java/android/provider/DocumentsProvider.java
@@ -75,9 +75,9 @@
     private static final int MATCH_ROOTS = 1;
     private static final int MATCH_ROOT = 2;
     private static final int MATCH_RECENT = 3;
-    private static final int MATCH_DOCUMENT = 4;
-    private static final int MATCH_CHILDREN = 5;
-    private static final int MATCH_SEARCH = 6;
+    private static final int MATCH_SEARCH = 4;
+    private static final int MATCH_DOCUMENT = 5;
+    private static final int MATCH_CHILDREN = 6;
 
     private String mAuthority;
 
@@ -94,9 +94,9 @@
         mMatcher.addURI(mAuthority, "root", MATCH_ROOTS);
         mMatcher.addURI(mAuthority, "root/*", MATCH_ROOT);
         mMatcher.addURI(mAuthority, "root/*/recent", MATCH_RECENT);
+        mMatcher.addURI(mAuthority, "root/*/search", MATCH_SEARCH);
         mMatcher.addURI(mAuthority, "document/*", MATCH_DOCUMENT);
         mMatcher.addURI(mAuthority, "document/*/children", MATCH_CHILDREN);
-        mMatcher.addURI(mAuthority, "document/*/search", MATCH_SEARCH);
 
         // Sanity check our setup
         if (!info.exported) {
@@ -176,13 +176,12 @@
     }
 
     /**
-     * Return documents that that match the given query, starting the search at
-     * the given directory.
+     * Return documents that that match the given query.
      *
-     * @param parentDocumentId the directory to start search at.
+     * @param rootId the root to search under.
      */
     @SuppressWarnings("unused")
-    public Cursor querySearchDocuments(String parentDocumentId, String query, String[] projection)
+    public Cursor querySearchDocuments(String rootId, String query, String[] projection)
             throws FileNotFoundException {
         throw new UnsupportedOperationException("Search not supported");
     }
@@ -267,6 +266,9 @@
                     return queryRoots(projection);
                 case MATCH_RECENT:
                     return queryRecentDocuments(getRootId(uri), projection);
+                case MATCH_SEARCH:
+                    return querySearchDocuments(
+                            getRootId(uri), getSearchDocumentsQuery(uri), projection);
                 case MATCH_DOCUMENT:
                     return queryDocument(getDocumentId(uri), projection);
                 case MATCH_CHILDREN:
@@ -276,9 +278,6 @@
                     } else {
                         return queryChildDocuments(getDocumentId(uri), projection, sortOrder);
                     }
-                case MATCH_SEARCH:
-                    return querySearchDocuments(
-                            getDocumentId(uri), getSearchDocumentsQuery(uri), projection);
                 default:
                     throw new UnsupportedOperationException("Unsupported Uri " + uri);
             }
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 025926e..af905b4 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -5642,6 +5642,9 @@
         /** {@hide} */
         public static final String
                 BLUETOOTH_INPUT_DEVICE_PRIORITY_PREFIX = "bluetooth_input_device_priority_";
+        /** {@hide} */
+        public static final String
+                BLUETOOTH_MAP_PRIORITY_PREFIX = "bluetooth_map_priority_";
 
         /**
          * Get the key that retrieves a bluetooth headset's priority.
@@ -5668,6 +5671,13 @@
         }
 
         /**
+         * Get the key that retrieves a bluetooth map priority.
+         * @hide
+         */
+        public static final String getBluetoothMapPriorityKey(String address) {
+            return BLUETOOTH_MAP_PRIORITY_PREFIX + address.toUpperCase(Locale.ROOT);
+        }
+        /**
          * Scaling factor for normal window animations. Setting to 0 will
          * disable window animations.
          */
diff --git a/core/java/com/android/internal/os/ProcessCpuTracker.java b/core/java/com/android/internal/os/ProcessCpuTracker.java
index 30ca73e..58cd60d 100644
--- a/core/java/com/android/internal/os/ProcessCpuTracker.java
+++ b/core/java/com/android/internal/os/ProcessCpuTracker.java
@@ -49,12 +49,12 @@
         PROC_SPACE_TERM,
         PROC_SPACE_TERM,
         PROC_SPACE_TERM,
-        PROC_SPACE_TERM|PROC_OUT_LONG,                  // 9: minor faults
+        PROC_SPACE_TERM|PROC_OUT_LONG,                  // 10: minor faults
         PROC_SPACE_TERM,
-        PROC_SPACE_TERM|PROC_OUT_LONG,                  // 11: major faults
+        PROC_SPACE_TERM|PROC_OUT_LONG,                  // 12: major faults
         PROC_SPACE_TERM,
-        PROC_SPACE_TERM|PROC_OUT_LONG,                  // 13: utime
-        PROC_SPACE_TERM|PROC_OUT_LONG                   // 14: stime
+        PROC_SPACE_TERM|PROC_OUT_LONG,                  // 14: utime
+        PROC_SPACE_TERM|PROC_OUT_LONG,                  // 15: stime
     };
 
     static final int PROCESS_STAT_MINOR_FAULTS = 0;
@@ -69,7 +69,7 @@
 
     private static final int[] PROCESS_FULL_STATS_FORMAT = new int[] {
         PROC_SPACE_TERM,
-        PROC_SPACE_TERM|PROC_PARENS|PROC_OUT_STRING,    // 1: name
+        PROC_SPACE_TERM|PROC_PARENS|PROC_OUT_STRING,    // 2: name
         PROC_SPACE_TERM,
         PROC_SPACE_TERM,
         PROC_SPACE_TERM,
@@ -77,19 +77,20 @@
         PROC_SPACE_TERM,
         PROC_SPACE_TERM,
         PROC_SPACE_TERM,
-        PROC_SPACE_TERM|PROC_OUT_LONG,                  // 9: minor faults
+        PROC_SPACE_TERM|PROC_OUT_LONG,                  // 10: minor faults
         PROC_SPACE_TERM,
-        PROC_SPACE_TERM|PROC_OUT_LONG,                  // 11: major faults
+        PROC_SPACE_TERM|PROC_OUT_LONG,                  // 12: major faults
         PROC_SPACE_TERM,
-        PROC_SPACE_TERM|PROC_OUT_LONG,                  // 13: utime
-        PROC_SPACE_TERM|PROC_OUT_LONG,                  // 14: stime
+        PROC_SPACE_TERM|PROC_OUT_LONG,                  // 14: utime
+        PROC_SPACE_TERM|PROC_OUT_LONG,                  // 15: stime
         PROC_SPACE_TERM,
         PROC_SPACE_TERM,
         PROC_SPACE_TERM,
         PROC_SPACE_TERM,
         PROC_SPACE_TERM,
         PROC_SPACE_TERM,
-        PROC_SPACE_TERM|PROC_OUT_LONG,                  // 21: vsize
+        PROC_SPACE_TERM,
+        PROC_SPACE_TERM|PROC_OUT_LONG,                  // 23: vsize
     };
 
     static final int PROCESS_FULL_STAT_MINOR_FAULTS = 1;
@@ -190,6 +191,10 @@
         public String name;
         public int nameWidth;
 
+        // vsize capture when process first detected; can be used to
+        // filter out kernel processes.
+        public long vsize;
+
         public long base_uptime;
         public long rel_uptime;
 
@@ -444,6 +449,7 @@
                     // are actually kernel threads...  do we want to?  Some
                     // of them do use CPU, but there can be a *lot* that are
                     // not doing anything.
+                    st.vsize = procStats[PROCESS_FULL_STAT_VSIZE];
                     if (true || procStats[PROCESS_FULL_STAT_VSIZE] != 0) {
                         st.interesting = true;
                         st.baseName = procStatsString[0];
diff --git a/core/java/com/android/internal/util/MemInfoReader.java b/core/java/com/android/internal/util/MemInfoReader.java
index 850e1f0..ad65433 100644
--- a/core/java/com/android/internal/util/MemInfoReader.java
+++ b/core/java/com/android/internal/util/MemInfoReader.java
@@ -18,6 +18,7 @@
 
 import java.io.FileInputStream;
 
+import android.os.Debug;
 import android.os.StrictMode;
 
 public class MemInfoReader {
@@ -63,34 +64,11 @@
         // /proc/ and /sys/ files perhaps?
         StrictMode.ThreadPolicy savedPolicy = StrictMode.allowThreadDiskReads();
         try {
-            mTotalSize = 0;
-            mFreeSize = 0;
-            mCachedSize = 0;
-            FileInputStream is = new FileInputStream("/proc/meminfo");
-            int len = is.read(mBuffer);
-            is.close();
-            final int BUFLEN = mBuffer.length;
-            int count = 0;
-            for (int i=0; i<len && count < 3; i++) {
-                if (matchText(mBuffer, i, "MemTotal")) {
-                    i += 8;
-                    mTotalSize = extractMemValue(mBuffer, i);
-                    count++;
-                } else if (matchText(mBuffer, i, "MemFree")) {
-                    i += 7;
-                    mFreeSize = extractMemValue(mBuffer, i);
-                    count++;
-                } else if (matchText(mBuffer, i, "Cached")) {
-                    i += 6;
-                    mCachedSize = extractMemValue(mBuffer, i);
-                    count++;
-                }
-                while (i < BUFLEN && mBuffer[i] != '\n') {
-                    i++;
-                }
-            }
-        } catch (java.io.FileNotFoundException e) {
-        } catch (java.io.IOException e) {
+            long[] infos = new long[Debug.MEMINFO_COUNT];
+            Debug.getMemInfo(infos);
+            mTotalSize = infos[Debug.MEMINFO_TOTAL] * 1024;
+            mFreeSize = infos[Debug.MEMINFO_FREE] * 1024;
+            mCachedSize = infos[Debug.MEMINFO_CACHED] * 1024;
         } finally {
             StrictMode.setThreadPolicy(savedPolicy);
         }
diff --git a/core/jni/android_os_Debug.cpp b/core/jni/android_os_Debug.cpp
index 1779c9f..60540f4 100644
--- a/core/jni/android_os_Debug.cpp
+++ b/core/jni/android_os_Debug.cpp
@@ -516,6 +516,87 @@
     return android_os_Debug_getPssPid(env, clazz, getpid(), NULL);
 }
 
+static void android_os_Debug_getMemInfo(JNIEnv *env, jobject clazz, jlongArray out)
+{
+    char buffer[1024];
+    int numFound = 0;
+
+    if (out == NULL) {
+        jniThrowNullPointerException(env, "out == null");
+        return;
+    }
+
+    int fd = open("/proc/meminfo", O_RDONLY);
+
+    if (fd < 0) {
+        printf("Unable to open /proc/meminfo: %s\n", strerror(errno));
+        return;
+    }
+
+    const int len = read(fd, buffer, sizeof(buffer)-1);
+    close(fd);
+
+    if (len < 0) {
+        printf("Empty /proc/meminfo");
+        return;
+    }
+    buffer[len] = 0;
+
+    static const char* const tags[] = {
+            "MemTotal:",
+            "MemFree:",
+            "Buffers:",
+            "Cached:",
+            "Shmem:",
+            "Slab:",
+            NULL
+    };
+    static const int tagsLen[] = {
+            9,
+            8,
+            8,
+            7,
+            6,
+            5,
+            0
+    };
+    long mem[] = { 0, 0, 0, 0, 0, 0 };
+
+    char* p = buffer;
+    while (*p && numFound < 6) {
+        int i = 0;
+        while (tags[i]) {
+            if (strncmp(p, tags[i], tagsLen[i]) == 0) {
+                p += tagsLen[i];
+                while (*p == ' ') p++;
+                char* num = p;
+                while (*p >= '0' && *p <= '9') p++;
+                if (*p != 0) {
+                    *p = 0;
+                    p++;
+                }
+                mem[i] = atoll(num);
+                numFound++;
+                break;
+            }
+            i++;
+        }
+        while (*p && *p != '\n') {
+            p++;
+        }
+        if (*p) p++;
+    }
+
+    int maxNum = env->GetArrayLength(out);
+    jlong* outArray = env->GetLongArrayElements(out, 0);
+    if (outArray != NULL) {
+        for (int i=0; i<maxNum && tags[i]; i++) {
+            outArray[i] = mem[i];
+        }
+    }
+    env->ReleaseLongArrayElements(out, outArray, 0);
+}
+
 static jint read_binder_stat(const char* stat)
 {
     FILE* fp = fopen(BINDER_STATS, "r");
@@ -790,6 +871,8 @@
             (void*) android_os_Debug_getPss },
     { "getPss",                 "(I[J)J",
             (void*) android_os_Debug_getPssPid },
+    { "getMemInfo",             "([J)V",
+            (void*) android_os_Debug_getMemInfo },
     { "dumpNativeHeap",         "(Ljava/io/FileDescriptor;)V",
             (void*) android_os_Debug_dumpNativeHeap },
     { "getBinderSentTransactions", "()I",
diff --git a/core/res/res/values-mcc510-mnc21/config.xml b/core/res/res/values-mcc510-mnc21/config.xml
new file mode 100644
index 0000000..1fd9dfa
--- /dev/null
+++ b/core/res/res/values-mcc510-mnc21/config.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 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 xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- Don't use roaming icon for considered operators -->
+    <string-array translatable="false" name="config_operatorConsideredNonRoaming">
+        <item>51001</item>
+    </string-array>
+</resources>
diff --git a/data/fonts/Android.mk b/data/fonts/Android.mk
index 0d9a386..2846e61 100644
--- a/data/fonts/Android.mk
+++ b/data/fonts/Android.mk
@@ -138,8 +138,7 @@
     DroidSansHebrew-Regular.ttf \
     DroidSansHebrew-Bold.ttf \
     DroidSansArmenian.ttf \
-    DroidSansGeorgian.ttf \
-    AndroidEmoji.ttf
+    DroidSansGeorgian.ttf
 
 endif # !MINIMAL_FONT
 
diff --git a/data/fonts/AndroidEmoji.ttf b/data/fonts/AndroidEmoji.ttf
deleted file mode 100644
index 569cbab..0000000
--- a/data/fonts/AndroidEmoji.ttf
+++ /dev/null
Binary files differ
diff --git a/data/fonts/fallback_fonts.xml b/data/fonts/fallback_fonts.xml
index 1198aba..69db6aa 100644
--- a/data/fonts/fallback_fonts.xml
+++ b/data/fonts/fallback_fonts.xml
@@ -186,7 +186,7 @@
     </family>
     <family>
         <fileset>
-            <file>AndroidEmoji.ttf</file>
+            <file>NotoColorEmoji.ttf</file>
         </fileset>
     </family>
     <family>
diff --git a/data/fonts/fonts.mk b/data/fonts/fonts.mk
index 05cca13e..a677c4f 100644
--- a/data/fonts/fonts.mk
+++ b/data/fonts/fonts.mk
@@ -43,7 +43,6 @@
     DroidSansMono.ttf \
     DroidSansArmenian.ttf \
     DroidSansGeorgian.ttf \
-    AndroidEmoji.ttf \
     Clockopia.ttf \
     AndroidClock.ttf \
     AndroidClock_Highlight.ttf \
diff --git a/docs/html/guide/topics/manifest/uses-sdk-element.jd b/docs/html/guide/topics/manifest/uses-sdk-element.jd
index 18e479f..07b08f6 100644
--- a/docs/html/guide/topics/manifest/uses-sdk-element.jd
+++ b/docs/html/guide/topics/manifest/uses-sdk-element.jd
@@ -1,4 +1,4 @@
-fpage.title=&lt;uses-sdk&gt;
+page.title=&lt;uses-sdk&gt;
 page.tags="api levels","sdk version","minsdkversion","targetsdkversion","maxsdkversion"
 @jd:body
 
diff --git a/obex/javax/obex/ClientOperation.java b/obex/javax/obex/ClientOperation.java
index 294b502..0c65283 100644
--- a/obex/javax/obex/ClientOperation.java
+++ b/obex/javax/obex/ClientOperation.java
@@ -121,6 +121,13 @@
                     (header).mAuthResp.length);
 
         }
+
+        if ((header).mConnectionID != null) {
+            mRequestHeader.mConnectionID = new byte[4];
+            System.arraycopy((header).mConnectionID, 0, mRequestHeader.mConnectionID, 0,
+                    4);
+
+        }
     }
 
     /**
@@ -420,7 +427,7 @@
                 //split the headerArray
                 end = ObexHelper.findHeaderEnd(headerArray, start, mMaxPacketSize
                         - ObexHelper.BASE_PACKET_LENGTH);
-                // can not split 
+                // can not split
                 if (end == -1) {
                     mOperationDone = true;
                     abort();
@@ -521,7 +528,7 @@
             return false;
         }
 
-        // send all of the output data in 0x48, 
+        // send all of the output data in 0x48,
         // send 0x49 with empty body
         if ((mPrivateOutput != null) && (mPrivateOutput.size() > 0))
             returnValue = true;
diff --git a/obex/javax/obex/ServerSession.java b/obex/javax/obex/ServerSession.java
index a4b9759..f1b9a0d 100644
--- a/obex/javax/obex/ServerSession.java
+++ b/obex/javax/obex/ServerSession.java
@@ -256,6 +256,10 @@
     public void sendResponse(int code, byte[] header) throws IOException {
         int totalLength = 3;
         byte[] data = null;
+        OutputStream op = mOutput;
+        if (op == null) {
+            return;
+        }
 
         if (header != null) {
             totalLength += header.length;
@@ -270,8 +274,8 @@
             data[1] = (byte)0x00;
             data[2] = (byte)totalLength;
         }
-        mOutput.write(data);
-        mOutput.flush();
+        op.write(data);
+        op.flush();
     }
 
     /**
diff --git a/packages/DocumentsUI/res/layout/item_doc_grid.xml b/packages/DocumentsUI/res/layout/item_doc_grid.xml
index 3cfae64..b745bb9 100644
--- a/packages/DocumentsUI/res/layout/item_doc_grid.xml
+++ b/packages/DocumentsUI/res/layout/item_doc_grid.xml
@@ -30,6 +30,7 @@
             android:layout_width="match_parent"
             android:layout_height="0dip"
             android:layout_weight="1"
+            android:layout_marginBottom="6dp"
             android:background="#fff">
 
             <FrameLayout
@@ -63,10 +64,10 @@
         </FrameLayout>
 
         <LinearLayout
+            android:id="@+id/line1"
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
             android:orientation="horizontal"
-            android:paddingTop="6dp"
             android:paddingStart="?android:attr/listPreferredItemPaddingStart"
             android:paddingEnd="?android:attr/listPreferredItemPaddingEnd">
 
@@ -121,6 +122,20 @@
                 android:textAlignment="viewStart"
                 style="@style/TextAppearance.Small" />
 
+            <Space
+                android:layout_width="0dp"
+                android:layout_height="0dp"
+                android:layout_weight="1" />
+
+            <ImageView
+                android:id="@android:id/icon2"
+                android:layout_width="@dimen/root_icon_size"
+                android:layout_height="@dimen/root_icon_size"
+                android:layout_marginStart="8dip"
+                android:scaleType="centerInside"
+                android:contentDescription="@null"
+                android:visibility="gone" />
+
         </LinearLayout>
 
     </LinearLayout>
diff --git a/packages/DocumentsUI/res/menu/activity.xml b/packages/DocumentsUI/res/menu/activity.xml
index 6c37a4e..d995376 100644
--- a/packages/DocumentsUI/res/menu/activity.xml
+++ b/packages/DocumentsUI/res/menu/activity.xml
@@ -19,7 +19,7 @@
         android:id="@+id/menu_create_dir"
         android:title="@string/menu_create_dir"
         android:icon="@drawable/ic_menu_new_folder"
-        android:showAsAction="ifRoom" />
+        android:showAsAction="always" />
     <item
         android:id="@+id/menu_search"
         android:title="@string/menu_search"
@@ -48,12 +48,12 @@
         android:id="@+id/menu_grid"
         android:title="@string/menu_grid"
         android:icon="@drawable/ic_menu_view_grid"
-        android:showAsAction="ifRoom" />
+        android:showAsAction="never" />
     <item
         android:id="@+id/menu_list"
         android:title="@string/menu_list"
         android:icon="@drawable/ic_menu_view_list"
-        android:showAsAction="ifRoom" />
+        android:showAsAction="never" />
     <item
         android:id="@+id/menu_settings"
         android:title="@string/menu_settings"
diff --git a/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java b/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java
index b2981db..198927c 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java
@@ -102,6 +102,8 @@
     private int mLastSortOrder = SORT_ORDER_UNKNOWN;
     private boolean mLastShowSize = false;
 
+    private boolean mHideGridTitles = false;
+
     private Point mThumbSize;
 
     private DocumentsAdapter mAdapter;
@@ -112,11 +114,6 @@
     private static final String EXTRA_DOC = "doc";
     private static final String EXTRA_QUERY = "query";
 
-    /**
-     * MIME types that should always show thumbnails in list mode.
-     */
-    private static final String[] LIST_THUMBNAIL_MIMES = new String[] { "image/*", "video/*" };
-
     private static AtomicInteger sLoaderId = new AtomicInteger(4000);
 
     private final int mLoaderId = sLoaderId.incrementAndGet();
@@ -125,9 +122,8 @@
         show(fm, TYPE_NORMAL, root, doc, null);
     }
 
-    public static void showSearch(
-            FragmentManager fm, RootInfo root, DocumentInfo doc, String query) {
-        show(fm, TYPE_SEARCH, root, doc, query);
+    public static void showSearch(FragmentManager fm, RootInfo root, String query) {
+        show(fm, TYPE_SEARCH, root, null, query);
     }
 
     public static void showRecentsOpen(FragmentManager fm) {
@@ -183,14 +179,23 @@
         final Context context = getActivity();
         final State state = getDisplayState(DirectoryFragment.this);
 
+        final RootInfo root = getArguments().getParcelable(EXTRA_ROOT);
+        final DocumentInfo doc = getArguments().getParcelable(EXTRA_DOC);
+
         mAdapter = new DocumentsAdapter();
         mType = getArguments().getInt(EXTRA_TYPE);
 
+        if (mType == TYPE_RECENT_OPEN) {
+            // Hide titles when showing recents for picking images/videos
+            mHideGridTitles = MimePredicate.mimeMatches(
+                    MimePredicate.VISUAL_MIMES, state.acceptMimes);
+        } else {
+            mHideGridTitles = (doc != null) && doc.isGridTitlesHidden();
+        }
+
         mCallbacks = new LoaderCallbacks<DirectoryResult>() {
             @Override
             public Loader<DirectoryResult> onCreateLoader(int id, Bundle args) {
-                final RootInfo root = getArguments().getParcelable(EXTRA_ROOT);
-                final DocumentInfo doc = getArguments().getParcelable(EXTRA_DOC);
                 final String query = getArguments().getString(EXTRA_QUERY);
 
                 Uri contentsUri;
@@ -205,7 +210,7 @@
                                 context, mType, root, doc, contentsUri, state.userSortOrder);
                     case TYPE_SEARCH:
                         contentsUri = DocumentsContract.buildSearchDocumentsUri(
-                                doc.authority, doc.documentId, query);
+                                root.authority, root.rootId, query);
                         if (state.action == ACTION_MANAGE) {
                             contentsUri = DocumentsContract.setManageMode(contentsUri);
                         }
@@ -274,7 +279,7 @@
         final RootInfo root = getArguments().getParcelable(EXTRA_ROOT);
         final DocumentInfo doc = getArguments().getParcelable(EXTRA_DOC);
 
-        if (root != null) {
+        if (root != null && doc != null) {
             final Uri stateUri = RecentsProvider.buildState(
                     root.authority, root.rootId, doc.documentId);
             final ContentValues values = new ContentValues();
@@ -644,6 +649,8 @@
             final Context context = parent.getContext();
             final State state = getDisplayState(DirectoryFragment.this);
 
+            final DocumentInfo doc = getArguments().getParcelable(EXTRA_DOC);
+
             final RootsCache roots = DocumentsApplication.getRootsCache(context);
             final ThumbnailCache thumbs = DocumentsApplication.getThumbnailsCache(
                     context, mThumbSize);
@@ -672,12 +679,15 @@
             final String docSummary = getCursorString(cursor, Document.COLUMN_SUMMARY);
             final long docSize = getCursorLong(cursor, Document.COLUMN_SIZE);
 
+            final View line1 = convertView.findViewById(R.id.line1);
+            final View line2 = convertView.findViewById(R.id.line2);
+
             final View icon = convertView.findViewById(android.R.id.icon);
             final ImageView iconMime = (ImageView) convertView.findViewById(R.id.icon_mime);
             final ImageView iconThumb = (ImageView) convertView.findViewById(R.id.icon_thumb);
             final TextView title = (TextView) convertView.findViewById(android.R.id.title);
-            final View line2 = convertView.findViewById(R.id.line2);
             final ImageView icon1 = (ImageView) convertView.findViewById(android.R.id.icon1);
+            final ImageView icon2 = (ImageView) convertView.findViewById(android.R.id.icon2);
             final TextView summary = (TextView) convertView.findViewById(android.R.id.summary);
             final TextView date = (TextView) convertView.findViewById(R.id.date);
             final TextView size = (TextView) convertView.findViewById(R.id.size);
@@ -693,10 +703,11 @@
 
             final boolean supportsThumbnail = (docFlags & Document.FLAG_SUPPORTS_THUMBNAIL) != 0;
             final boolean allowThumbnail = (state.derivedMode == MODE_GRID)
-                    || MimePredicate.mimeMatches(LIST_THUMBNAIL_MIMES, docMimeType);
+                    || MimePredicate.mimeMatches(MimePredicate.VISUAL_MIMES, docMimeType);
+            final boolean showThumbnail = supportsThumbnail && allowThumbnail;
 
             boolean cacheHit = false;
-            if (supportsThumbnail && allowThumbnail) {
+            if (showThumbnail) {
                 final Uri uri = DocumentsContract.buildDocumentUri(docAuthority, docId);
                 final Bitmap cachedResult = thumbs.get(uri);
                 if (cachedResult != null) {
@@ -727,15 +738,19 @@
                 }
             }
 
-            title.setText(docDisplayName);
-
+            boolean hasLine1 = false;
             boolean hasLine2 = false;
 
+            final boolean hideTitle = (state.derivedMode == MODE_GRID) && mHideGridTitles;
+            if (!hideTitle) {
+                title.setText(docDisplayName);
+                hasLine1 = true;
+            }
+
+            Drawable iconDrawable = null;
             if (mType == TYPE_RECENT_OPEN) {
                 final RootInfo root = roots.getRoot(docAuthority, docRootId);
-                final Drawable iconDrawable = root.loadIcon(context);
-                icon1.setVisibility(View.VISIBLE);
-                icon1.setImageDrawable(iconDrawable);
+                iconDrawable = root.loadIcon(context);
 
                 if (summary != null) {
                     final boolean alwaysShowSummary = getResources()
@@ -757,7 +772,13 @@
                     }
                 }
             } else {
-                icon1.setVisibility(View.GONE);
+                // Directories showing thumbnails in grid mode get a little icon
+                // hint to remind user they're a directory.
+                if (Document.MIME_TYPE_DIR.equals(docMimeType) && state.derivedMode == MODE_GRID
+                        && showThumbnail) {
+                    iconDrawable = context.getResources().getDrawable(R.drawable.ic_root_folder);
+                }
+
                 if (summary != null) {
                     if (docSummary != null) {
                         summary.setText(docSummary);
@@ -769,6 +790,19 @@
                 }
             }
 
+            if (icon1 != null) icon1.setVisibility(View.GONE);
+            if (icon2 != null) icon2.setVisibility(View.GONE);
+
+            if (iconDrawable != null) {
+                if (hasLine1) {
+                    icon1.setVisibility(View.VISIBLE);
+                    icon1.setImageDrawable(iconDrawable);
+                } else {
+                    icon2.setVisibility(View.VISIBLE);
+                    icon2.setImageDrawable(iconDrawable);
+                }
+            }
+
             if (docLastModified == -1) {
                 date.setText(null);
             } else {
@@ -788,6 +822,9 @@
                 size.setVisibility(View.GONE);
             }
 
+            if (line1 != null) {
+                line1.setVisibility(hasLine1 ? View.VISIBLE : View.GONE);
+            }
             if (line2 != null) {
                 line2.setVisibility(hasLine2 ? View.VISIBLE : View.GONE);
             }
@@ -797,11 +834,13 @@
             if (enabled) {
                 setEnabledRecursive(convertView, true);
                 icon.setAlpha(1f);
-                icon1.setAlpha(1f);
+                if (icon1 != null) icon1.setAlpha(1f);
+                if (icon2 != null) icon2.setAlpha(1f);
             } else {
                 setEnabledRecursive(convertView, false);
                 icon.setAlpha(0.5f);
-                icon1.setAlpha(0.5f);
+                if (icon1 != null) icon1.setAlpha(0.5f);
+                if (icon2 != null) icon2.setAlpha(0.5f);
             }
 
             return convertView;
@@ -944,6 +983,7 @@
     }
 
     private void setEnabledRecursive(View v, boolean enabled) {
+        if (v == null) return;
         if (v.isEnabled() == enabled) return;
         v.setEnabled(enabled);
 
diff --git a/packages/DocumentsUI/src/com/android/documentsui/DirectoryLoader.java b/packages/DocumentsUI/src/com/android/documentsui/DirectoryLoader.java
index 334e262..8627ecf 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/DirectoryLoader.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/DirectoryLoader.java
@@ -32,6 +32,7 @@
 import android.net.Uri;
 import android.os.CancellationSignal;
 import android.os.OperationCanceledException;
+import android.provider.DocumentsContract;
 import android.provider.DocumentsContract.Document;
 import android.util.Log;
 
@@ -42,6 +43,8 @@
 
 import libcore.io.IoUtils;
 
+import java.io.FileNotFoundException;
+
 class DirectoryResult implements AutoCloseable {
     ContentProviderClient client;
     Cursor cursor;
@@ -64,7 +67,7 @@
 
     private final int mType;
     private final RootInfo mRoot;
-    private final DocumentInfo mDoc;
+    private DocumentInfo mDoc;
     private final Uri mUri;
     private final int mUserSortOrder;
 
@@ -97,6 +100,19 @@
 
         int userMode = State.MODE_UNKNOWN;
 
+        // Use default document when searching
+        if (mType == DirectoryFragment.TYPE_SEARCH) {
+            final Uri docUri = DocumentsContract.buildDocumentUri(
+                    mRoot.authority, mRoot.documentId);
+            try {
+                mDoc = DocumentInfo.fromUri(resolver, docUri);
+            } catch (FileNotFoundException e) {
+                Log.w(TAG, "Failed to query", e);
+                result.exception = e;
+                return result;
+            }
+        }
+
         // Pick up any custom modes requested by user
         Cursor cursor = null;
         try {
@@ -157,7 +173,7 @@
 
             result.cursor = cursor;
         } catch (Exception e) {
-            Log.d(TAG, "Failed to query", e);
+            Log.w(TAG, "Failed to query", e);
             result.exception = e;
             ContentProviderClient.closeQuietly(result.client);
         } finally {
diff --git a/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java b/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java
index eb51fb5..f6cb481 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java
@@ -45,6 +45,7 @@
 import android.os.Bundle;
 import android.os.Parcel;
 import android.provider.DocumentsContract;
+import android.provider.DocumentsContract.Root;
 import android.support.v4.app.ActionBarDrawerToggle;
 import android.support.v4.view.GravityCompat;
 import android.support.v4.widget.DrawerLayout;
@@ -243,6 +244,7 @@
         } else {
             // Restore last stack for calling package
             // TODO: move into async loader
+            boolean restoredStack = false;
             final String packageName = getCallingPackage();
             final Cursor cursor = getContentResolver()
                     .query(RecentsProvider.buildResume(packageName), null, null, null, null);
@@ -251,6 +253,7 @@
                     final byte[] rawStack = cursor.getBlob(
                             cursor.getColumnIndex(ResumeColumns.STACK));
                     DurableUtils.readFromArray(rawStack, mState.stack);
+                    restoredStack = true;
                 }
             } catch (IOException e) {
                 Log.w(TAG, "Failed to resume", e);
@@ -263,10 +266,13 @@
             final List<RootInfo> matchingRoots = mRoots.getMatchingRoots(mState);
             if (!matchingRoots.contains(root)) {
                 mState.stack.reset();
+                restoredStack = false;
             }
 
-            // Only open drawer when showing recents
-            if (mState.stack.isRecents()) {
+            // Only open drawer when not restoring stack, and when not showing
+            // visual content.
+            if (!restoredStack
+                    && !MimePredicate.mimeMatches(MimePredicate.VISUAL_MIMES, mState.acceptMimes)) {
                 setRootsDrawerOpen(true);
             }
         }
@@ -442,6 +448,8 @@
         super.onPrepareOptionsMenu(menu);
 
         final FragmentManager fm = getFragmentManager();
+
+        final RootInfo root = getCurrentRoot();
         final DocumentInfo cwd = getCurrentDirectory();
 
         final MenuItem createDir = menu.findItem(R.id.menu_create_dir);
@@ -503,7 +511,9 @@
             SaveFragment.get(fm).setSaveEnabled(cwd != null && cwd.isCreateSupported());
         } else {
             createDir.setVisible(false);
-            searchVisible = cwd != null && cwd.isSearchSupported();
+
+            searchVisible = root != null
+                    && ((root.flags & Root.FLAG_SUPPORTS_SEARCH) != 0);
         }
 
         // TODO: close any search in-progress when hiding
@@ -722,7 +732,7 @@
         } else {
             if (mState.currentSearch != null) {
                 // Ongoing search
-                DirectoryFragment.showSearch(fm, root, cwd, mState.currentSearch);
+                DirectoryFragment.showSearch(fm, root, mState.currentSearch);
             } else {
                 // Normal boring directory
                 DirectoryFragment.showNormal(fm, root, cwd);
diff --git a/packages/DocumentsUI/src/com/android/documentsui/MimePredicate.java b/packages/DocumentsUI/src/com/android/documentsui/MimePredicate.java
index b55ce82..2d96876 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/MimePredicate.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/MimePredicate.java
@@ -22,6 +22,12 @@
 public class MimePredicate implements Predicate<DocumentInfo> {
     private final String[] mFilters;
 
+    /**
+     * MIME types that are visual in nature. For example, they should always be
+     * shown as thumbnails in list mode.
+     */
+    public static final String[] VISUAL_MIMES = new String[] { "image/*", "video/*" };
+
     public MimePredicate(String[] filters) {
         mFilters = filters;
     }
diff --git a/packages/DocumentsUI/src/com/android/documentsui/RecentLoader.java b/packages/DocumentsUI/src/com/android/documentsui/RecentLoader.java
index a7173b6..1912010 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/RecentLoader.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/RecentLoader.java
@@ -27,6 +27,7 @@
 import android.database.MergeCursor;
 import android.net.Uri;
 import android.provider.DocumentsContract;
+import android.provider.DocumentsContract.Document;
 import android.provider.DocumentsContract.Root;
 import android.util.Log;
 
@@ -176,7 +177,7 @@
                 try {
                     final Cursor cursor = task.get();
                     final FilteringCursorWrapper filtered = new FilteringCursorWrapper(
-                            cursor, mAcceptMimes) {
+                            cursor, mAcceptMimes, new String[] { Document.MIME_TYPE_DIR }) {
                         @Override
                         public void close() {
                             // Ignored, since we manage cursor lifecycle internally
diff --git a/packages/DocumentsUI/src/com/android/documentsui/RootsCache.java b/packages/DocumentsUI/src/com/android/documentsui/RootsCache.java
index b48674cf..9b54948 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/RootsCache.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/RootsCache.java
@@ -137,12 +137,14 @@
 
     @GuardedBy("ActivityThread")
     public boolean isIconUnique(RootInfo root) {
+        final int rootIcon = root.derivedIcon != 0 ? root.derivedIcon : root.icon;
         for (RootInfo test : mRoots) {
             if (Objects.equal(test.authority, root.authority)) {
                 if (Objects.equal(test.rootId, root.rootId)) {
                     continue;
                 }
-                if (test.icon == root.icon) {
+                final int testIcon = test.derivedIcon != 0 ? test.derivedIcon : test.icon;
+                if (testIcon == rootIcon) {
                     return false;
                 }
             }
@@ -176,6 +178,7 @@
             final boolean supportsCreate = (root.flags & Root.FLAG_SUPPORTS_CREATE) != 0;
             final boolean advanced = (root.flags & Root.FLAG_ADVANCED) != 0;
             final boolean localOnly = (root.flags & Root.FLAG_LOCAL_ONLY) != 0;
+            final boolean empty = (root.flags & Root.FLAG_EMPTY) != 0;
 
             // Exclude read-only devices when creating
             if (state.action == State.ACTION_CREATE && !supportsCreate) continue;
@@ -183,6 +186,8 @@
             if (!state.showAdvanced && advanced) continue;
             // Exclude non-local devices when local only
             if (state.localOnly && !localOnly) continue;
+            // Only show empty roots when creating
+            if (state.action != State.ACTION_CREATE && empty) continue;
 
             // Only include roots that serve requested content
             final boolean overlap =
diff --git a/packages/DocumentsUI/src/com/android/documentsui/RootsFragment.java b/packages/DocumentsUI/src/com/android/documentsui/RootsFragment.java
index 54dcf1c..908729c 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/RootsFragment.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/RootsFragment.java
@@ -35,6 +35,7 @@
 import android.widget.ArrayAdapter;
 import android.widget.ImageView;
 import android.widget.ListView;
+import android.widget.Space;
 import android.widget.TextView;
 
 import com.android.documentsui.DocumentsActivity.State;
@@ -136,11 +137,8 @@
     };
 
     private static class RootsAdapter extends ArrayAdapter<RootInfo> implements SectionAdapter {
-        private int mHeaderId;
-
-        public RootsAdapter(Context context, int headerId) {
+        public RootsAdapter(Context context) {
             super(context, 0);
-            mHeaderId = headerId;
         }
 
         @Override
@@ -177,13 +175,8 @@
         @Override
         public View getHeaderView(View convertView, ViewGroup parent) {
             if (convertView == null) {
-                convertView = LayoutInflater.from(parent.getContext())
-                        .inflate(R.layout.item_root_header, parent, false);
+                convertView = new Space(parent.getContext());
             }
-
-            final TextView title = (TextView) convertView.findViewById(android.R.id.title);
-            title.setText(mHeaderId);
-
             return convertView;
         }
     }
@@ -237,9 +230,9 @@
         private final AppsAdapter mApps;
 
         public SectionedRootsAdapter(Context context, List<RootInfo> roots, Intent includeApps) {
-            mServices = new RootsAdapter(context, R.string.root_type_service);
-            mShortcuts = new RootsAdapter(context, R.string.root_type_shortcut);
-            mDevices = new RootsAdapter(context, R.string.root_type_device);
+            mServices = new RootsAdapter(context);
+            mShortcuts = new RootsAdapter(context);
+            mDevices = new RootsAdapter(context);
             mApps = new AppsAdapter(context);
 
             for (RootInfo root : roots) {
@@ -274,15 +267,15 @@
             mShortcuts.sort(comp);
             mDevices.sort(comp);
 
-            if (mServices.getCount() > 0) {
-                addSection(mServices);
-            }
             if (mShortcuts.getCount() > 0) {
                 addSection(mShortcuts);
             }
             if (mDevices.getCount() > 0) {
                 addSection(mDevices);
             }
+            if (mServices.getCount() > 0) {
+                addSection(mServices);
+            }
             if (mApps.getCount() > 0) {
                 addSection(mApps);
             }
diff --git a/packages/DocumentsUI/src/com/android/documentsui/model/DocumentInfo.java b/packages/DocumentsUI/src/com/android/documentsui/model/DocumentInfo.java
index c69103e..681cc9b 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/model/DocumentInfo.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/model/DocumentInfo.java
@@ -188,10 +188,6 @@
         return (flags & Document.FLAG_DIR_SUPPORTS_CREATE) != 0;
     }
 
-    public boolean isSearchSupported() {
-        return (flags & Document.FLAG_DIR_SUPPORTS_SEARCH) != 0;
-    }
-
     public boolean isThumbnailSupported() {
         return (flags & Document.FLAG_SUPPORTS_THUMBNAIL) != 0;
     }
@@ -208,6 +204,10 @@
         return (flags & Document.FLAG_SUPPORTS_DELETE) != 0;
     }
 
+    public boolean isGridTitlesHidden() {
+        return (flags & Document.FLAG_DIR_HIDE_GRID_TITLES) != 0;
+    }
+
     public static String getCursorString(Cursor cursor, String columnName) {
         final int index = cursor.getColumnIndex(columnName);
         return (index != -1) ? cursor.getString(index) : null;
diff --git a/packages/DocumentsUI/src/com/android/documentsui/model/RootInfo.java b/packages/DocumentsUI/src/com/android/documentsui/model/RootInfo.java
index b5a198c..1afc80a 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/model/RootInfo.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/model/RootInfo.java
@@ -161,15 +161,21 @@
 
         // TODO: remove these special case icons
         if ("com.android.externalstorage.documents".equals(authority)) {
-            derivedIcon = R.drawable.ic_root_sdcard;
+            if ("documents".equals(rootId)) {
+                derivedIcon = R.drawable.ic_doc_text;
+            } else {
+                derivedIcon = R.drawable.ic_root_sdcard;
+            }
         }
         if ("com.android.providers.downloads.documents".equals(authority)) {
             derivedIcon = R.drawable.ic_root_download;
         }
         if ("com.android.providers.media.documents".equals(authority)) {
-            if ("image".equals(rootId)) {
+            if ("images_root".equals(rootId)) {
                 derivedIcon = R.drawable.ic_doc_image;
-            } else if ("audio".equals(rootId)) {
+            } else if ("videos_root".equals(rootId)) {
+                derivedIcon = R.drawable.ic_doc_video;
+            } else if ("audio_root".equals(rootId)) {
                 derivedIcon = R.drawable.ic_doc_audio;
             }
         }
diff --git a/packages/ExternalStorageProvider/res/values/strings.xml b/packages/ExternalStorageProvider/res/values/strings.xml
index 0eaf500a..f1c1ade 100644
--- a/packages/ExternalStorageProvider/res/values/strings.xml
+++ b/packages/ExternalStorageProvider/res/values/strings.xml
@@ -15,6 +15,11 @@
 -->
 
 <resources>
+    <!-- Title of the external storage application [CHAR LIMIT=32] -->
     <string name="app_label">External Storage</string>
+
+    <!-- Title for documents backend that offers internal storage. [CHAR LIMIT=24] -->
     <string name="root_internal_storage">Internal storage</string>
+    <!-- Title for documents backend that offers documents. [CHAR LIMIT=24] -->
+    <string name="root_documents">Documents</string>
 </resources>
diff --git a/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java b/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java
index ada3ad7..3e2cd15 100644
--- a/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java
+++ b/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java
@@ -62,7 +62,6 @@
         public String rootId;
         public int rootType;
         public int flags;
-        public int icon;
         public String title;
         public String docId;
     }
@@ -85,9 +84,10 @@
             mIdToPath.put(rootId, path);
 
             final RootInfo root = new RootInfo();
-            root.rootId = "primary";
+            root.rootId = rootId;
             root.rootType = Root.ROOT_TYPE_DEVICE;
-            root.flags = Root.FLAG_SUPPORTS_CREATE | Root.FLAG_LOCAL_ONLY | Root.FLAG_ADVANCED;
+            root.flags = Root.FLAG_SUPPORTS_CREATE | Root.FLAG_LOCAL_ONLY | Root.FLAG_ADVANCED
+                    | Root.FLAG_SUPPORTS_SEARCH;
             root.title = getContext().getString(R.string.root_internal_storage);
             root.docId = getDocIdForFile(path);
             mRoots.add(root);
@@ -96,6 +96,25 @@
             throw new IllegalStateException(e);
         }
 
+        try {
+            final String rootId = "documents";
+            final File path = Environment.getExternalStoragePublicDirectory(
+                    Environment.DIRECTORY_DOCUMENTS);
+            mIdToPath.put(rootId, path);
+
+            final RootInfo root = new RootInfo();
+            root.rootId = rootId;
+            root.rootType = Root.ROOT_TYPE_SHORTCUT;
+            root.flags = Root.FLAG_SUPPORTS_CREATE | Root.FLAG_LOCAL_ONLY
+                    | Root.FLAG_SUPPORTS_SEARCH;
+            root.title = getContext().getString(R.string.root_documents);
+            root.docId = getDocIdForFile(path);
+            mRoots.add(root);
+            mIdToRoot.put(rootId, root);
+        } catch (FileNotFoundException e) {
+            throw new IllegalStateException(e);
+        }
+
         return true;
     }
 
@@ -146,6 +165,9 @@
         if (target == null) {
             throw new FileNotFoundException("No root for " + tag);
         }
+        if (!target.exists()) {
+            target.mkdirs();
+        }
         target = new File(target, path);
         if (!target.exists()) {
             throw new FileNotFoundException("Missing file for " + docId + " at " + target);
@@ -163,9 +185,6 @@
 
         int flags = 0;
 
-        if (file.isDirectory()) {
-            flags |= Document.FLAG_DIR_SUPPORTS_SEARCH;
-        }
         if (file.isDirectory() && file.canWrite()) {
             flags |= Document.FLAG_DIR_SUPPORTS_CREATE;
         }
@@ -200,7 +219,6 @@
             row.add(Root.COLUMN_ROOT_ID, root.rootId);
             row.add(Root.COLUMN_ROOT_TYPE, root.rootType);
             row.add(Root.COLUMN_FLAGS, root.flags);
-            row.add(Root.COLUMN_ICON, root.icon);
             row.add(Root.COLUMN_TITLE, root.title);
             row.add(Root.COLUMN_DOCUMENT_ID, root.docId);
             row.add(Root.COLUMN_AVAILABLE_BYTES, path.getFreeSpace());
@@ -260,10 +278,10 @@
     }
 
     @Override
-    public Cursor querySearchDocuments(String parentDocumentId, String query, String[] projection)
+    public Cursor querySearchDocuments(String rootId, String query, String[] projection)
             throws FileNotFoundException {
         final MatrixCursor result = new MatrixCursor(resolveDocumentProjection(projection));
-        final File parent = getFileForDocId(parentDocumentId);
+        final File parent = mIdToPath.get(rootId);
 
         final LinkedList<File> pending = new LinkedList<File>();
         pending.add(parent);
diff --git a/packages/SystemUI/res/values-az-rAZ-land/strings.xml b/packages/SystemUI/res/values-az-rAZ-land/strings.xml
new file mode 100644
index 0000000..8eb6978
--- /dev/null
+++ b/packages/SystemUI/res/values-az-rAZ-land/strings.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/**
+ * Copyright (c) 2010, 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 xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="toast_rotation_locked" msgid="7609673011431556092">"Hazırda ekran landşaft orientasiyasında kilidlənib."</string>
+</resources>
diff --git a/packages/SystemUI/res/values-en-rIN-land/strings.xml b/packages/SystemUI/res/values-en-rIN-land/strings.xml
new file mode 100644
index 0000000..ba773b8
--- /dev/null
+++ b/packages/SystemUI/res/values-en-rIN-land/strings.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/**
+ * Copyright (c) 2010, 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 xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="toast_rotation_locked" msgid="7609673011431556092">"Screen is now locked in landscape orientation."</string>
+</resources>
diff --git a/packages/SystemUI/res/values-et-rEE-land/strings.xml b/packages/SystemUI/res/values-et-rEE-land/strings.xml
new file mode 100644
index 0000000..77b0ce1
--- /dev/null
+++ b/packages/SystemUI/res/values-et-rEE-land/strings.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/**
+ * Copyright (c) 2010, 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 xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="toast_rotation_locked" msgid="7609673011431556092">"Ekraan on nüüd lukustatud horisontaalasendisse."</string>
+</resources>
diff --git a/packages/SystemUI/res/values-fr-rCA-land/strings.xml b/packages/SystemUI/res/values-fr-rCA-land/strings.xml
new file mode 100644
index 0000000..4775fc6
--- /dev/null
+++ b/packages/SystemUI/res/values-fr-rCA-land/strings.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/**
+ * Copyright (c) 2010, 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 xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="toast_rotation_locked" msgid="7609673011431556092">"L\'écran est désormais verrouillé au format paysage."</string>
+</resources>
diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml
index f9ede31..4c3c87f 100644
--- a/packages/SystemUI/res/values-hi/strings.xml
+++ b/packages/SystemUI/res/values-hi/strings.xml
@@ -22,7 +22,7 @@
     <string name="app_label" msgid="7164937344850004466">"सिस्‍टम UI"</string>
     <string name="status_bar_clear_all_button" msgid="7774721344716731603">"साफ़ करें"</string>
     <string name="status_bar_recent_remove_item_title" msgid="6026395868129852968">"सूची से निकालें"</string>
-    <string name="status_bar_recent_inspect_item_title" msgid="7793624864528818569">"एप्‍लिकेशन जानकारी"</string>
+    <string name="status_bar_recent_inspect_item_title" msgid="7793624864528818569">"एप्‍स जानकारी"</string>
     <string name="status_bar_no_recent_apps" msgid="6576392951053994640">"कोई हाल ही के एप्स नहीं"</string>
     <string name="status_bar_accessibility_dismiss_recents" msgid="4576076075226540105">"हाल ही के एप्स खारिज करें"</string>
   <plurals name="status_bar_accessibility_recent_apps">
@@ -40,7 +40,7 @@
     <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"सेटिंग"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
     <string name="status_bar_settings_airplane" msgid="4879879698500955300">"हवाई जहाज मोड"</string>
-    <string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"स्‍क्रीन स्‍वत: घुमाएं"</string>
+    <string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"स्‍क्रीन अपनेआप घुमाएं"</string>
     <string name="status_bar_settings_mute_label" msgid="554682549917429396">"म्यूट करें"</string>
     <string name="status_bar_settings_auto_brightness_label" msgid="511453614962324674">"स्वत:"</string>
     <string name="status_bar_settings_notifications" msgid="397146176280905137">"सूचनाएं"</string>
@@ -75,7 +75,7 @@
     <string name="accessibility_back" msgid="567011538994429120">"वापस जाएं"</string>
     <string name="accessibility_home" msgid="8217216074895377641">"होम"</string>
     <string name="accessibility_menu" msgid="316839303324695949">"मेनू"</string>
-    <string name="accessibility_recent" msgid="8571350598987952883">"हाल ही के एप्‍लिकेशन"</string>
+    <string name="accessibility_recent" msgid="8571350598987952883">"हाल ही के एप्‍स"</string>
     <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"इनपुट पद्धति‍ बटन स्विच करें."</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"संगतता ज़ूम बटन."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"छोटी से बड़ी स्‍क्रीन पर ज़ूम करें."</string>
@@ -144,7 +144,7 @@
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"सूचना खारिज की गई."</string>
     <string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"सूचना शेड."</string>
     <string name="accessibility_desc_quick_settings" msgid="6186378411582437046">"त्वरित सेटिंग."</string>
-    <string name="accessibility_desc_recent_apps" msgid="9014032916410590027">"हाल ही के एप्‍लिकेशन."</string>
+    <string name="accessibility_desc_recent_apps" msgid="9014032916410590027">"हाल ही के एप्‍स."</string>
     <string name="accessibility_quick_settings_user" msgid="1104846699869476855">"उपयोगकर्ता <xliff:g id="USER">%s</xliff:g>."</string>
     <string name="accessibility_quick_settings_wifi" msgid="6099781031669728709">"<xliff:g id="SIGNAL">%1$s</xliff:g>. <xliff:g id="NETWORK">%2$s</xliff:g>"</string>
     <string name="accessibility_quick_settings_mobile" msgid="4876806564086241341">"मोबाइल <xliff:g id="SIGNAL">%1$s</xliff:g>. <xliff:g id="TYPE">%2$s</xliff:g>. <xliff:g id="NETWORK">%3$s</xliff:g>."</string>
@@ -164,7 +164,7 @@
     <string name="gps_notification_found_text" msgid="4619274244146446464">"GPS द्वारा सेट किया गया स्‍थान"</string>
     <string name="accessibility_location_active" msgid="2427290146138169014">"स्थान अनुरोध सक्रिय"</string>
     <string name="accessibility_clear_all" msgid="5235938559247164925">"सभी सूचनाएं साफ़ करें."</string>
-    <string name="status_bar_notification_inspect_item_title" msgid="1163547729015390250">"एप्‍लिकेशन जानकारी"</string>
+    <string name="status_bar_notification_inspect_item_title" msgid="1163547729015390250">"एप्‍स जानकारी"</string>
     <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"स्‍क्रीन स्‍वचालित रूप से घूमेगी."</string>
     <string name="accessibility_rotation_lock_on_landscape" msgid="6731197337665366273">"स्‍क्रीन लैंडस्केप अभिविन्यास में लॉक है."</string>
     <string name="accessibility_rotation_lock_on_portrait" msgid="5809367521644012115">"स्‍क्रीन पोर्ट्रेट अभिविन्‍यास में लॉक है."</string>
diff --git a/packages/SystemUI/res/values-hy-rAM-land/strings.xml b/packages/SystemUI/res/values-hy-rAM-land/strings.xml
new file mode 100644
index 0000000..7c0535c
--- /dev/null
+++ b/packages/SystemUI/res/values-hy-rAM-land/strings.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/**
+ * Copyright (c) 2010, 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 xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="toast_rotation_locked" msgid="7609673011431556092">"Էկրանն այժմ կողպված է հորիզոնական դիրքավորման մեջ:"</string>
+</resources>
diff --git a/packages/SystemUI/res/values-ka-rGE-land/strings.xml b/packages/SystemUI/res/values-ka-rGE-land/strings.xml
new file mode 100644
index 0000000..3f20938
--- /dev/null
+++ b/packages/SystemUI/res/values-ka-rGE-land/strings.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/**
+ * Copyright (c) 2010, 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 xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="toast_rotation_locked" msgid="7609673011431556092">"ეკრანი ამჟამად დაბლოკილია თარაზულ ორიენტაციაში"</string>
+</resources>
diff --git a/packages/SystemUI/res/values-km-rKH-land/strings.xml b/packages/SystemUI/res/values-km-rKH-land/strings.xml
new file mode 100644
index 0000000..f148cc3
--- /dev/null
+++ b/packages/SystemUI/res/values-km-rKH-land/strings.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/**
+ * Copyright (c) 2010, 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 xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="toast_rotation_locked" msgid="7609673011431556092">"ឥឡូវ​អេក្រង់​​ជាប់​សោ​ក្នុង​ទិស​ផ្ដេក។"</string>
+</resources>
diff --git a/packages/SystemUI/res/values-lo-rLA-land/strings.xml b/packages/SystemUI/res/values-lo-rLA-land/strings.xml
new file mode 100644
index 0000000..a838a15
--- /dev/null
+++ b/packages/SystemUI/res/values-lo-rLA-land/strings.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/**
+ * Copyright (c) 2010, 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 xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="toast_rotation_locked" msgid="7609673011431556092">"ໜ້າຈໍຕອນນີ້ຖືກລັອກໄວ້ໃນແບບລວງນອນ."</string>
+</resources>
diff --git a/packages/SystemUI/res/values-mn-rMN-land/strings.xml b/packages/SystemUI/res/values-mn-rMN-land/strings.xml
new file mode 100644
index 0000000..ec4616f
--- /dev/null
+++ b/packages/SystemUI/res/values-mn-rMN-land/strings.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/**
+ * Copyright (c) 2010, 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 xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="toast_rotation_locked" msgid="7609673011431556092">"Дэлгэц хэвтээ чиглэлд түгжигдсэн."</string>
+</resources>
diff --git a/packages/SystemUI/res/values-ms-rMY-land/strings.xml b/packages/SystemUI/res/values-ms-rMY-land/strings.xml
new file mode 100644
index 0000000..175b0fa
--- /dev/null
+++ b/packages/SystemUI/res/values-ms-rMY-land/strings.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/**
+ * Copyright (c) 2010, 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 xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="toast_rotation_locked" msgid="7609673011431556092">"Skrin kini dikunci dalam orientasi landskap."</string>
+</resources>
diff --git a/packages/SystemUI/res/values-ne-rNP-land/strings.xml b/packages/SystemUI/res/values-ne-rNP-land/strings.xml
new file mode 100644
index 0000000..8d5286e
--- /dev/null
+++ b/packages/SystemUI/res/values-ne-rNP-land/strings.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/**
+ * Copyright (c) 2010, 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 xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="toast_rotation_locked" msgid="7609673011431556092">"स्क्रिन अहिले ल्यान्डस्केप अवस्थामा बन्द छ।"</string>
+</resources>
diff --git a/packages/SystemUI/res/values-ne-rNP/strings.xml b/packages/SystemUI/res/values-ne-rNP/strings.xml
index 19e2744..9e6605e 100644
--- a/packages/SystemUI/res/values-ne-rNP/strings.xml
+++ b/packages/SystemUI/res/values-ne-rNP/strings.xml
@@ -38,7 +38,7 @@
     <string name="invalid_charger" msgid="4549105996740522523">"USB चार्ज गर्न समर्थित छैन।\n आपूर्ति गरिएको चार्जर मात्र प्रयोग गर्नुहोस्।"</string>
     <string name="battery_low_why" msgid="7279169609518386372">"ब्याट्रि प्रयोग"</string>
     <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"सेटिङहरू"</string>
-    <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"वाइ-फाइ"</string>
+    <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"वाइफाइ"</string>
     <string name="status_bar_settings_airplane" msgid="4879879698500955300">"हवाइजहाज मोड"</string>
     <string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"स्वत:घुम्ने स्क्रिन"</string>
     <string name="status_bar_settings_mute_label" msgid="554682549917429396">"म्युट गर्नुहोस्"</string>
@@ -127,9 +127,9 @@
     <string name="accessibility_data_connection_cdma" msgid="6132648193978823023">"CDMA"</string>
     <string name="accessibility_data_connection_roaming" msgid="5977362333466556094">"रोमिङ"</string>
     <string name="accessibility_data_connection_edge" msgid="4477457051631979278">"Edge"</string>
-    <string name="accessibility_data_connection_wifi" msgid="2324496756590645221">"वाइ-फाइ"</string>
+    <string name="accessibility_data_connection_wifi" msgid="2324496756590645221">"वाइफाइ"</string>
     <string name="accessibility_no_sim" msgid="8274017118472455155">"SIM छैन।"</string>
-    <string name="accessibility_bluetooth_tether" msgid="4102784498140271969">"ब्लुटुथ टिथर गर्दै।"</string>
+    <string name="accessibility_bluetooth_tether" msgid="4102784498140271969">"ब्लुटुथ टेदर गर्दै।"</string>
     <string name="accessibility_airplane_mode" msgid="834748999790763092">"हवाइजहाज मोड।"</string>
     <string name="accessibility_battery_level" msgid="7451474187113371965">"ब्याट्रि <xliff:g id="NUMBER">%d</xliff:g> प्रतिशत"</string>
     <string name="accessibility_settings_button" msgid="799583911231893380">"प्रणाली सेटिङहरू"</string>
@@ -159,7 +159,7 @@
     <string name="data_usage_disabled_dialog" msgid="3853117269051806280">"तपाईँ निर्दिष्ट डेटा उपयोग सीमामा पुग्नु भएको छ।\n\nयदि तपाईँले डेटालाई पुनःसक्षम पार्नु भयो भने तपाईँलाई अर्को संचालकबाट शुल्क लगाउन सक्छ।"</string>
     <string name="data_usage_disabled_dialog_enable" msgid="7729772039208664606">"डेटा पुनः सक्षम गर्नुहोस्"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"इन्टरनेट जडान छैन"</string>
-    <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"वाइ-फाइ जडित"</string>
+    <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"वाइफाइ जडित"</string>
     <string name="gps_notification_searching_text" msgid="8574247005642736060">"GPSको लागि खोजी गर्दै"</string>
     <string name="gps_notification_found_text" msgid="4619274244146446464">"GPS द्वारा स्थान सेट गरिएको"</string>
     <string name="accessibility_location_active" msgid="2427290146138169014">"स्थान अनुरोधहरू सक्रिय"</string>
@@ -189,11 +189,11 @@
     <string name="quick_settings_settings_label" msgid="5326556592578065401">"सेटिङहरू"</string>
     <string name="quick_settings_time_label" msgid="4635969182239736408">"समय"</string>
     <string name="quick_settings_user_label" msgid="5238995632130897840">"मलाई"</string>
-    <string name="quick_settings_wifi_label" msgid="9135344704899546041">"वाइ-फाइ"</string>
+    <string name="quick_settings_wifi_label" msgid="9135344704899546041">"वाइफाइ"</string>
     <string name="quick_settings_wifi_not_connected" msgid="7171904845345573431">"जोडिएको छैन"</string>
     <string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"नेटवर्क छैन"</string>
-    <string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"वाइ-फाइ बन्द"</string>
-    <string name="quick_settings_wifi_display_label" msgid="6893592964463624333">"वाइ-फाइ प्रदर्शन"</string>
+    <string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"वाइफाइ बन्द"</string>
+    <string name="quick_settings_wifi_display_label" msgid="6893592964463624333">"वाइफाइ प्रदर्शन"</string>
     <string name="quick_settings_wifi_display_no_connection_label" msgid="2355298740765736918">"ताररहित प्रदर्शन"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"उज्यालपन"</string>
     <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"स्वतः"</string>
diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml
index 520ffb4..2c469b4 100644
--- a/packages/SystemUI/res/values-ru/strings.xml
+++ b/packages/SystemUI/res/values-ru/strings.xml
@@ -185,7 +185,7 @@
     <string name="quick_settings_rotation_unlocked_label" msgid="336054930362580584">"Автоповорот"</string>
     <string name="quick_settings_rotation_locked_label" msgid="8058646447242565486">"Автоповорот выкл."</string>
     <string name="quick_settings_ime_label" msgid="7073463064369468429">"Способ ввода"</string>
-    <string name="quick_settings_location_label" msgid="5011327048748762257">"Местоположение"</string>
+    <string name="quick_settings_location_label" msgid="5011327048748762257">"Передача геоданных"</string>
     <string name="quick_settings_location_off_label" msgid="7464544086507331459">"Местоположение выкл."</string>
     <string name="quick_settings_media_device_label" msgid="1302906836372603762">"Режим медиа"</string>
     <string name="quick_settings_rssi_label" msgid="7725671335550695589">"RSSI"</string>
diff --git a/packages/SystemUI/res/values-si-rLK-land/strings.xml b/packages/SystemUI/res/values-si-rLK-land/strings.xml
new file mode 100644
index 0000000..b5aba2a
--- /dev/null
+++ b/packages/SystemUI/res/values-si-rLK-land/strings.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/**
+ * Copyright (c) 2010, 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 xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="toast_rotation_locked" msgid="7609673011431556092">"තිරය දැන් තිරස් දිශානතිය අගුළු දමා ඇත."</string>
+</resources>
diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml
index d3ac4c2..f911f27 100644
--- a/packages/SystemUI/res/values-sw/strings.xml
+++ b/packages/SystemUI/res/values-sw/strings.xml
@@ -179,7 +179,7 @@
     <string name="quick_settings_rotation_unlocked_label" msgid="336054930362580584">"Zungusha Otomatiki"</string>
     <string name="quick_settings_rotation_locked_label" msgid="8058646447242565486">"Mzunguko Umefungwa"</string>
     <string name="quick_settings_ime_label" msgid="7073463064369468429">"Mbinu ya uingizaji"</string>
-    <string name="quick_settings_location_label" msgid="5011327048748762257">"Eneo"</string>
+    <string name="quick_settings_location_label" msgid="5011327048748762257">"Kutambua Eneo"</string>
     <string name="quick_settings_location_off_label" msgid="7464544086507331459">"Eneo Limezimwa"</string>
     <string name="quick_settings_media_device_label" msgid="1302906836372603762">"Kifaa cha midia"</string>
     <string name="quick_settings_rssi_label" msgid="7725671335550695589">"RSSI"</string>
diff --git a/packages/SystemUI/res/values-zh-rHK-land/strings.xml b/packages/SystemUI/res/values-zh-rHK-land/strings.xml
new file mode 100644
index 0000000..8d55df4
--- /dev/null
+++ b/packages/SystemUI/res/values-zh-rHK-land/strings.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/**
+ * Copyright (c) 2010, 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 xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="toast_rotation_locked" msgid="7609673011431556092">"屏幕現已鎖定為橫向模式"</string>
+</resources>
diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml
index 4dfad2f..6bf89e8 100644
--- a/packages/SystemUI/res/values-zu/strings.xml
+++ b/packages/SystemUI/res/values-zu/strings.xml
@@ -24,10 +24,10 @@
     <string name="status_bar_recent_remove_item_title" msgid="6026395868129852968">"Susa ohlwini"</string>
     <string name="status_bar_recent_inspect_item_title" msgid="7793624864528818569">"Ulwazi lwensiza"</string>
     <string name="status_bar_no_recent_apps" msgid="6576392951053994640">"Azikho izinhlelo zokusebenza zakamuva"</string>
-    <string name="status_bar_accessibility_dismiss_recents" msgid="4576076075226540105">"Susa izinsiza zakamumva"</string>
+    <string name="status_bar_accessibility_dismiss_recents" msgid="4576076075226540105">"Susa izinhlelo zokusebenza zakamumva"</string>
   <plurals name="status_bar_accessibility_recent_apps">
     <item quantity="one" msgid="5854176083865845541">"Insiza eyi-1 yakamumva"</item>
-    <item quantity="other" msgid="1040784359794890744">"%d izinsiza zakamumva"</item>
+    <item quantity="other" msgid="1040784359794890744">"%d izinhlelo zokusebenza zakamumva"</item>
   </plurals>
     <string name="status_bar_no_notifications_title" msgid="4755261167193833213">"Azikho izaziso"</string>
     <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Okuqhubekayo"</string>
@@ -47,11 +47,11 @@
     <string name="bluetooth_tethered" msgid="7094101612161133267">"Ukusebenzisa i-Bluetooth njengemodemu"</string>
     <string name="status_bar_input_method_settings_configure_input_methods" msgid="3504292471512317827">"Izilungiselelo zezindlela zokufakwayo"</string>
     <string name="status_bar_use_physical_keyboard" msgid="7551903084416057810">"Ukwakheka kwekhibhodi"</string>
-    <string name="usb_device_permission_prompt" msgid="834698001271562057">"Vumela insiza <xliff:g id="APPLICATION">%1$s</xliff:g> ukuthi ufinyelele ezintweni eziphuma ne-USB?"</string>
-    <string name="usb_accessory_permission_prompt" msgid="5171775411178865750">"Vumela insiza <xliff:g id="APPLICATION">%1$s</xliff:g> ukuthi ufinyelele ezintweni eziphuma ne-USB?"</string>
+    <string name="usb_device_permission_prompt" msgid="834698001271562057">"Vumela uhlelo lokusebenza <xliff:g id="APPLICATION">%1$s</xliff:g> ukuthi ufinyelele ezintweni eziphuma ne-USB?"</string>
+    <string name="usb_accessory_permission_prompt" msgid="5171775411178865750">"Vumela uhlelo lokusebenza <xliff:g id="APPLICATION">%1$s</xliff:g> ukuthi ufinyelele ezintweni eziphuma ne-USB?"</string>
     <string name="usb_device_confirm_prompt" msgid="5161205258635253206">"Vula <xliff:g id="ACTIVITY">%1$s</xliff:g> uma ledivayisi ye-USB ixhunyiwe?"</string>
     <string name="usb_accessory_confirm_prompt" msgid="3808984931830229888">"Vula <xliff:g id="ACTIVITY">%1$s</xliff:g> uma le-accessory ye-USB ixhunyiwe"</string>
-    <string name="usb_accessory_uri_prompt" msgid="513450621413733343">"Azikho izinsiza ezisebenze ngezinto ze-USB. Funda okwengeziwe ngale into kwi <xliff:g id="URL">%1$s</xliff:g>"</string>
+    <string name="usb_accessory_uri_prompt" msgid="513450621413733343">"Azikho izinhlelo zokusebenza ezisebenze ngezinto ze-USB. Funda okwengeziwe ngale into kwi <xliff:g id="URL">%1$s</xliff:g>"</string>
     <string name="title_usb_accessory" msgid="4966265263465181372">"ama-accessory e-USB"</string>
     <string name="label_view" msgid="6304565553218192990">"Buka"</string>
     <string name="always_use_device" msgid="1450287437017315906">"Sebenzisa ngokuzenzakalelayo yale divayisi ye-USB"</string>
@@ -71,7 +71,7 @@
     <string name="usb_preference_title" msgid="6551050377388882787">"Okukhethwa kokudluliswa kwefayela ye-USB"</string>
     <string name="use_mtp_button_title" msgid="4333504413563023626">"Lengisa njengesidlali semediya (MTP)"</string>
     <string name="use_ptp_button_title" msgid="7517127540301625751">"Lengisa ikhamera (PTP)"</string>
-    <string name="installer_cd_button_title" msgid="2312667578562201583">"Faka insiza yokudluliswa Kwefayela ye-Android kwi-Mac"</string>
+    <string name="installer_cd_button_title" msgid="2312667578562201583">"Faka uhlelo lokusebenza yokudluliswa Kwefayela ye-Android kwi-Mac"</string>
     <string name="accessibility_back" msgid="567011538994429120">"Emuva"</string>
     <string name="accessibility_home" msgid="8217216074895377641">"Ekhaya"</string>
     <string name="accessibility_menu" msgid="316839303324695949">"Imenyu"</string>
diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java b/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java
index 3946d1c..ada30ac 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java
@@ -354,7 +354,6 @@
             if (mPopup != null) {
                 mPopup.dismiss();
             }
-            ((RecentsActivity) mContext).moveTaskToBack(true);
         }
     }
 
diff --git a/packages/services/Proxy/com/android/net/IProxyCallback.aidl b/packages/services/Proxy/com/android/net/IProxyCallback.aidl
new file mode 100644
index 0000000..26b2a3f9
--- /dev/null
+++ b/packages/services/Proxy/com/android/net/IProxyCallback.aidl
@@ -0,0 +1,22 @@
+/**
+ * Copyright (c) 2013, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.net;
+
+/** @hide */
+interface IProxyCallback
+{
+    oneway void getProxyPort(IBinder callback);
+}
diff --git a/packages/services/Proxy/com/android/net/IProxyPortListener.aidl b/packages/services/Proxy/com/android/net/IProxyPortListener.aidl
new file mode 100644
index 0000000..fa4caf3
--- /dev/null
+++ b/packages/services/Proxy/com/android/net/IProxyPortListener.aidl
@@ -0,0 +1,22 @@
+/**
+ * Copyright (c) 2013, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.net;
+
+/** @hide */
+interface IProxyPortListener
+{
+    oneway void setProxyPort(int port);
+}
diff --git a/packages/services/Proxy/src/com/android/proxyhandler/ProxyServer.java b/packages/services/Proxy/src/com/android/proxyhandler/ProxyServer.java
index 77f3c8c..4bf1db8 100644
--- a/packages/services/Proxy/src/com/android/proxyhandler/ProxyServer.java
+++ b/packages/services/Proxy/src/com/android/proxyhandler/ProxyServer.java
@@ -15,8 +15,11 @@
  */
 package com.android.proxyhandler;
 
+import android.net.ProxyProperties;
+import android.os.RemoteException;
 import android.util.Log;
 
+import com.android.net.IProxyPortListener;
 import com.google.android.collect.Lists;
 
 import java.io.IOException;
@@ -49,6 +52,8 @@
     public boolean mIsRunning = false;
 
     private ServerSocket serverSocket;
+    private int mPort;
+    private IProxyPortListener mCallback;
 
     private class ProxyConnection implements Runnable {
         private Socket connection;
@@ -179,33 +184,59 @@
 
     public ProxyServer() {
         threadExecutor = Executors.newCachedThreadPool();
+        mPort = -1;
+        mCallback = null;
     }
 
     @Override
     public void run() {
         try {
-            serverSocket = new ServerSocket(ProxyService.PORT);
+            serverSocket = new ServerSocket(0);
 
-            serverSocket.setReuseAddress(true);
+            if (serverSocket != null) {
+                setPort(serverSocket.getLocalPort());
 
-            while (mIsRunning) {
-                try {
-                    ProxyConnection parser = new ProxyConnection(serverSocket.accept());
+                while (mIsRunning) {
+                    try {
+                        ProxyConnection parser = new ProxyConnection(serverSocket.accept());
 
-                    threadExecutor.execute(parser);
-                } catch (IOException e) {
-                    e.printStackTrace();
+                        threadExecutor.execute(parser);
+                    } catch (IOException e) {
+                        e.printStackTrace();
+                    }
                 }
             }
         } catch (SocketException e) {
-            e.printStackTrace();
-        } catch (IOException e) {
-            e.printStackTrace();
+            Log.e(TAG, "Failed to start proxy server", e);
+        } catch (IOException e1) {
+            Log.e(TAG, "Failed to start proxy server", e1);
         }
 
         mIsRunning = false;
     }
 
+    public synchronized void setPort(int port) {
+        if (mCallback != null) {
+            try {
+                mCallback.setProxyPort(port);
+            } catch (RemoteException e) {
+                Log.w(TAG, "Proxy failed to report port to PacManager", e);
+            }
+        }
+        mPort = port;
+    }
+
+    public synchronized void setCallback(IProxyPortListener callback) {
+        if (mPort != -1) {
+            try {
+                callback.setProxyPort(mPort);
+            } catch (RemoteException e) {
+                Log.w(TAG, "Proxy failed to report port to PacManager", e);
+            }
+        }
+        mCallback = callback;
+    }
+
     public synchronized void startServer() {
         mIsRunning = true;
         start();
@@ -222,4 +253,12 @@
             }
         }
     }
+
+    public boolean isBound() {
+        return (mPort != -1);
+    }
+
+    public int getPort() {
+        return mPort;
+    }
 }
diff --git a/packages/services/Proxy/src/com/android/proxyhandler/ProxyService.java b/packages/services/Proxy/src/com/android/proxyhandler/ProxyService.java
index cef3659..109435c 100644
--- a/packages/services/Proxy/src/com/android/proxyhandler/ProxyService.java
+++ b/packages/services/Proxy/src/com/android/proxyhandler/ProxyService.java
@@ -21,8 +21,12 @@
 import android.net.ProxyProperties;
 import android.os.Bundle;
 import android.os.IBinder;
+import android.os.RemoteException;
 import android.text.TextUtils;
 
+import com.android.net.IProxyCallback;
+import com.android.net.IProxyPortListener;
+
 /**
  * @hide
  */
@@ -56,6 +60,16 @@
 
     @Override
     public IBinder onBind(Intent intent) {
-        return null;
+        return new IProxyCallback.Stub() {
+            @Override
+            public void getProxyPort(IBinder callback) throws RemoteException {
+                if (server != null) {
+                    IProxyPortListener portListener = IProxyPortListener.Stub.asInterface(callback);
+                    if (portListener != null) {
+                        server.setCallback(portListener);
+                    }
+                }
+            }
+        };
     }
 }
\ No newline at end of file
diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java
index 3f8d7eb..19b762d 100644
--- a/services/java/com/android/server/ConnectivityService.java
+++ b/services/java/com/android/server/ConnectivityService.java
@@ -3463,7 +3463,7 @@
 
     private void sendProxyBroadcast(ProxyProperties proxy) {
         if (proxy == null) proxy = new ProxyProperties("", 0, "");
-        mPacManager.setCurrentProxyScriptUrl(proxy);
+        if (mPacManager.setCurrentProxyScriptUrl(proxy)) return;
         if (DBG) log("sending Proxy Broadcast for " + proxy);
         Intent intent = new Intent(Proxy.PROXY_CHANGE_ACTION);
         intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING |
@@ -3987,40 +3987,6 @@
             // Start off with notification off
             setProvNotificationVisible(false, ConnectivityManager.TYPE_NONE, null, null);
 
-            // See if we've alreadying determined if we've got a provsioning connection
-            // if so we don't need to do anything active
-            MobileDataStateTracker mdstDefault = (MobileDataStateTracker)
-                    mNetTrackers[ConnectivityManager.TYPE_MOBILE];
-            boolean isDefaultProvisioning = mdstDefault.isProvisioningNetwork();
-
-            MobileDataStateTracker mdstHipri = (MobileDataStateTracker)
-                    mNetTrackers[ConnectivityManager.TYPE_MOBILE_HIPRI];
-            boolean isHipriProvisioning = mdstHipri.isProvisioningNetwork();
-
-            if (isDefaultProvisioning || isHipriProvisioning) {
-                if (mIsNotificationVisible) {
-                    if (DBG) {
-                        log("checkMobileProvisioning: provisioning-ignore notification is visible");
-                    }
-                } else {
-                    NetworkInfo ni = null;
-                    if (isDefaultProvisioning) {
-                        ni = mdstDefault.getNetworkInfo();
-                    }
-                    if (isHipriProvisioning) {
-                        ni = mdstHipri.getNetworkInfo();
-                    }
-                    String url = getMobileProvisioningUrl();
-                    if ((ni != null) && (!TextUtils.isEmpty(url))) {
-                        setProvNotificationVisible(true, ni.getType(), ni.getExtraInfo(), url);
-                    } else {
-                        if (DBG) log("checkMobileProvisioning: provisioning but no url, ignore");
-                    }
-                }
-                mIsCheckingMobileProvisioning.set(false);
-                return timeOutMs;
-            }
-
             CheckMp checkMp = new CheckMp(mContext, this);
             CheckMp.CallBack cb = new CheckMp.CallBack() {
                 @Override
@@ -4154,8 +4120,26 @@
             mParams = params;
 
             if (mCs.isNetworkSupported(ConnectivityManager.TYPE_MOBILE) == false) {
-                log("isMobileOk: not mobile capable");
                 result = CMP_RESULT_CODE_NO_CONNECTION;
+                log("isMobileOk: X not mobile capable result=" + result);
+                return result;
+            }
+
+            // See if we've already determined we've got a provisioning connection,
+            // if so we don't need to do anything active.
+            MobileDataStateTracker mdstDefault = (MobileDataStateTracker)
+                    mCs.mNetTrackers[ConnectivityManager.TYPE_MOBILE];
+            boolean isDefaultProvisioning = mdstDefault.isProvisioningNetwork();
+            log("isMobileOk: isDefaultProvisioning=" + isDefaultProvisioning);
+
+            MobileDataStateTracker mdstHipri = (MobileDataStateTracker)
+                    mCs.mNetTrackers[ConnectivityManager.TYPE_MOBILE_HIPRI];
+            boolean isHipriProvisioning = mdstHipri.isProvisioningNetwork();
+            log("isMobileOk: isHipriProvisioning=" + isHipriProvisioning);
+
+            if (isDefaultProvisioning || isHipriProvisioning) {
+                result = CMP_RESULT_CODE_PROVISIONING_NETWORK;
+                log("isMobileOk: X default || hipri is provisioning result=" + result);
                 return result;
             }
 
@@ -4217,8 +4201,8 @@
                         MobileDataStateTracker mdst = (MobileDataStateTracker)
                                 mCs.mNetTrackers[ConnectivityManager.TYPE_MOBILE_HIPRI];
                         if (mdst.isProvisioningNetwork()) {
-                            if (DBG) log("isMobileOk: isProvisioningNetwork is true");
                             result = CMP_RESULT_CODE_PROVISIONING_NETWORK;
+                            if (DBG) log("isMobileOk: X isProvisioningNetwork result=" + result);
                             return result;
                         } else {
                             if (DBG) log("isMobileOk: isProvisioningNetwork is false, continue");
@@ -4233,8 +4217,8 @@
                         try {
                             addresses = InetAddress.getAllByName(orgUri.getHost());
                         } catch (UnknownHostException e) {
-                            log("isMobileOk: UnknownHostException");
                             result = CMP_RESULT_CODE_NO_DNS;
+                            log("isMobileOk: X UnknownHostException result=" + result);
                             return result;
                         }
                         log("isMobileOk: addresses=" + inetAddressesToString(addresses));
@@ -4309,8 +4293,9 @@
 
                                 if (responseCode == 204) {
                                     // Return
-                                    log("isMobileOk: expected responseCode=" + responseCode);
                                     result = CMP_RESULT_CODE_CONNECTABLE;
+                                    log("isMobileOk: X expected responseCode=" + responseCode
+                                            + " result=" + result);
                                     return result;
                                 } else {
                                     // Retry to be sure this was redirected, we've gotten
@@ -4328,7 +4313,7 @@
                                 }
                             }
                         }
-                        log("isMobileOk: loops|timed out result=" + result);
+                        log("isMobileOk: X loops|timed out result=" + result);
                         return result;
                     } catch (Exception e) {
                         log("isMobileOk: Exception e=" + e);
diff --git a/services/java/com/android/server/am/ActiveServices.java b/services/java/com/android/server/am/ActiveServices.java
index 4521037..b4d9da0 100644
--- a/services/java/com/android/server/am/ActiveServices.java
+++ b/services/java/com/android/server/am/ActiveServices.java
@@ -328,8 +328,17 @@
                 addToStarting = true;
                 if (DEBUG_DELAYED_STATS) Slog.v(TAG, "Not delaying, but counting as bg: " + r);
             } else if (DEBUG_DELAYED_STATS) {
-                Slog.v(TAG, "Not potential delay (state=" + proc.curProcState
-                        + " " + proc.makeAdjReason() + "): " + r);
+                StringBuilder sb = new StringBuilder(128);
+                sb.append("Not potential delay (state=").append(proc.curProcState)
+                        .append(' ').append(proc.adjType);
+                String reason = proc.makeAdjReason();
+                if (reason != null) {
+                    sb.append(' ');
+                    sb.append(reason);
+                }
+                sb.append("): ");
+                sb.append(r.toString());
+                Slog.v(TAG, sb.toString());
             }
         } else if (DEBUG_DELAYED_STATS) {
             if (callerFg) {
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index 96b7030..e208f10 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -1370,64 +1370,167 @@
                 break;
             }
             case REPORT_MEM_USAGE: {
-                boolean isDebuggable = "1".equals(SystemProperties.get(SYSTEM_DEBUGGABLE, "0"));
-                if (!isDebuggable) {
-                    return;
-                }
-                synchronized (ActivityManagerService.this) {
-                    long now = SystemClock.uptimeMillis();
-                    if (now < (mLastMemUsageReportTime+5*60*1000)) {
-                        // Don't report more than every 5 minutes to somewhat
-                        // avoid spamming.
-                        return;
-                    }
-                    mLastMemUsageReportTime = now;
-                }
+                final ArrayList<ProcessMemInfo> memInfos = (ArrayList<ProcessMemInfo>)msg.obj;
                 Thread thread = new Thread() {
                     @Override public void run() {
-                        StringBuilder dropBuilder = new StringBuilder(1024);
+                        final SparseArray<ProcessMemInfo> infoMap
+                                = new SparseArray<ProcessMemInfo>(memInfos.size());
+                        for (int i=0, N=memInfos.size(); i<N; i++) {
+                            ProcessMemInfo mi = memInfos.get(i);
+                            infoMap.put(mi.pid, mi);
+                        }
+                        updateCpuStatsNow();
+                        synchronized (mProcessCpuThread) {
+                            final int N = mProcessCpuTracker.countStats();
+                            for (int i=0; i<N; i++) {
+                                ProcessCpuTracker.Stats st = mProcessCpuTracker.getStats(i);
+                                if (st.vsize > 0) {
+                                    long pss = Debug.getPss(st.pid, null);
+                                    if (pss > 0) {
+                                        if (infoMap.indexOfKey(st.pid) < 0) {
+                                            ProcessMemInfo mi = new ProcessMemInfo(st.name, st.pid,
+                                                    ProcessList.NATIVE_ADJ, -1, "native", null);
+                                            mi.pss = pss;
+                                            memInfos.add(mi);
+                                        }
+                                    }
+                                }
+                            }
+                        }
+
+                        long totalPss = 0;
+                        for (int i=0, N=memInfos.size(); i<N; i++) {
+                            ProcessMemInfo mi = memInfos.get(i);
+                            if (mi.pss == 0) {
+                                mi.pss = Debug.getPss(mi.pid, null);
+                            }
+                            totalPss += mi.pss;
+                        }
+                        Collections.sort(memInfos, new Comparator<ProcessMemInfo>() {
+                            @Override public int compare(ProcessMemInfo lhs, ProcessMemInfo rhs) {
+                                if (lhs.oomAdj != rhs.oomAdj) {
+                                    return lhs.oomAdj < rhs.oomAdj ? -1 : 1;
+                                }
+                                if (lhs.pss != rhs.pss) {
+                                    return lhs.pss < rhs.pss ? 1 : -1;
+                                }
+                                return 0;
+                            }
+                        });
+
+                        StringBuilder tag = new StringBuilder(128);
+                        StringBuilder stack = new StringBuilder(128);
+                        tag.append("Low on memory -- ");
+                        appendMemBucket(tag, totalPss, "total", false);
+                        appendMemBucket(stack, totalPss, "total", true);
+
                         StringBuilder logBuilder = new StringBuilder(1024);
+                        logBuilder.append("Low on memory:\n");
+
+                        boolean firstLine = true;
+                        int lastOomAdj = Integer.MIN_VALUE;
+                        for (int i=0, N=memInfos.size(); i<N; i++) {
+                            ProcessMemInfo mi = memInfos.get(i);
+
+                            if (mi.oomAdj != ProcessList.NATIVE_ADJ
+                                    && (mi.oomAdj < ProcessList.SERVICE_ADJ
+                                            || mi.oomAdj == ProcessList.HOME_APP_ADJ
+                                            || mi.oomAdj == ProcessList.PREVIOUS_APP_ADJ)) {
+                                if (lastOomAdj != mi.oomAdj) {
+                                    lastOomAdj = mi.oomAdj;
+                                    if (mi.oomAdj <= ProcessList.FOREGROUND_APP_ADJ) {
+                                        tag.append(" / ");
+                                    }
+                                    if (mi.oomAdj >= ProcessList.FOREGROUND_APP_ADJ) {
+                                        if (firstLine) {
+                                            stack.append(":");
+                                            firstLine = false;
+                                        }
+                                        stack.append("\n\t at ");
+                                    } else {
+                                        stack.append("$");
+                                    }
+                                } else {
+                                    tag.append(" ");
+                                    stack.append("$");
+                                }
+                                if (mi.oomAdj <= ProcessList.FOREGROUND_APP_ADJ) {
+                                    appendMemBucket(tag, mi.pss, mi.name, false);
+                                }
+                                appendMemBucket(stack, mi.pss, mi.name, true);
+                                if (mi.oomAdj >= ProcessList.FOREGROUND_APP_ADJ
+                                        && ((i+1) >= N || memInfos.get(i+1).oomAdj != lastOomAdj)) {
+                                    stack.append("(");
+                                    for (int k=0; k<DUMP_MEM_OOM_ADJ.length; k++) {
+                                        if (DUMP_MEM_OOM_ADJ[k] == mi.oomAdj) {
+                                            stack.append(DUMP_MEM_OOM_LABEL[k]);
+                                            stack.append(":");
+                                            stack.append(DUMP_MEM_OOM_ADJ[k]);
+                                        }
+                                    }
+                                    stack.append(")");
+                                }
+                            }
+
+                            logBuilder.append("  ");
+                            logBuilder.append(ProcessList.makeOomAdjString(mi.oomAdj));
+                            logBuilder.append(' ');
+                            logBuilder.append(ProcessList.makeProcStateString(mi.procState));
+                            logBuilder.append(' ');
+                            ProcessList.appendRamKb(logBuilder, mi.pss);
+                            logBuilder.append(" kB: ");
+                            logBuilder.append(mi.name);
+                            logBuilder.append(" (");
+                            logBuilder.append(mi.pid);
+                            logBuilder.append(") ");
+                            logBuilder.append(mi.adjType);
+                            logBuilder.append('\n');
+                            if (mi.adjReason != null) {
+                                logBuilder.append("                      ");
+                                logBuilder.append(mi.adjReason);
+                                logBuilder.append('\n');
+                            }
+                        }
+
+                        logBuilder.append("           ");
+                        ProcessList.appendRamKb(logBuilder, totalPss);
+                        logBuilder.append(" kB: TOTAL\n");
+
+                        long[] infos = new long[Debug.MEMINFO_COUNT];
+                        Debug.getMemInfo(infos);
+                        logBuilder.append("  MemInfo: ");
+                        logBuilder.append(infos[Debug.MEMINFO_SLAB]).append(" kB slab, ");
+                        logBuilder.append(infos[Debug.MEMINFO_SHMEM]).append(" kB shmem, ");
+                        logBuilder.append(infos[Debug.MEMINFO_BUFFERS]).append(" kB buffers, ");
+                        logBuilder.append(infos[Debug.MEMINFO_CACHED]).append(" kB cached, ");
+                        logBuilder.append(infos[Debug.MEMINFO_FREE]).append(" kB free\n");
+
+                        Slog.i(TAG, logBuilder.toString());
+
+                        StringBuilder dropBuilder = new StringBuilder(1024);
+                        /*
                         StringWriter oomSw = new StringWriter();
                         PrintWriter oomPw = new FastPrintWriter(oomSw, false, 256);
                         StringWriter catSw = new StringWriter();
                         PrintWriter catPw = new FastPrintWriter(catSw, false, 256);
                         String[] emptyArgs = new String[] { };
-                        StringBuilder tag = new StringBuilder(128);
-                        StringBuilder stack = new StringBuilder(128);
-                        tag.append("Low on memory -- ");
-                        dumpApplicationMemoryUsage(null, oomPw, "  ", emptyArgs, true, catPw,
-                                tag, stack);
+                        dumpApplicationMemoryUsage(null, oomPw, "  ", emptyArgs, true, catPw);
+                        oomPw.flush();
+                        String oomString = oomSw.toString();
+                        */
                         dropBuilder.append(stack);
                         dropBuilder.append('\n');
                         dropBuilder.append('\n');
-                        oomPw.flush();
-                        String oomString = oomSw.toString();
+                        dropBuilder.append(logBuilder);
+                        dropBuilder.append('\n');
+                        /*
                         dropBuilder.append(oomString);
                         dropBuilder.append('\n');
-                        logBuilder.append(oomString);
-                        try {
-                            java.lang.Process proc = Runtime.getRuntime().exec(new String[] {
-                                    "procrank", });
-                            final InputStreamReader converter = new InputStreamReader(
-                                    proc.getInputStream());
-                            BufferedReader in = new BufferedReader(converter);
-                            String line;
-                            while (true) {
-                                line = in.readLine();
-                                if (line == null) {
-                                    break;
-                                }
-                                if (line.length() > 0) {
-                                    logBuilder.append(line);
-                                    logBuilder.append('\n');
-                                }
-                                dropBuilder.append(line);
-                                dropBuilder.append('\n');
-                            }
-                            converter.close();
-                        } catch (IOException e) {
-                        }
+                        */
+                        StringWriter catSw = new StringWriter();
                         synchronized (ActivityManagerService.this) {
+                            PrintWriter catPw = new FastPrintWriter(catSw, false, 256);
+                            String[] emptyArgs = new String[] { };
                             catPw.println();
                             dumpProcessesLocked(null, catPw, emptyArgs, 0, false, null);
                             catPw.println();
@@ -1435,12 +1538,13 @@
                                     false, false, null);
                             catPw.println();
                             dumpActivitiesLocked(null, catPw, emptyArgs, 0, false, false, null);
+                            catPw.flush();
                         }
-                        catPw.flush();
                         dropBuilder.append(catSw.toString());
                         addErrorToDropBox("lowmem", null, "system_server", null,
                                 null, tag.toString(), dropBuilder.toString(), null, null);
-                        Slog.i(TAG, logBuilder.toString());
+                        //Slog.i(TAG, "Sent to dropbox:");
+                        //Slog.i(TAG, dropBuilder.toString());
                         synchronized (ActivityManagerService.this) {
                             long now = SystemClock.uptimeMillis();
                             if (mLastMemUsageReportTime < now) {
@@ -1691,8 +1795,7 @@
                 return;
             }
 
-            mActivityManagerService.dumpApplicationMemoryUsage(fd, pw, "  ", args,
-                    false, null, null, null);
+            mActivityManagerService.dumpApplicationMemoryUsage(fd, pw, "  ", args, false, null);
         }
     }
 
@@ -2466,10 +2569,17 @@
         }
     }
 
-    String getHomePackageName() {
+    Intent getHomeIntent() {
         Intent intent = new Intent(mTopAction, mTopData != null ? Uri.parse(mTopData) : null);
         intent.setComponent(mTopComponent);
-        intent.addCategory(Intent.CATEGORY_HOME);
+        if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
+            intent.addCategory(Intent.CATEGORY_HOME);
+        }
+        return intent;
+    }
+
+    String getHomePackageName() {
+        Intent intent = getHomeIntent();
         ActivityInfo aInfo = resolveActivityInfo(intent, STOCK_PM_FLAGS, mCurrentUserId);
         if (aInfo != null) {
             final String homePackageName = aInfo.applicationInfo.packageName;
@@ -2495,13 +2605,7 @@
             // error message and don't try to start anything.
             return false;
         }
-        Intent intent = new Intent(
-            mTopAction,
-            mTopData != null ? Uri.parse(mTopData) : null);
-        intent.setComponent(mTopComponent);
-        if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
-            intent.addCategory(Intent.CATEGORY_HOME);
-        }
+        Intent intent = getHomeIntent();
         ActivityInfo aInfo =
             resolveActivityInfo(intent, STOCK_PM_FLAGS, userId);
         if (aInfo != null) {
@@ -3271,6 +3375,66 @@
         return appIndex >= 0 ? mLruProcesses.get(appIndex) : null;
     }
 
+    final void doLowMemReportIfNeededLocked(ProcessRecord dyingProc) {
+        // If there are no longer any background processes running,
+        // and the app that died was not running instrumentation,
+        // then tell everyone we are now low on memory.
+        boolean haveBg = false;
+        for (int i=mLruProcesses.size()-1; i>=0; i--) {
+            ProcessRecord rec = mLruProcesses.get(i);
+            if (rec.thread != null
+                    && rec.setProcState >= ActivityManager.PROCESS_STATE_CACHED_ACTIVITY) {
+                haveBg = true;
+                break;
+            }
+        }
+
+        if (!haveBg) {
+            boolean doReport = "1".equals(SystemProperties.get(SYSTEM_DEBUGGABLE, "0"));
+            if (doReport) {
+                long now = SystemClock.uptimeMillis();
+                if (now < (mLastMemUsageReportTime+5*60*1000)) {
+                    doReport = false;
+                } else {
+                    mLastMemUsageReportTime = now;
+                }
+            }
+            final ArrayList<ProcessMemInfo> memInfos
+                    = doReport ? new ArrayList<ProcessMemInfo>(mLruProcesses.size()) : null;
+            EventLog.writeEvent(EventLogTags.AM_LOW_MEMORY, mLruProcesses.size());
+            long now = SystemClock.uptimeMillis();
+            for (int i=mLruProcesses.size()-1; i>=0; i--) {
+                ProcessRecord rec = mLruProcesses.get(i);
+                if (rec == dyingProc || rec.thread == null) {
+                    continue;
+                }
+                if (doReport) {
+                    memInfos.add(new ProcessMemInfo(rec.processName, rec.pid, rec.setAdj,
+                            rec.setProcState, rec.adjType, rec.makeAdjReason()));
+                }
+                if ((rec.lastLowMemory+GC_MIN_INTERVAL) <= now) {
+                    // The low memory report is overriding any current
+                    // state for a GC request.  Make sure to do
+                    // heavy/important/visible/foreground processes first.
+                    if (rec.setAdj <= ProcessList.HEAVY_WEIGHT_APP_ADJ) {
+                        rec.lastRequestedGc = 0;
+                    } else {
+                        rec.lastRequestedGc = rec.lastLowMemory;
+                    }
+                    rec.reportLowMemory = true;
+                    rec.lastLowMemory = now;
+                    mProcessesToGc.remove(rec);
+                    addProcessToGcListLocked(rec);
+                }
+            }
+            if (doReport) {
+                Message msg = mHandler.obtainMessage(REPORT_MEM_USAGE, memInfos);
+                mHandler.sendMessage(msg);
+            }
+            scheduleAppGcsLocked();
+        }
+    }
+
     final void appDiedLocked(ProcessRecord app, int pid,
             IApplicationThread thread) {
 
@@ -3296,42 +3460,7 @@
             handleAppDiedLocked(app, false, true);
 
             if (doLowMem) {
-                // If there are no longer any background processes running,
-                // and the app that died was not running instrumentation,
-                // then tell everyone we are now low on memory.
-                boolean haveBg = false;
-                for (int i=mLruProcesses.size()-1; i>=0; i--) {
-                    ProcessRecord rec = mLruProcesses.get(i);
-                    if (rec.thread != null && rec.setAdj >= ProcessList.CACHED_APP_MIN_ADJ) {
-                        haveBg = true;
-                        break;
-                    }
-                }
-
-                if (!haveBg) {
-                    EventLog.writeEvent(EventLogTags.AM_LOW_MEMORY, mLruProcesses.size());
-                    long now = SystemClock.uptimeMillis();
-                    for (int i=mLruProcesses.size()-1; i>=0; i--) {
-                        ProcessRecord rec = mLruProcesses.get(i);
-                        if (rec != app && rec.thread != null &&
-                                (rec.lastLowMemory+GC_MIN_INTERVAL) <= now) {
-                            // The low memory report is overriding any current
-                            // state for a GC request.  Make sure to do
-                            // heavy/important/visible/foreground processes first.
-                            if (rec.setAdj <= ProcessList.HEAVY_WEIGHT_APP_ADJ) {
-                                rec.lastRequestedGc = 0;
-                            } else {
-                                rec.lastRequestedGc = rec.lastLowMemory;
-                            }
-                            rec.reportLowMemory = true;
-                            rec.lastLowMemory = now;
-                            mProcessesToGc.remove(rec);
-                            addProcessToGcListLocked(rec);
-                        }
-                    }
-                    mHandler.sendEmptyMessage(REPORT_MEM_USAGE);
-                    scheduleAppGcsLocked();
-                }
+                doLowMemReportIfNeededLocked(app);
             }
         } else if (app.pid != pid) {
             // A new process has already been started.
@@ -3850,6 +3979,8 @@
                 for (int i=0; i<N; i++) {
                     removeProcessLocked(procs.get(i), false, true, "kill all background");
                 }
+                updateOomAdjLocked();
+                doLowMemReportIfNeededLocked(null);
             }
         } finally {
             Binder.restoreCallingIdentity(callingId);
@@ -4159,6 +4290,7 @@
         for (int i=0; i<N; i++) {
             removeProcessLocked(procs.get(i), callerWillRestart, allowRestart, reason);
         }
+        updateOomAdjLocked();
         return N > 0;
     }
 
@@ -10791,14 +10923,6 @@
         }
     }
 
-    private static String buildOomTag(String prefix, String space, int val, int base) {
-        if (val == base) {
-            if (space == null) return prefix;
-            return prefix + "  ";
-        }
-        return prefix + "+" + Integer.toString(val-base);
-    }
-    
     private static final int dumpProcessList(PrintWriter pw,
             ActivityManagerService service, List list,
             String prefix, String normalLabel, String persistentLabel,
@@ -10870,34 +10994,7 @@
 
         for (int i=list.size()-1; i>=0; i--) {
             ProcessRecord r = list.get(i).first;
-            String oomAdj;
-            if (r.setAdj >= ProcessList.CACHED_APP_MIN_ADJ) {
-                oomAdj = buildOomTag("cch", "  ", r.setAdj, ProcessList.CACHED_APP_MIN_ADJ);
-            } else if (r.setAdj >= ProcessList.SERVICE_B_ADJ) {
-                oomAdj = buildOomTag("svcb ", null, r.setAdj, ProcessList.SERVICE_B_ADJ);
-            } else if (r.setAdj >= ProcessList.PREVIOUS_APP_ADJ) {
-                oomAdj = buildOomTag("prev ", null, r.setAdj, ProcessList.PREVIOUS_APP_ADJ);
-            } else if (r.setAdj >= ProcessList.HOME_APP_ADJ) {
-                oomAdj = buildOomTag("home ", null, r.setAdj, ProcessList.HOME_APP_ADJ);
-            } else if (r.setAdj >= ProcessList.SERVICE_ADJ) {
-                oomAdj = buildOomTag("svc  ", null, r.setAdj, ProcessList.SERVICE_ADJ);
-            } else if (r.setAdj >= ProcessList.HEAVY_WEIGHT_APP_ADJ) {
-                oomAdj = buildOomTag("hvy  ", null, r.setAdj, ProcessList.HEAVY_WEIGHT_APP_ADJ);
-            } else if (r.setAdj >= ProcessList.BACKUP_APP_ADJ) {
-                oomAdj = buildOomTag("bkup ", null, r.setAdj, ProcessList.BACKUP_APP_ADJ);
-            } else if (r.setAdj >= ProcessList.PERCEPTIBLE_APP_ADJ) {
-                oomAdj = buildOomTag("prcp ", null, r.setAdj, ProcessList.PERCEPTIBLE_APP_ADJ);
-            } else if (r.setAdj >= ProcessList.VISIBLE_APP_ADJ) {
-                oomAdj = buildOomTag("vis  ", null, r.setAdj, ProcessList.VISIBLE_APP_ADJ);
-            } else if (r.setAdj >= ProcessList.FOREGROUND_APP_ADJ) {
-                oomAdj = buildOomTag("fore ", null, r.setAdj, ProcessList.FOREGROUND_APP_ADJ);
-            } else if (r.setAdj >= ProcessList.PERSISTENT_PROC_ADJ) {
-                oomAdj = buildOomTag("pers ", null, r.setAdj, ProcessList.PERSISTENT_PROC_ADJ);
-            } else if (r.setAdj >= ProcessList.SYSTEM_ADJ) {
-                oomAdj = buildOomTag("sys  ", null, r.setAdj, ProcessList.SYSTEM_ADJ);
-            } else {
-                oomAdj = Integer.toString(r.setAdj);
-            }
+            String oomAdj = ProcessList.makeOomAdjString(r.setAdj);
             char schedGroup;
             switch (r.setSchedGroup) {
                 case Process.THREAD_GROUP_BG_NONINTERACTIVE:
@@ -10918,54 +11015,7 @@
             } else {
                 foreground = ' ';
             }
-            String procState;
-            switch (r.curProcState) {
-                case ActivityManager.PROCESS_STATE_PERSISTENT:
-                    procState = "P ";
-                    break;
-                case ActivityManager.PROCESS_STATE_PERSISTENT_UI:
-                    procState = "PU";
-                    break;
-                case ActivityManager.PROCESS_STATE_TOP:
-                    procState = "T ";
-                    break;
-                case ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND:
-                    procState = "IF";
-                    break;
-                case ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND:
-                    procState = "IB";
-                    break;
-                case ActivityManager.PROCESS_STATE_BACKUP:
-                    procState = "BU";
-                    break;
-                case ActivityManager.PROCESS_STATE_HEAVY_WEIGHT:
-                    procState = "HW";
-                    break;
-                case ActivityManager.PROCESS_STATE_SERVICE:
-                    procState = "S ";
-                    break;
-                case ActivityManager.PROCESS_STATE_RECEIVER:
-                    procState = "R ";
-                    break;
-                case ActivityManager.PROCESS_STATE_HOME:
-                    procState = "HO";
-                    break;
-                case ActivityManager.PROCESS_STATE_LAST_ACTIVITY:
-                    procState = "LA";
-                    break;
-                case ActivityManager.PROCESS_STATE_CACHED_ACTIVITY:
-                    procState = "CA";
-                    break;
-                case ActivityManager.PROCESS_STATE_CACHED_ACTIVITY_CLIENT:
-                    procState = "Ca";
-                    break;
-                case ActivityManager.PROCESS_STATE_CACHED_EMPTY:
-                    procState = "CE";
-                    break;
-                default:
-                    procState = "??";
-                    break;
-            }
+            String procState = ProcessList.makeProcStateString(r.curProcState);
             pw.print(prefix);
             pw.print(r.persistent ? persistentLabel : normalLabel);
             pw.print(" #");
@@ -11253,6 +11303,7 @@
     }
 
     static final int[] DUMP_MEM_OOM_ADJ = new int[] {
+            ProcessList.NATIVE_ADJ,
             ProcessList.SYSTEM_ADJ, ProcessList.PERSISTENT_PROC_ADJ, ProcessList.FOREGROUND_APP_ADJ,
             ProcessList.VISIBLE_APP_ADJ, ProcessList.PERCEPTIBLE_APP_ADJ,
             ProcessList.BACKUP_APP_ADJ, ProcessList.HEAVY_WEIGHT_APP_ADJ,
@@ -11260,6 +11311,7 @@
             ProcessList.PREVIOUS_APP_ADJ, ProcessList.SERVICE_B_ADJ, ProcessList.CACHED_APP_MAX_ADJ
     };
     static final String[] DUMP_MEM_OOM_LABEL = new String[] {
+            "Native",
             "System", "Persistent", "Foreground",
             "Visible", "Perceptible",
             "Heavy Weight", "Backup",
@@ -11267,6 +11319,7 @@
             "Previous", "B Services", "Cached"
     };
     static final String[] DUMP_MEM_OOM_COMPACT_LABEL = new String[] {
+            "native",
             "sys", "pers", "fore",
             "vis", "percept",
             "heavy", "backup",
@@ -11275,8 +11328,7 @@
     };
 
     final void dumpApplicationMemoryUsage(FileDescriptor fd,
-            PrintWriter pw, String prefix, String[] args, boolean brief,
-            PrintWriter categoryPw, StringBuilder outTag, StringBuilder outStack) {
+            PrintWriter pw, String prefix, String[] args, boolean brief, PrintWriter categoryPw) {
         boolean dumpDetails = false;
         boolean dumpDalvik = false;
         boolean oomOnly = false;
@@ -11337,6 +11389,7 @@
         System.arraycopy(args, opti, innerArgs, 0, args.length-opti);
 
         ArrayList<MemItem> procMems = new ArrayList<MemItem>();
+        final SparseArray<MemItem> procMemsMap = new SparseArray<MemItem>();
         long nativePss=0, dalvikPss=0, otherPss=0;
         long[] miscPss = new long[Debug.MemoryInfo.NUM_OTHER_STATS];
 
@@ -11404,6 +11457,7 @@
                             (hasActivities ? " / activities)" : ")"),
                             r.processName, myTotalPss, pid, hasActivities);
                     procMems.add(pssItem);
+                    procMemsMap.put(pid, pssItem);
 
                     nativePss += mi.nativePss;
                     dalvikPss += mi.dalvikPss;
@@ -11434,6 +11488,48 @@
         }
 
         if (!isCheckinRequest && procs.size() > 1) {
+            // If we are showing aggregations, also look for native processes to
+            // include so that our aggregations are more accurate.
+            updateCpuStatsNow();
+            synchronized (mProcessCpuThread) {
+                final int N = mProcessCpuTracker.countStats();
+                for (int i=0; i<N; i++) {
+                    ProcessCpuTracker.Stats st = mProcessCpuTracker.getStats(i);
+                    if (st.vsize > 0 && procMemsMap.indexOfKey(st.pid) < 0) {
+                        if (mi == null) {
+                            mi = new Debug.MemoryInfo();
+                        }
+                        if (!brief && !oomOnly) {
+                            Debug.getMemoryInfo(st.pid, mi);
+                        } else {
+                            mi.nativePss = (int)Debug.getPss(st.pid, tmpLong);
+                            mi.nativePrivateDirty = (int)tmpLong[0];
+                        }
+
+                        final long myTotalPss = mi.getTotalPss();
+                        totalPss += myTotalPss;
+
+                        MemItem pssItem = new MemItem(st.name + " (pid " + st.pid + ")",
+                                st.name, myTotalPss, st.pid, false);
+                        procMems.add(pssItem);
+
+                        nativePss += mi.nativePss;
+                        dalvikPss += mi.dalvikPss;
+                        otherPss += mi.otherPss;
+                        for (int j=0; j<Debug.MemoryInfo.NUM_OTHER_STATS; j++) {
+                            long mem = mi.getOtherPss(j);
+                            miscPss[j] += mem;
+                            otherPss -= mem;
+                        }
+                        oomPss[0] += myTotalPss;
+                        if (oomProcs[0] == null) {
+                            oomProcs[0] = new ArrayList<MemItem>();
+                        }
+                        oomProcs[0].add(pssItem);
+                    }
+                }
+            }
+
             ArrayList<MemItem> catMems = new ArrayList<MemItem>();
 
             catMems.add(new MemItem("Native", "Native", nativePss, -1));
@@ -11456,68 +11552,6 @@
                 }
             }
 
-            if (outTag != null || outStack != null) {
-                if (outTag != null) {
-                    appendMemBucket(outTag, totalPss, "total", false);
-                }
-                if (outStack != null) {
-                    appendMemBucket(outStack, totalPss, "total", true);
-                }
-                boolean firstLine = true;
-                for (int i=0; i<oomMems.size(); i++) {
-                    MemItem miCat = oomMems.get(i);
-                    if (miCat.subitems == null || miCat.subitems.size() < 1) {
-                        continue;
-                    }
-                    if (miCat.id < ProcessList.SERVICE_ADJ
-                            || miCat.id == ProcessList.HOME_APP_ADJ
-                            || miCat.id == ProcessList.PREVIOUS_APP_ADJ) {
-                        if (outTag != null && miCat.id <= ProcessList.FOREGROUND_APP_ADJ) {
-                            outTag.append(" / ");
-                        }
-                        if (outStack != null) {
-                            if (miCat.id >= ProcessList.FOREGROUND_APP_ADJ) {
-                                if (firstLine) {
-                                    outStack.append(":");
-                                    firstLine = false;
-                                }
-                                outStack.append("\n\t at ");
-                            } else {
-                                outStack.append("$");
-                            }
-                        }
-                        for (int j=0; j<miCat.subitems.size(); j++) {
-                            MemItem memi = miCat.subitems.get(j);
-                            if (j > 0) {
-                                if (outTag != null) {
-                                    outTag.append(" ");
-                                }
-                                if (outStack != null) {
-                                    outStack.append("$");
-                                }
-                            }
-                            if (outTag != null && miCat.id <= ProcessList.FOREGROUND_APP_ADJ) {
-                                appendMemBucket(outTag, memi.pss, memi.shortLabel, false);
-                            }
-                            if (outStack != null) {
-                                appendMemBucket(outStack, memi.pss, memi.shortLabel, true);
-                            }
-                        }
-                        if (outStack != null && miCat.id >= ProcessList.FOREGROUND_APP_ADJ) {
-                            outStack.append("(");
-                            for (int k=0; k<DUMP_MEM_OOM_ADJ.length; k++) {
-                                if (DUMP_MEM_OOM_ADJ[k] == miCat.id) {
-                                    outStack.append(DUMP_MEM_OOM_LABEL[k]);
-                                    outStack.append(":");
-                                    outStack.append(DUMP_MEM_OOM_ADJ[k]);
-                                }
-                            }
-                            outStack.append(")");
-                        }
-                    }
-                }
-            }
-
             if (!brief && !oomOnly && !isCompact) {
                 pw.println();
                 pw.println("Total PSS by process:");
diff --git a/services/java/com/android/server/am/ActivityStack.java b/services/java/com/android/server/am/ActivityStack.java
index e994c23..064b3a8 100644
--- a/services/java/com/android/server/am/ActivityStack.java
+++ b/services/java/com/android/server/am/ActivityStack.java
@@ -2910,6 +2910,19 @@
         mWindowManager.prepareAppTransition(transit, false);
     }
 
+    void moveHomeTaskToTop() {
+        final int top = mTaskHistory.size() - 1;
+        for (int taskNdx = top; taskNdx >= 0; --taskNdx) {
+            final TaskRecord task = mTaskHistory.get(taskNdx);
+            if (task.isHomeTask()) {
+                mTaskHistory.remove(taskNdx);
+                mTaskHistory.add(top, task);
+                mWindowManager.moveTaskToTop(task.taskId);
+                return;
+            }
+        }
+    }
+
     final boolean findTaskToMoveToFrontLocked(int taskId, int flags, Bundle options) {
         final TaskRecord task = taskForIdLocked(taskId);
         if (task != null) {
diff --git a/services/java/com/android/server/am/ActivityStackSupervisor.java b/services/java/com/android/server/am/ActivityStackSupervisor.java
index 3e0b5eb..e0eb2c4 100644
--- a/services/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/java/com/android/server/am/ActivityStackSupervisor.java
@@ -284,6 +284,7 @@
         if (prev != null) {
             prev.mLaunchHomeTaskNext = false;
         }
+        mHomeStack.moveHomeTaskToTop();
         ActivityRecord r = mHomeStack.topRunningActivityLocked(null);
         if (r != null) {
             mService.setFocusedActivityLocked(r);
diff --git a/services/java/com/android/server/am/ProcessList.java b/services/java/com/android/server/am/ProcessList.java
index fb81b3a..54593aa 100644
--- a/services/java/com/android/server/am/ProcessList.java
+++ b/services/java/com/android/server/am/ProcessList.java
@@ -19,6 +19,7 @@
 import java.io.FileOutputStream;
 import java.io.IOException;
 
+import android.app.ActivityManager;
 import com.android.internal.util.MemInfoReader;
 import com.android.server.wm.WindowManagerService;
 
@@ -98,6 +99,10 @@
     // The system process runs at the default adjustment.
     static final int SYSTEM_ADJ = -16;
 
+    // Special code for native processes that are not being managed by the system (so
+    // don't have an oom adj assigned by the system).
+    static final int NATIVE_ADJ = -17;
+
     // Memory pages are 4K.
     static final int PAGE_SIZE = 4*1024;
 
@@ -278,6 +283,46 @@
         return (totalProcessLimit*2)/3;
     }
 
+    private static String buildOomTag(String prefix, String space, int val, int base) {
+        if (val == base) {
+            if (space == null) return prefix;
+            return prefix + "  ";
+        }
+        return prefix + "+" + Integer.toString(val-base);
+    }
+
+    public static String makeOomAdjString(int setAdj) {
+        if (setAdj >= ProcessList.CACHED_APP_MIN_ADJ) {
+            return buildOomTag("cch", "  ", setAdj, ProcessList.CACHED_APP_MIN_ADJ);
+        } else if (setAdj >= ProcessList.SERVICE_B_ADJ) {
+            return buildOomTag("svcb ", null, setAdj, ProcessList.SERVICE_B_ADJ);
+        } else if (setAdj >= ProcessList.PREVIOUS_APP_ADJ) {
+            return buildOomTag("prev ", null, setAdj, ProcessList.PREVIOUS_APP_ADJ);
+        } else if (setAdj >= ProcessList.HOME_APP_ADJ) {
+            return buildOomTag("home ", null, setAdj, ProcessList.HOME_APP_ADJ);
+        } else if (setAdj >= ProcessList.SERVICE_ADJ) {
+            return buildOomTag("svc  ", null, setAdj, ProcessList.SERVICE_ADJ);
+        } else if (setAdj >= ProcessList.HEAVY_WEIGHT_APP_ADJ) {
+            return buildOomTag("hvy  ", null, setAdj, ProcessList.HEAVY_WEIGHT_APP_ADJ);
+        } else if (setAdj >= ProcessList.BACKUP_APP_ADJ) {
+            return buildOomTag("bkup ", null, setAdj, ProcessList.BACKUP_APP_ADJ);
+        } else if (setAdj >= ProcessList.PERCEPTIBLE_APP_ADJ) {
+            return buildOomTag("prcp ", null, setAdj, ProcessList.PERCEPTIBLE_APP_ADJ);
+        } else if (setAdj >= ProcessList.VISIBLE_APP_ADJ) {
+            return buildOomTag("vis  ", null, setAdj, ProcessList.VISIBLE_APP_ADJ);
+        } else if (setAdj >= ProcessList.FOREGROUND_APP_ADJ) {
+            return buildOomTag("fore ", null, setAdj, ProcessList.FOREGROUND_APP_ADJ);
+        } else if (setAdj >= ProcessList.PERSISTENT_PROC_ADJ) {
+            return buildOomTag("pers ", null, setAdj, ProcessList.PERSISTENT_PROC_ADJ);
+        } else if (setAdj >= ProcessList.SYSTEM_ADJ) {
+            return buildOomTag("sys  ", null, setAdj, ProcessList.SYSTEM_ADJ);
+        } else if (setAdj >= ProcessList.NATIVE_ADJ) {
+            return buildOomTag("ntv  ", null, setAdj, ProcessList.NATIVE_ADJ);
+        } else {
+            return Integer.toString(setAdj);
+        }
+    }
+
     // The minimum amount of time after a state change it is safe ro collect PSS.
     public static final int PSS_MIN_TIME_FROM_STATE_CHANGE = 15*1000;
 
@@ -366,6 +411,70 @@
         return sProcStateToProcMem[procState1] != sProcStateToProcMem[procState2];
     }
 
+    public static String makeProcStateString(int curProcState) {
+        String procState;
+        switch (curProcState) {
+            case -1:
+                procState = "N ";
+                break;
+            case ActivityManager.PROCESS_STATE_PERSISTENT:
+                procState = "P ";
+                break;
+            case ActivityManager.PROCESS_STATE_PERSISTENT_UI:
+                procState = "PU";
+                break;
+            case ActivityManager.PROCESS_STATE_TOP:
+                procState = "T ";
+                break;
+            case ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND:
+                procState = "IF";
+                break;
+            case ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND:
+                procState = "IB";
+                break;
+            case ActivityManager.PROCESS_STATE_BACKUP:
+                procState = "BU";
+                break;
+            case ActivityManager.PROCESS_STATE_HEAVY_WEIGHT:
+                procState = "HW";
+                break;
+            case ActivityManager.PROCESS_STATE_SERVICE:
+                procState = "S ";
+                break;
+            case ActivityManager.PROCESS_STATE_RECEIVER:
+                procState = "R ";
+                break;
+            case ActivityManager.PROCESS_STATE_HOME:
+                procState = "HO";
+                break;
+            case ActivityManager.PROCESS_STATE_LAST_ACTIVITY:
+                procState = "LA";
+                break;
+            case ActivityManager.PROCESS_STATE_CACHED_ACTIVITY:
+                procState = "CA";
+                break;
+            case ActivityManager.PROCESS_STATE_CACHED_ACTIVITY_CLIENT:
+                procState = "Ca";
+                break;
+            case ActivityManager.PROCESS_STATE_CACHED_EMPTY:
+                procState = "CE";
+                break;
+            default:
+                procState = "??";
+                break;
+        }
+        return procState;
+    }
+
+    public static void appendRamKb(StringBuilder sb, long ramKb) {
+        for (int j=0, fact=10; j<6; j++, fact*=10) {
+            if (ramKb < fact) {
+                sb.append(' ');
+            }
+        }
+        sb.append(ramKb);
+    }
+
     public static long computeNextPssTime(int procState, boolean first, boolean sleeping,
             long now) {
         final long[] table = sleeping
diff --git a/services/java/com/android/server/am/ProcessMemInfo.java b/services/java/com/android/server/am/ProcessMemInfo.java
new file mode 100644
index 0000000..c94694e
--- /dev/null
+++ b/services/java/com/android/server/am/ProcessMemInfo.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.am;
+
+public class ProcessMemInfo {
+    final String name;
+    final int pid;
+    final int oomAdj;
+    final int procState;
+    final String adjType;
+    final String adjReason;
+    long pss;
+
+    public ProcessMemInfo(String _name, int _pid, int _oomAdj, int _procState,
+            String _adjType, String _adjReason) {
+        name = _name;
+        pid = _pid;
+        oomAdj = _oomAdj;
+        procState = _procState;
+        adjType = _adjType;
+        adjReason = _adjReason;
+    }
+}
diff --git a/services/java/com/android/server/am/ProcessRecord.java b/services/java/com/android/server/am/ProcessRecord.java
index 892271f..35e06b6 100644
--- a/services/java/com/android/server/am/ProcessRecord.java
+++ b/services/java/com/android/server/am/ProcessRecord.java
@@ -529,9 +529,8 @@
     }
 
     public String makeAdjReason() {
-        StringBuilder sb = new StringBuilder(128);
-        sb.append('(').append(adjType).append(')');
         if (adjSource != null || adjTarget != null) {
+            StringBuilder sb = new StringBuilder(128);
             sb.append(' ');
             if (adjTarget instanceof ComponentName) {
                 sb.append(((ComponentName)adjTarget).flattenToShortString());
@@ -550,8 +549,9 @@
             } else {
                 sb.append("{null}");
             }
+            return sb.toString();
         }
-        return sb.toString();
+        return null;
     }
 
     /*
diff --git a/services/java/com/android/server/am/TaskRecord.java b/services/java/com/android/server/am/TaskRecord.java
index 63793fa..479665c 100644
--- a/services/java/com/android/server/am/TaskRecord.java
+++ b/services/java/com/android/server/am/TaskRecord.java
@@ -322,6 +322,10 @@
         return subtask.activity;
     }
 
+    boolean isHomeTask() {
+        return mTaskType == ActivityRecord.HOME_ACTIVITY_TYPE;
+    }
+
     boolean isApplicationTask() {
         return mTaskType == ActivityRecord.APPLICATION_ACTIVITY_TYPE;
     }
diff --git a/services/java/com/android/server/connectivity/PacManager.java b/services/java/com/android/server/connectivity/PacManager.java
index c8cc85e..772921a 100644
--- a/services/java/com/android/server/connectivity/PacManager.java
+++ b/services/java/com/android/server/connectivity/PacManager.java
@@ -24,17 +24,22 @@
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.ServiceConnection;
+import android.net.Proxy;
 import android.net.ProxyProperties;
+import android.os.Binder;
 import android.os.IBinder;
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.SystemClock;
 import android.os.SystemProperties;
+import android.os.UserHandle;
 import android.provider.Settings;
 import android.text.TextUtils;
 import android.util.Log;
 
 import com.android.internal.annotations.GuardedBy;
+import com.android.net.IProxyCallback;
+import com.android.net.IProxyPortListener;
 import com.android.net.IProxyService;
 import com.android.server.IoThread;
 
@@ -79,6 +84,7 @@
     private Context mContext;
 
     private int mCurrentDelay;
+    private int mLastPort;
 
     /**
      * Used for locking when setting mProxyService and all references to mPacUrl or mCurrentPac.
@@ -119,6 +125,7 @@
 
     public PacManager(Context context) {
         mContext = context;
+        mLastPort = -1;
 
         mPacRefreshIntent = PendingIntent.getBroadcast(
                 context, 0, new Intent(ACTION_PAC_REFRESH), 0);
@@ -133,7 +140,16 @@
         return mAlarmManager;
     }
 
-    public synchronized void setCurrentProxyScriptUrl(ProxyProperties proxy) {
+    /**
+     * Updates the PAC Manager with current Proxy information. This is called by
+     * the ConnectivityService directly before a broadcast takes place to allow
+     * the PacManager to indicate that the broadcast should not be sent and the
+     * PacManager will trigger a new broadcast when it is ready.
+     *
+     * @param proxy Proxy information that is about to be broadcast.
+     * @return Returns true when the broadcast should not be sent
+     */
+    public synchronized boolean setCurrentProxyScriptUrl(ProxyProperties proxy) {
         if (!TextUtils.isEmpty(proxy.getPacFileUrl())) {
             synchronized (mProxyLock) {
                 mPacUrl = proxy.getPacFileUrl();
@@ -141,6 +157,7 @@
             mCurrentDelay = DELAY_1;
             getAlarmManager().cancel(mPacRefreshIntent);
             bind();
+            return true;
         } else {
             getAlarmManager().cancel(mPacRefreshIntent);
             synchronized (mProxyLock) {
@@ -156,6 +173,7 @@
                     }
                 }
             }
+            return false;
         }
     }
 
@@ -233,6 +251,16 @@
         }
         Intent intent = new Intent();
         intent.setClassName(PAC_PACKAGE, PAC_SERVICE);
+        // Already bound no need to bind again.
+        if (mProxyConnection != null) {
+            if (mLastPort != -1) {
+                sendPacBroadcast(new ProxyProperties(mPacUrl, mLastPort));
+            } else {
+                Log.e(TAG, "Received invalid port from Local Proxy,"
+                        + " PAC will not be operational");
+            }
+            return;
+        }
         mConnection = new ServiceConnection() {
             @Override
             public void onServiceDisconnected(ComponentName component) {
@@ -277,6 +305,26 @@
 
             @Override
             public void onServiceConnected(ComponentName component, IBinder binder) {
+                IProxyCallback callbackService = IProxyCallback.Stub.asInterface(binder);
+                if (callbackService != null) {
+                    try {
+                        callbackService.getProxyPort(new IProxyPortListener.Stub() {
+                            @Override
+                            public void setProxyPort(int port) throws RemoteException {
+                                mLastPort = port;
+                                if (port != -1) {
+                                    Log.d(TAG, "Local proxy is bound on " + port);
+                                    sendPacBroadcast(new ProxyProperties(mPacUrl, port));
+                                } else {
+                                    Log.e(TAG, "Received invalid port from Local Proxy,"
+                                            + " PAC will not be operational");
+                                }
+                            }
+                        });
+                    } catch (RemoteException e) {
+                        e.printStackTrace();
+                    }
+                }
             }
         };
         mContext.bindService(intent, mProxyConnection,
@@ -287,5 +335,19 @@
         mContext.unbindService(mConnection);
         mContext.unbindService(mProxyConnection);
         mConnection = null;
+        mProxyConnection = null;
+    }
+
+    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);
+        }
     }
 }
diff --git a/services/java/com/android/server/pm/PackageManagerService.java b/services/java/com/android/server/pm/PackageManagerService.java
index 686b64e..39fc4ad 100755
--- a/services/java/com/android/server/pm/PackageManagerService.java
+++ b/services/java/com/android/server/pm/PackageManagerService.java
@@ -9716,10 +9716,6 @@
             throw new IllegalArgumentException(
                     "replacePreferredActivity expects filter to have only 1 action.");
         }
-        if (filter.countCategories() != 1) {
-            throw new IllegalArgumentException(
-                    "replacePreferredActivity expects filter to have only 1 category.");
-        }
         if (filter.countDataAuthorities() != 0
                 || filter.countDataPaths() != 0
                 || filter.countDataSchemes() != 0
@@ -9756,8 +9752,11 @@
                             removed = new ArrayList<PreferredActivity>();
                         }
                         removed.add(pa);
-                        Log.i(TAG, "Removing preferred activity " + pa.mPref.mComponent + ":");
-                        filter.dump(new LogPrinter(Log.INFO, TAG), "  ");
+                        if (DEBUG_PREFERRED) {
+                            Slog.i(TAG, "Removing preferred activity "
+                                    + pa.mPref.mComponent + ":");
+                            filter.dump(new LogPrinter(Log.INFO, TAG), "  ");
+                        }
                     }
                 }
                 if (removed != null) {
@@ -9877,6 +9876,28 @@
     }
 
     @Override
+    public ComponentName getHomeActivities(List<ResolveInfo> allHomeCandidates) {
+        Intent intent = new Intent(Intent.ACTION_MAIN);
+        intent.addCategory(Intent.CATEGORY_HOME);
+
+        final int callingUserId = UserHandle.getCallingUserId();
+        List<ResolveInfo> list = queryIntentActivities(intent, null, 0, callingUserId);
+        ResolveInfo preferred = findPreferredActivity(intent, null, 0, list, 0,
+                true, false, callingUserId);
+
+        allHomeCandidates.clear();
+        if (list != null) {
+            for (ResolveInfo ri : list) {
+                allHomeCandidates.add(ri);
+            }
+        }
+        return (preferred == null || preferred.activityInfo == null)
+                ? null
+                : new ComponentName(preferred.activityInfo.packageName,
+                        preferred.activityInfo.name);
+    }
+
+    @Override
     public void setApplicationEnabledSetting(String appPackageName,
             int newState, int flags, int userId, String callingPackage) {
         if (!sUserManager.exists(userId)) return;
diff --git a/test-runner/src/android/test/mock/MockPackageManager.java b/test-runner/src/android/test/mock/MockPackageManager.java
index 4683534..5f944f6 100644
--- a/test-runner/src/android/test/mock/MockPackageManager.java
+++ b/test-runner/src/android/test/mock/MockPackageManager.java
@@ -46,6 +46,7 @@
 import android.graphics.drawable.Drawable;
 import android.net.Uri;
 import android.os.Binder;
+import android.os.RemoteException;
 import android.os.UserHandle;
 
 import java.util.List;
@@ -543,6 +544,12 @@
         throw new UnsupportedOperationException();
     }
 
+    /** @hide - hidden in superclass */
+    @Override
+    public ComponentName getHomeActivities(List<ResolveInfo> outActivities) {
+        throw new UnsupportedOperationException();
+    }
+
     @Override
     public String[] getSystemSharedLibraryNames() {
         throw new UnsupportedOperationException();
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/binding/BaseAdapter.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/binding/AdapterHelper.java
similarity index 62%
rename from tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/binding/BaseAdapter.java
rename to tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/binding/AdapterHelper.java
index e0414fe..6c998af 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/binding/BaseAdapter.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/binding/AdapterHelper.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2011 The Android Open Source Project
+ * 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.
@@ -16,7 +16,6 @@
 
 package com.android.layoutlib.bridge.impl.binding;
 
-import com.android.ide.common.rendering.api.AdapterBinding;
 import com.android.ide.common.rendering.api.DataBindingItem;
 import com.android.ide.common.rendering.api.IProjectCallback;
 import com.android.ide.common.rendering.api.LayoutLog;
@@ -27,7 +26,6 @@
 import com.android.layoutlib.bridge.impl.RenderAction;
 import com.android.util.Pair;
 
-import android.database.DataSetObserver;
 import android.view.View;
 import android.view.ViewGroup;
 import android.widget.AdapterView;
@@ -35,124 +33,27 @@
 import android.widget.ImageView;
 import android.widget.TextView;
 
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-
 /**
- * Base adapter to do fake data binding in {@link AdapterView} objects.
+ * A Helper class to do fake data binding in {@link AdapterView} objects.
  */
-public class BaseAdapter {
+@SuppressWarnings("deprecation")
+public class AdapterHelper {
 
-    /**
-     * This is the items provided by the adapter. They are dynamically generated.
-     */
-    protected final static class AdapterItem {
-        private final DataBindingItem mItem;
-        private final int mType;
-        private final int mFullPosition;
-        private final int mPositionPerType;
-        private List<AdapterItem> mChildren;
-
-        protected AdapterItem(DataBindingItem item, int type, int fullPosition,
-                int positionPerType) {
-            mItem = item;
-            mType = type;
-            mFullPosition = fullPosition;
-            mPositionPerType = positionPerType;
-        }
-
-        void addChild(AdapterItem child) {
-            if (mChildren == null) {
-                mChildren = new ArrayList<AdapterItem>();
-            }
-
-            mChildren.add(child);
-        }
-
-        List<AdapterItem> getChildren() {
-            if (mChildren != null) {
-                return mChildren;
-            }
-
-            return Collections.emptyList();
-        }
-
-        int getType() {
-            return mType;
-        }
-
-        int getFullPosition() {
-            return mFullPosition;
-        }
-
-        int getPositionPerType() {
-            return mPositionPerType;
-        }
-
-        DataBindingItem getDataBindingItem() {
-            return mItem;
-        }
-    }
-
-    private final AdapterBinding mBinding;
-    private final IProjectCallback mCallback;
-    private final ResourceReference mAdapterRef;
-    private boolean mSkipCallbackParser = false;
-
-    protected final List<AdapterItem> mItems = new ArrayList<AdapterItem>();
-
-    protected BaseAdapter(ResourceReference adapterRef, AdapterBinding binding,
-            IProjectCallback callback) {
-        mAdapterRef = adapterRef;
-        mBinding = binding;
-        mCallback = callback;
-    }
-
-    // ------- Some Adapter method used by all children classes.
-
-    public boolean areAllItemsEnabled() {
-        return true;
-    }
-
-    public boolean hasStableIds() {
-        return true;
-    }
-
-    public boolean isEmpty() {
-        return mItems.size() == 0;
-    }
-
-    public void registerDataSetObserver(DataSetObserver observer) {
-        // pass
-    }
-
-    public void unregisterDataSetObserver(DataSetObserver observer) {
-        // pass
-    }
-
-    // -------
-
-
-    protected AdapterBinding getBinding() {
-        return mBinding;
-    }
-
-    protected View getView(AdapterItem item, AdapterItem parentItem, View convertView,
-            ViewGroup parent) {
+    static Pair<View, Boolean> getView(AdapterItem item, AdapterItem parentItem, ViewGroup parent,
+            IProjectCallback callback, ResourceReference adapterRef, boolean skipCallbackParser) {
         // we don't care about recycling here because we never scroll.
         DataBindingItem dataBindingItem = item.getDataBindingItem();
 
         BridgeContext context = RenderAction.getCurrentContext();
 
         Pair<View, Boolean> pair = context.inflateView(dataBindingItem.getViewReference(),
-                parent, false /*attachToRoot*/, mSkipCallbackParser);
+                parent, false /*attachToRoot*/, skipCallbackParser);
 
         View view = pair.getFirst();
-        mSkipCallbackParser |= pair.getSecond();
+        skipCallbackParser |= pair.getSecond();
 
         if (view != null) {
-            fillView(context, view, item, parentItem);
+            fillView(context, view, item, parentItem, callback, adapterRef);
         } else {
             // create a text view to display an error.
             TextView tv = new TextView(context);
@@ -160,16 +61,16 @@
             view = tv;
         }
 
-        return view;
+        return Pair.of(view, skipCallbackParser);
     }
 
-    private void fillView(BridgeContext context, View view, AdapterItem item,
-            AdapterItem parentItem) {
+    private static void fillView(BridgeContext context, View view, AdapterItem item,
+            AdapterItem parentItem, IProjectCallback callback, ResourceReference adapterRef) {
         if (view instanceof ViewGroup) {
             ViewGroup group = (ViewGroup) view;
             final int count = group.getChildCount();
             for (int i = 0 ; i < count ; i++) {
-                fillView(context, group.getChildAt(i), item, parentItem);
+                fillView(context, group.getChildAt(i), item, parentItem, callback, adapterRef);
             }
         } else {
             int id = view.getId();
@@ -184,8 +85,8 @@
 
                     if (view instanceof TextView) {
                         TextView tv = (TextView) view;
-                        Object value = mCallback.getAdapterItemValue(
-                                mAdapterRef, context.getViewKey(view),
+                        Object value = callback.getAdapterItemValue(
+                                adapterRef, context.getViewKey(view),
                                 item.getDataBindingItem().getViewReference(),
                                 fullPosition, positionPerType,
                                 fullParentPosition, parentPositionPerType,
@@ -204,8 +105,8 @@
                     if (view instanceof Checkable) {
                         Checkable cb = (Checkable) view;
 
-                        Object value = mCallback.getAdapterItemValue(
-                                mAdapterRef, context.getViewKey(view),
+                        Object value = callback.getAdapterItemValue(
+                                adapterRef, context.getViewKey(view),
                                 item.getDataBindingItem().getViewReference(),
                                 fullPosition, positionPerType,
                                 fullParentPosition, parentPositionPerType,
@@ -224,8 +125,8 @@
                     if (view instanceof ImageView) {
                         ImageView iv = (ImageView) view;
 
-                        Object value = mCallback.getAdapterItemValue(
-                                mAdapterRef, context.getViewKey(view),
+                        Object value = callback.getAdapterItemValue(
+                                adapterRef, context.getViewKey(view),
                                 item.getDataBindingItem().getViewReference(),
                                 fullPosition, positionPerType,
                                 fullParentPosition, parentPositionPerType,
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/binding/AdapterItem.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/binding/AdapterItem.java
new file mode 100644
index 0000000..8e28dba
--- /dev/null
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/binding/AdapterItem.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.layoutlib.bridge.impl.binding;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import com.android.ide.common.rendering.api.DataBindingItem;
+
+/**
+ * This is the items provided by the adapter. They are dynamically generated.
+ */
+final class AdapterItem {
+    private final DataBindingItem mItem;
+    private final int mType;
+    private final int mFullPosition;
+    private final int mPositionPerType;
+    private List<AdapterItem> mChildren;
+
+    protected AdapterItem(DataBindingItem item, int type, int fullPosition,
+            int positionPerType) {
+        mItem = item;
+        mType = type;
+        mFullPosition = fullPosition;
+        mPositionPerType = positionPerType;
+    }
+
+    void addChild(AdapterItem child) {
+        if (mChildren == null) {
+            mChildren = new ArrayList<AdapterItem>();
+        }
+
+        mChildren.add(child);
+    }
+
+    List<AdapterItem> getChildren() {
+        if (mChildren != null) {
+            return mChildren;
+        }
+
+        return Collections.emptyList();
+    }
+
+    int getType() {
+        return mType;
+    }
+
+    int getFullPosition() {
+        return mFullPosition;
+    }
+
+    int getPositionPerType() {
+        return mPositionPerType;
+    }
+
+    DataBindingItem getDataBindingItem() {
+        return mItem;
+    }
+}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/binding/FakeAdapter.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/binding/FakeAdapter.java
index 22570b9..9a13f5a 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/binding/FakeAdapter.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/binding/FakeAdapter.java
@@ -20,10 +20,12 @@
 import com.android.ide.common.rendering.api.DataBindingItem;
 import com.android.ide.common.rendering.api.IProjectCallback;
 import com.android.ide.common.rendering.api.ResourceReference;
+import com.android.util.Pair;
 
 import android.view.View;
 import android.view.ViewGroup;
 import android.widget.AdapterView;
+import android.widget.BaseAdapter;
 import android.widget.ListAdapter;
 import android.widget.SpinnerAdapter;
 
@@ -35,17 +37,23 @@
  * and {@link SpinnerAdapter}.
  *
  */
-public class FakeAdapter extends BaseAdapter implements ListAdapter, SpinnerAdapter {
+@SuppressWarnings("deprecation")
+public class FakeAdapter extends BaseAdapter {
 
     // don't use a set because the order is important.
     private final List<ResourceReference> mTypes = new ArrayList<ResourceReference>();
+    private final IProjectCallback mCallback;
+    private final ResourceReference mAdapterRef;
+    private final List<AdapterItem> mItems = new ArrayList<AdapterItem>();
+    private boolean mSkipCallbackParser = false;
 
     public FakeAdapter(ResourceReference adapterRef, AdapterBinding binding,
             IProjectCallback callback) {
-        super(adapterRef, binding, callback);
+        mAdapterRef = adapterRef;
+        mCallback = callback;
 
-        final int repeatCount = getBinding().getRepeatCount();
-        final int itemCount = getBinding().getItemCount();
+        final int repeatCount = binding.getRepeatCount();
+        final int itemCount = binding.getItemCount();
 
         // Need an array to count for each type.
         // This is likely too big, but is the max it can be.
@@ -54,7 +62,7 @@
         // We put several repeating sets.
         for (int r = 0 ; r < repeatCount ; r++) {
             // loop on the type of list items, and add however many for each type.
-            for (DataBindingItem dataBindingItem : getBinding()) {
+            for (DataBindingItem dataBindingItem : binding) {
                 ResourceReference viewRef = dataBindingItem.getViewReference();
                 int typeIndex = mTypes.indexOf(viewRef);
                 if (typeIndex == -1) {
@@ -103,7 +111,11 @@
     public View getView(int position, View convertView, ViewGroup parent) {
         // we don't care about recycling here because we never scroll.
         AdapterItem item = mItems.get(position);
-        return getView(item, null /*parentGroup*/, convertView, parent);
+        Pair<View, Boolean> pair = AdapterHelper.getView(item, null /*parentGroup*/, parent,
+                mCallback, mAdapterRef, mSkipCallbackParser);
+        mSkipCallbackParser = pair.getSecond();
+        return pair.getFirst();
+
     }
 
     @Override
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/binding/FakeExpandableAdapter.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/binding/FakeExpandableAdapter.java
index 199e040..e539579 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/binding/FakeExpandableAdapter.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/binding/FakeExpandableAdapter.java
@@ -20,7 +20,9 @@
 import com.android.ide.common.rendering.api.DataBindingItem;
 import com.android.ide.common.rendering.api.IProjectCallback;
 import com.android.ide.common.rendering.api.ResourceReference;
+import com.android.util.Pair;
 
+import android.database.DataSetObserver;
 import android.view.View;
 import android.view.ViewGroup;
 import android.widget.ExpandableListAdapter;
@@ -29,8 +31,14 @@
 import java.util.ArrayList;
 import java.util.List;
 
-public class FakeExpandableAdapter extends BaseAdapter implements ExpandableListAdapter,
-        HeterogeneousExpandableList {
+@SuppressWarnings("deprecation")
+public class FakeExpandableAdapter implements ExpandableListAdapter, HeterogeneousExpandableList {
+
+    private final IProjectCallback mCallback;
+    private final ResourceReference mAdapterRef;
+    private boolean mSkipCallbackParser = false;
+
+    protected final List<AdapterItem> mItems = new ArrayList<AdapterItem>();
 
     // don't use a set because the order is important.
     private final List<ResourceReference> mGroupTypes = new ArrayList<ResourceReference>();
@@ -38,7 +46,8 @@
 
     public FakeExpandableAdapter(ResourceReference adapterRef, AdapterBinding binding,
             IProjectCallback callback) {
-        super(adapterRef, binding, callback);
+        mAdapterRef = adapterRef;
+        mCallback = callback;
 
         createItems(binding, binding.getItemCount(), binding.getRepeatCount(), mGroupTypes, 1);
     }
@@ -125,7 +134,10 @@
             ViewGroup parent) {
         // we don't care about recycling here because we never scroll.
         AdapterItem item = mItems.get(groupPosition);
-        return getView(item, null /*parentItem*/, convertView, parent);
+        Pair<View, Boolean> pair = AdapterHelper.getView(item, null /*parentItem*/, parent,
+                mCallback, mAdapterRef, mSkipCallbackParser);
+        mSkipCallbackParser = pair.getSecond();
+        return pair.getFirst();
     }
 
     @Override
@@ -134,7 +146,10 @@
         // we don't care about recycling here because we never scroll.
         AdapterItem parentItem = mItems.get(groupPosition);
         AdapterItem item = getChildItem(groupPosition, childPosition);
-        return getView(item, parentItem, convertView, parent);
+        Pair<View, Boolean> pair = AdapterHelper.getView(item, parentItem, parent, mCallback,
+                mAdapterRef, mSkipCallbackParser);
+        mSkipCallbackParser = pair.getSecond();
+        return pair.getFirst();
     }
 
     @Override
@@ -172,6 +187,31 @@
         // pass
     }
 
+    @Override
+    public void registerDataSetObserver(DataSetObserver observer) {
+        // pass
+    }
+
+    @Override
+    public void unregisterDataSetObserver(DataSetObserver observer) {
+        // pass
+    }
+
+    @Override
+    public boolean hasStableIds() {
+        return true;
+    }
+
+    @Override
+    public boolean areAllItemsEnabled() {
+        return true;
+    }
+
+    @Override
+    public boolean isEmpty() {
+        return mItems.isEmpty();
+    }
+
     // ---- HeterogeneousExpandableList
 
     @Override