Merge "Always disable() through SBMS; watch date."
diff --git a/api/current.txt b/api/current.txt
index b0621c2..d113e90 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -4528,6 +4528,44 @@
     field public static final java.lang.String VENDOR_SPECIFIC_HEADSET_EVENT_COMPANY_ID_CATEGORY = "android.bluetooth.headset.intent.category.companyid";
   }
 
+  public final class BluetoothHealth implements android.bluetooth.BluetoothProfile {
+    method public boolean connectChannelToSource(android.bluetooth.BluetoothDevice, android.bluetooth.BluetoothHealthAppConfiguration);
+    method public boolean disconnectChannel(android.bluetooth.BluetoothDevice, android.bluetooth.BluetoothHealthAppConfiguration, int);
+    method public java.util.List<android.bluetooth.BluetoothDevice> getConnectedDevices();
+    method public int getConnectionState(android.bluetooth.BluetoothDevice);
+    method public java.util.List<android.bluetooth.BluetoothDevice> getDevicesMatchingConnectionStates(int[]);
+    method public android.os.ParcelFileDescriptor getMainChannelFd(android.bluetooth.BluetoothDevice, android.bluetooth.BluetoothHealthAppConfiguration);
+    method public boolean registerSinkAppConfiguration(java.lang.String, int, android.bluetooth.BluetoothHealthCallback);
+    method public boolean unregisterAppConfiguration(android.bluetooth.BluetoothHealthAppConfiguration);
+    field public static final int APP_CONFIG_REGISTRATION_FAILURE = 1; // 0x1
+    field public static final int APP_CONFIG_REGISTRATION_SUCCESS = 0; // 0x0
+    field public static final int APP_CONFIG_UNREGISTRATION_FAILURE = 3; // 0x3
+    field public static final int APP_CONFIG_UNREGISTRATION_SUCCESS = 2; // 0x2
+    field public static final int CHANNEL_TYPE_RELIABLE = 10; // 0xa
+    field public static final int CHANNEL_TYPE_STREAMING = 11; // 0xb
+    field public static final int SINK_ROLE = 2; // 0x2
+    field public static final int SOURCE_ROLE = 1; // 0x1
+    field public static final int STATE_CHANNEL_CONNECTED = 2; // 0x2
+    field public static final int STATE_CHANNEL_CONNECTING = 1; // 0x1
+    field public static final int STATE_CHANNEL_DISCONNECTED = 0; // 0x0
+    field public static final int STATE_CHANNEL_DISCONNECTING = 3; // 0x3
+  }
+
+  public final class BluetoothHealthAppConfiguration implements android.os.Parcelable {
+    method public int describeContents();
+    method public int getDataType();
+    method public java.lang.String getName();
+    method public int getRole();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator CREATOR;
+  }
+
+  public abstract class BluetoothHealthCallback {
+    ctor public BluetoothHealthCallback();
+    method public void onHealthAppConfigurationStatusChange(android.bluetooth.BluetoothHealthAppConfiguration, int);
+    method public void onHealthChannelStateChange(android.bluetooth.BluetoothHealthAppConfiguration, android.bluetooth.BluetoothDevice, int, int, android.os.ParcelFileDescriptor, int);
+  }
+
   public abstract interface BluetoothProfile {
     method public abstract java.util.List<android.bluetooth.BluetoothDevice> getConnectedDevices();
     method public abstract int getConnectionState(android.bluetooth.BluetoothDevice);
@@ -16662,6 +16700,7 @@
     field public static final java.lang.String CONTENT_TYPE = "vnd.android.cursor.dir/raw_contact_entity";
     field public static final android.net.Uri CONTENT_URI;
     field public static final java.lang.String DATA_ID = "data_id";
+    field public static final android.net.Uri PROFILE_CONTENT_URI;
   }
 
   public static final class ContactsContract.Settings implements android.provider.ContactsContract.SettingsColumns {
@@ -16674,6 +16713,7 @@
     field public static final java.lang.String ACCOUNT_NAME = "account_name";
     field public static final java.lang.String ACCOUNT_TYPE = "account_type";
     field public static final java.lang.String ANY_UNSYNCED = "any_unsynced";
+    field public static final java.lang.String DATA_SET = "data_set";
     field public static final java.lang.String SHOULD_SYNC = "should_sync";
     field public static final java.lang.String UNGROUPED_COUNT = "summ_count";
     field public static final java.lang.String UNGROUPED_VISIBLE = "ungrouped_visible";
@@ -25917,8 +25957,9 @@
     ctor public FrameLayout(android.content.Context);
     ctor public FrameLayout(android.content.Context, android.util.AttributeSet);
     ctor public FrameLayout(android.content.Context, android.util.AttributeSet, int);
-    method public boolean getConsiderGoneChildrenWhenMeasuring();
+    method public deprecated boolean getConsiderGoneChildrenWhenMeasuring();
     method public android.graphics.drawable.Drawable getForeground();
+    method public boolean getMeasureAllChildren();
     method protected void onLayout(boolean, int, int, int, int);
     method public void setForeground(android.graphics.drawable.Drawable);
     method public void setForegroundGravity(int);
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 41e3fdf..034e3c7 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -1638,6 +1638,12 @@
      * or later, consider instead using {@link LoaderManager} instead, available
      * via {@link #getLoaderManager()}.</em>
      *
+     * <p><strong>Warning:</strong> Do not call {@link Cursor#close()} on a cursor obtained using
+     * this method, because the activity will do that for you at the appropriate time. However, if
+     * you call {@link #stopManagingCursor} on a cursor from a managed query, the system <em>will
+     * not</em> automatically close the cursor and, in that case, you must call
+     * {@link Cursor#close()}.</p>
+     * 
      * @param uri The URI of the content provider to query.
      * @param projection List of columns to return.
      * @param selection SQL WHERE clause.
@@ -1672,6 +1678,12 @@
      * or later, consider instead using {@link LoaderManager} instead, available
      * via {@link #getLoaderManager()}.</em>
      *
+     * <p><strong>Warning:</strong> Do not call {@link Cursor#close()} on a cursor obtained using
+     * this method, because the activity will do that for you at the appropriate time. However, if
+     * you call {@link #stopManagingCursor} on a cursor from a managed query, the system <em>will
+     * not</em> automatically close the cursor and, in that case, you must call
+     * {@link Cursor#close()}.</p>
+     * 
      * @param uri The URI of the content provider to query.
      * @param projection List of columns to return.
      * @param selection SQL WHERE clause.
@@ -1707,6 +1719,12 @@
      * or later, consider instead using {@link LoaderManager} instead, available
      * via {@link #getLoaderManager()}.</em>
      *
+     * <p><strong>Warning:</strong> Do not call {@link Cursor#close()} on cursor obtained from
+     * {@link #managedQuery}, because the activity will do that for you at the appropriate time.
+     * However, if you call {@link #stopManagingCursor} on a cursor from a managed query, the system
+     * <em>will not</em> automatically close the cursor and, in that case, you must call
+     * {@link Cursor#close()}.</p>
+     * 
      * @param c The Cursor to be managed.
      * 
      * @see #managedQuery(android.net.Uri , String[], String, String[], String)
@@ -1728,6 +1746,10 @@
      * {@link #startManagingCursor}, stop the activity's management of that
      * cursor.
      * 
+     * <p><strong>Warning:</strong> After calling this method on a cursor from a managed query,
+     * the system <em>will not</em> automatically close the cursor and you must call 
+     * {@link Cursor#close()}.</p>
+     * 
      * @param c The Cursor that was being managed.
      * 
      * @see #startManagingCursor
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index 102fac1..4fe9cef 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -1254,6 +1254,12 @@
          */
         public ComponentName importanceReasonComponent;
         
+        /**
+         * When {@link importanceReasonPid} is non-0, this is the importance
+         * of the other pid. @hide
+         */
+        public int importanceReasonImportance;
+
         public RunningAppProcessInfo() {
             importance = IMPORTANCE_FOREGROUND;
             importanceReasonCode = REASON_UNKNOWN;
@@ -1280,6 +1286,7 @@
             dest.writeInt(importanceReasonCode);
             dest.writeInt(importanceReasonPid);
             ComponentName.writeToParcel(importanceReasonComponent, dest);
+            dest.writeInt(importanceReasonImportance);
         }
 
         public void readFromParcel(Parcel source) {
@@ -1293,6 +1300,7 @@
             importanceReasonCode = source.readInt();
             importanceReasonPid = source.readInt();
             importanceReasonComponent = ComponentName.readFromParcel(source);
+            importanceReasonImportance = source.readInt();
         }
 
         public static final Creator<RunningAppProcessInfo> CREATOR = 
diff --git a/core/java/android/bluetooth/BluetoothHealth.java b/core/java/android/bluetooth/BluetoothHealth.java
index 0a01dcf..c165d92 100644
--- a/core/java/android/bluetooth/BluetoothHealth.java
+++ b/core/java/android/bluetooth/BluetoothHealth.java
@@ -32,10 +32,25 @@
  * <p>BluetoothHealth is a proxy object for controlling the Bluetooth
  * Service via IPC.
  *
- * <p> Use {@link BluetoothAdapter#getProfileProxy} to get
- * the BluetoothHealth proxy object. Use
- * {@link BluetoothAdapter#closeProfileProxy} to close the service connection.
- * @hide
+ * <p> How to connect to a health device which is acting in the source role.
+ *  <li> Use {@link BluetoothAdapter#getProfileProxy} to get
+ *  the BluetoothHealth proxy object. </li>
+ *  <li> Create an {@link BluetoothHealth} callback and call
+ *  {@link #registerSinkAppConfiguration} to register an application
+ *  configuration </li>
+ *  <li> Pair with the remote device. This currently needs to be done manually
+ *  from Bluetooth Settings </li>
+ *  <li> Connect to a health device using {@link #connectChannelToSource}. Some
+ *  devices will connect the channel automatically. The {@link BluetoothHealth}
+ *  callback will inform the application of channel state change. </li>
+ *  <li> Use the file descriptor provided with a connected channel to read and
+ *  write data to the health channel. </li>
+ *  <li> The received data needs to be interpreted using a health manager which
+ *  implements the IEEE 11073-xxxxx specifications.
+ *  <li> When done, close the health channel by calling {@link #disconnectChannel}
+ *  and unregister the application configuration calling
+ *  {@link #unregisterAppConfiguration}
+ *
  */
 public final class BluetoothHealth implements BluetoothProfile {
     private static final String TAG = "BluetoothHealth";
@@ -137,7 +152,6 @@
      *
      * @param config  The health app configuration
      * @return Success or failure.
-     * @hide
      */
     public boolean unregisterAppConfiguration(BluetoothHealthAppConfiguration config) {
         boolean result = false;
@@ -222,16 +236,15 @@
      * @param device The remote Bluetooth device.
      * @param config The application configuration which has been registered using
      *        {@link #registerSinkAppConfiguration(String, int, BluetoothHealthCallback) }
-     * @param fd The file descriptor that was associated with the channel.
+     * @param channelId The channel id associated with the channel
      * @return If true, the callback associated with the application config will be called.
-     * @hide
      */
     public boolean disconnectChannel(BluetoothDevice device,
-            BluetoothHealthAppConfiguration config, ParcelFileDescriptor fd) {
+            BluetoothHealthAppConfiguration config, int channelId) {
         if (mService != null && isEnabled() && isValidDevice(device) &&
                 config != null) {
             try {
-                return mService.disconnectChannel(device, config, fd);
+                return mService.disconnectChannel(device, config, channelId);
             } catch (RemoteException e) {
                 Log.e(TAG, e.toString());
             }
@@ -248,11 +261,13 @@
      *
      * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
      *
+     * <p> Its the responsibility of the caller to close the ParcelFileDescriptor
+     * when done.
+     *
      * @param device The remote Bluetooth health device
      * @param config The application configuration
      * @return null on failure, ParcelFileDescriptor on success.
      */
-
     public ParcelFileDescriptor getMainChannelFd(BluetoothDevice device,
             BluetoothHealthAppConfiguration config) {
         if (mService != null && isEnabled() && isValidDevice(device) &&
@@ -300,7 +315,7 @@
     }
 
     /**
-     * Get connected devices for this specific profile.
+     * Get connected devices for the health profile.
      *
      * <p> Return the set of devices which are in state {@link #STATE_CONNECTED}
      *
@@ -368,14 +383,15 @@
         @Override
         public void onHealthAppConfigurationStatusChange(BluetoothHealthAppConfiguration config,
                                                          int status) {
-            mCallback.onHealthAppConfigurationStatusChange(config, status);
+           mCallback.onHealthAppConfigurationStatusChange(config, status);
         }
 
         @Override
         public void onHealthChannelStateChange(BluetoothHealthAppConfiguration config,
                                        BluetoothDevice device, int prevState, int newState,
-                                       ParcelFileDescriptor fd) {
-            mCallback.onHealthChannelStateChange(config, device, prevState, newState, fd);
+                                       ParcelFileDescriptor fd, int channelId) {
+            mCallback.onHealthChannelStateChange(config, device, prevState, newState, fd,
+                                                 channelId);
         }
     }
 
@@ -389,13 +405,13 @@
     public static final int STATE_CHANNEL_DISCONNECTING = 3;
 
     /** Health App Configuration registration success */
-    public static final int APPLICATION_REGISTRATION_SUCCESS = 0;
+    public static final int APP_CONFIG_REGISTRATION_SUCCESS = 0;
     /** Health App Configuration registration failure */
-    public static final int APPLICATION_REGISTRATION_FAILURE = 1;
+    public static final int APP_CONFIG_REGISTRATION_FAILURE = 1;
     /** Health App Configuration un-registration success */
-    public static final int APPLICATION_UNREGISTRATION_SUCCESS = 2;
+    public static final int APP_CONFIG_UNREGISTRATION_SUCCESS = 2;
     /** Health App Configuration un-registration failure */
-    public static final int APPLICATION_UNREGISTRATION_FAILURE = 3;
+    public static final int APP_CONFIG_UNREGISTRATION_FAILURE = 3;
 
     private ServiceListener mServiceListener;
     private IBluetooth mService;
diff --git a/core/java/android/bluetooth/BluetoothHealthAppConfiguration.java b/core/java/android/bluetooth/BluetoothHealthAppConfiguration.java
index 7020249..15a9101 100644
--- a/core/java/android/bluetooth/BluetoothHealthAppConfiguration.java
+++ b/core/java/android/bluetooth/BluetoothHealthAppConfiguration.java
@@ -26,7 +26,6 @@
  * that the Bluetooth Health third party application will register to communicate with the
  * remote Bluetooth health device.
  *
- * @hide
  */
 public final class BluetoothHealthAppConfiguration implements Parcelable {
     private final String mName;
@@ -39,6 +38,7 @@
      *
      * @param name Friendly name associated with the application configuration
      * @param dataType Data Type of the remote Bluetooth Health device
+     * @hide
      */
     BluetoothHealthAppConfiguration(String name, int dataType) {
         mName = name;
@@ -54,6 +54,7 @@
      * @param dataType Data Type of the remote Bluetooth Health device
      * @param role {@link BluetoothHealth#SOURCE_ROLE} or
      *                     {@link BluetoothHealth#SINK_ROLE}
+     * @hide
      */
     BluetoothHealthAppConfiguration(String name, int dataType, int role, int
         channelType) {
@@ -93,7 +94,6 @@
             mChannelType + "]";
     }
 
-    @Override
     public int describeContents() {
         return 0;
     }
@@ -132,6 +132,7 @@
      * @return One of {@link BluetoothHealth#CHANNEL_TYPE_RELIABLE} or
      *                         {@link BluetoothHealth#CHANNEL_TYPE_STREAMING} or
      *                         {@link BluetoothHealth#CHANNEL_TYPE_ANY}.
+     * @hide
      */
     public int getChannelType() {
         return mChannelType;
@@ -155,13 +156,10 @@
         }
     };
 
-    @Override
     public void writeToParcel(Parcel out, int flags) {
         out.writeString(mName);
         out.writeInt(mDataType);
         out.writeInt(mRole);
         out.writeInt(mChannelType);
     }
-
-
 }
diff --git a/core/java/android/bluetooth/BluetoothHealthCallback.java b/core/java/android/bluetooth/BluetoothHealthCallback.java
index 0d11bb5..baf2ade 100644
--- a/core/java/android/bluetooth/BluetoothHealthCallback.java
+++ b/core/java/android/bluetooth/BluetoothHealthCallback.java
@@ -21,22 +21,48 @@
 import android.util.Log;
 
 /**
- * This class is used for all the {@link BluetoothHealth} callbacks.
- * @hide
+ * This abstract class is used to implement {@link BluetoothHealth} callbacks.
  */
 public abstract class BluetoothHealthCallback {
-
     private static final String TAG = "BluetoothHealthCallback";
 
+    /**
+     * Callback to inform change in registration state of the health
+     * application.
+     * <p> This callback is called on the binder thread (not on the UI thread)
+     *
+     * @param config Bluetooth Health app configuration
+     * @param status Success or failure of the registration or unregistration
+     *            calls. Can be one of
+     *            {@link BluetoothHealth#APP_CONFIG_REGISTRATION_SUCCESS} or
+     *            {@link BluetoothHealth#APP_CONFIG_REGISTRATION_FAILURE} or
+     *            {@link BluetoothHealth#APP_CONFIG_UNREGISTRATION_SUCCESS} or
+     *            {@link BluetoothHealth#APP_CONFIG_UNREGISTRATION_FAILURE}
+     */
     public void onHealthAppConfigurationStatusChange(BluetoothHealthAppConfiguration config,
-                                                int status) {
-        Log.d(TAG, "onHealthAppConfigurationStatusChange: " + config + " Status:" + status);
+            int status) {
+        Log.d(TAG, "onHealthAppConfigurationStatusChange: " + config + "Status: " + status);
     }
 
+    /**
+     * Callback to inform change in channel state.
+     * <p> Its the responsibility of the implementor of this callback to close the
+     * parcel file descriptor when done. This callback is called on the Binder
+     * thread (not the UI thread)
+     *
+     * @param config The Health app configutation
+     * @param device The Bluetooth Device
+     * @param prevState The previous state of the channel
+     * @param newState The new state of the channel.
+     * @param fd The Parcel File Descriptor when the channel state is connected.
+     * @param channelId The id associated with the channel. This id will be used
+     *            in future calls like when disconnecting the channel.
+     */
     public void onHealthChannelStateChange(BluetoothHealthAppConfiguration config,
-                                    BluetoothDevice device, int prevState, int newState,
-                                    ParcelFileDescriptor fd) {
-        Log.d(TAG, "onHealthChannelStateChange: " + config + " Device:" + device +
-            "PrevState:" + prevState + "NewState:" + newState + "FileDescriptor:" + fd);
+            BluetoothDevice device, int prevState, int newState, ParcelFileDescriptor fd,
+            int channelId) {
+        Log.d(TAG, "onHealthChannelStateChange: " + config + "Device: " + device +
+              "prevState:" + prevState + "newState:" + newState + "ParcelFd:" + fd +
+              "ChannelId:" + channelId);
     }
 }
diff --git a/core/java/android/bluetooth/IBluetooth.aidl b/core/java/android/bluetooth/IBluetooth.aidl
index d4e7f7d..fefeb93 100644
--- a/core/java/android/bluetooth/IBluetooth.aidl
+++ b/core/java/android/bluetooth/IBluetooth.aidl
@@ -116,7 +116,7 @@
     boolean connectChannelToSource(in BluetoothDevice device, in BluetoothHealthAppConfiguration config);
     boolean connectChannelToSink(in BluetoothDevice device, in BluetoothHealthAppConfiguration config,
         int channelType);
-    boolean disconnectChannel(in BluetoothDevice device, in BluetoothHealthAppConfiguration config, in ParcelFileDescriptor fd);
+    boolean disconnectChannel(in BluetoothDevice device, in BluetoothHealthAppConfiguration config, int id);
     ParcelFileDescriptor getMainChannelFd(in BluetoothDevice device, in BluetoothHealthAppConfiguration config);
     List<BluetoothDevice> getConnectedHealthDevices();
     List<BluetoothDevice> getHealthDevicesMatchingConnectionStates(in int[] states);
diff --git a/core/java/android/bluetooth/IBluetoothHealthCallback.aidl b/core/java/android/bluetooth/IBluetoothHealthCallback.aidl
index 9fe5335..0ace9fe 100644
--- a/core/java/android/bluetooth/IBluetoothHealthCallback.aidl
+++ b/core/java/android/bluetooth/IBluetoothHealthCallback.aidl
@@ -27,5 +27,6 @@
 {
     void onHealthAppConfigurationStatusChange(in BluetoothHealthAppConfiguration config, int status);
     void onHealthChannelStateChange(in BluetoothHealthAppConfiguration config,
-        in BluetoothDevice device, int prevState, int newState, in ParcelFileDescriptor fd);
+        in BluetoothDevice device, int prevState, int newState, in
+        ParcelFileDescriptor fd, int id);
 }
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 46712a9..48f94d0 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -239,6 +239,9 @@
      * methods of activities and other components are called.  Note that you
      * <em>must</em> be sure to use {@link #unregisterComponentCallbacks} when
      * appropriate in the future; this will not be removed for you.
+     *
+     * @param callback The interface to call.  This can be either a
+     * {@link ComponentCallbacks} or {@link ComponentCallbacks2} interface.
      */
     public void registerComponentCallbacks(ComponentCallbacks callback) {
         getApplicationContext().registerComponentCallbacks(callback);
diff --git a/core/java/android/content/SyncManager.java b/core/java/android/content/SyncManager.java
index ef6e131..d4ed4b9 100644
--- a/core/java/android/content/SyncManager.java
+++ b/core/java/android/content/SyncManager.java
@@ -192,10 +192,10 @@
     private static final long SYNC_ALARM_TIMEOUT_MAX = 2 * 60 * 60 * 1000; // two hours
 
     /**
-     * The amount of time to wait after attempting a bind before canceling a sync and disabling
-     * the sync adapter
+     * The amount of time (in milliseconds) to wait after attempting a bind
+     * before canceling a sync and disabling the sync adapter
      */
-    public static final long BIND_TIMEOUT_MS = 30 * 1000;
+    public static final long BIND_TIMEOUT_MS = 5 * 60 * 1000;
 
     public void onAccountsUpdated(Account[] accounts) {
         // remember if this was the first time this was called after an update
diff --git a/core/java/android/provider/ContactsContract.java b/core/java/android/provider/ContactsContract.java
index 1f2b342..ca1d0d9 100644
--- a/core/java/android/provider/ContactsContract.java
+++ b/core/java/android/provider/ContactsContract.java
@@ -34,6 +34,7 @@
 import android.database.DatabaseUtils;
 import android.graphics.Rect;
 import android.net.Uri;
+import android.os.Bundle;
 import android.os.RemoteException;
 import android.text.TextUtils;
 import android.util.DisplayMetrics;
@@ -44,6 +45,9 @@
 import java.io.IOException;
 import java.io.InputStream;
 import java.util.ArrayList;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
 
 /**
  * <p>
@@ -167,6 +171,22 @@
     public static final String STREQUENT_PHONE_ONLY = "strequent_phone_only";
 
     /**
+     * A key to a boolean in the "extras" bundle of the cursor.
+     * The boolean indicates that the provider did not create a snippet and that the client asking
+     * for the snippet should do it (true means the snippeting was deferred to the client).
+     *
+     * @hide
+     */
+    public static final String DEFERRED_SNIPPETING = "deferred_snippeting";
+
+    /**
+     * Key to retrieve the original query on the client side.
+     *
+     * @hide
+     */
+    public static final String DEFERRED_SNIPPETING_QUERY = "deferred_snippeting_query";
+
+    /**
      * @hide
      */
     public static final class Preferences {
@@ -4357,6 +4377,12 @@
                 Uri.withAppendedPath(AUTHORITY_URI, "raw_contact_entities");
 
         /**
+         * The content:// style URI for this table, specific to the user's profile.
+         */
+        public static final Uri PROFILE_CONTENT_URI =
+                Uri.withAppendedPath(Profile.CONTENT_URI, "raw_contact_entities");
+
+        /**
          * The MIME type of {@link #CONTENT_URI} providing a directory of raw contact entities.
          */
         public static final String CONTENT_TYPE = "vnd.android.cursor.dir/raw_contact_entity";
@@ -4857,6 +4883,19 @@
          * @hide
          */
         public static final String SNIPPET_ARGS_PARAM_KEY = "snippet_args";
+
+        /**
+         * A key to ask the provider to defer the snippeting to the client if possible.
+         * Value of 1 implies true, 0 implies false when 0 is the default.
+         * When a cursor is returned to the client, it should check for an extra with the name
+         * {@link ContactsContract#DEFERRED_SNIPPETING} in the cursor. If it exists, the client
+         * should do its own snippeting using {@link ContactsContract#snippetize}. If
+         * it doesn't exist, the snippet column in the cursor should already contain a snippetized
+         * string.
+         *
+         * @hide
+         */
+        public static final String DEFERRED_SNIPPETING_KEY = "deferred_snippeting";
     }
 
     /**
@@ -7053,6 +7092,18 @@
         public static final String ACCOUNT_TYPE = "account_type";
 
         /**
+         * The data set within the account that this row belongs to.  This allows
+         * multiple sync adapters for the same account type to distinguish between
+         * each others' data.
+         *
+         * This is empty by default, and is completely optional.  It only needs to
+         * be populated if multiple sync adapters are entering distinct data for
+         * the same account type and account name.
+         * <P>Type: TEXT</P>
+         */
+        public static final String DATA_SET = "data_set";
+
+        /**
          * Depending on the mode defined by the sync-adapter, this flag controls
          * the top-level sync behavior for this data source.
          * <p>
@@ -8054,4 +8105,138 @@
             public static final String DATA_SET = "com.android.contacts.extra.DATA_SET";
         }
     }
+
+    /**
+     * Creates a snippet out of the given content that matches the given query.
+     * @param content - The content to use to compute the snippet.
+     * @param displayName - Display name for the contact - if this already contains the search
+     *        content, no snippet should be shown.
+     * @param query - String to search for in the content.
+     * @param snippetStartMatch - Marks the start of the matching string in the snippet.
+     * @param snippetEndMatch - Marks the end of the matching string in the snippet.
+     * @param snippetEllipsis - Ellipsis string appended to the end of the snippet (if too long).
+     * @param snippetMaxTokens - Maximum number of words from the snippet that will be displayed.
+     * @return The computed snippet, or null if the snippet could not be computed or should not be
+     *         shown.
+     *
+     *  @hide
+     */
+    public static String snippetize(String content, String displayName, String query,
+            char snippetStartMatch, char snippetEndMatch, String snippetEllipsis,
+            int snippetMaxTokens) {
+
+        String lowerQuery = query != null ? query.toLowerCase() : null;
+        if (TextUtils.isEmpty(content) || TextUtils.isEmpty(query) ||
+                TextUtils.isEmpty(displayName) || !content.toLowerCase().contains(lowerQuery)) {
+            return null;
+        }
+
+        // If the display name already contains the query term, return empty - snippets should
+        // not be needed in that case.
+        String lowerDisplayName = displayName != null ? displayName.toLowerCase() : "";
+        List<String> nameTokens = new ArrayList<String>();
+        List<Integer> nameTokenOffsets = new ArrayList<Integer>();
+        split(lowerDisplayName.trim(), nameTokens, nameTokenOffsets);
+        for (String nameToken : nameTokens) {
+            if (nameToken.startsWith(lowerQuery)) {
+                return null;
+            }
+        }
+
+        String[] contentLines = content.split("\n");
+
+        // Locate the lines of the content that contain the query term.
+        for (String contentLine : contentLines) {
+            if (contentLine.toLowerCase().contains(lowerQuery)) {
+
+                // Line contains the query string - now search for it at the start of tokens.
+                List<String> lineTokens = new ArrayList<String>();
+                List<Integer> tokenOffsets = new ArrayList<Integer>();
+                split(contentLine.trim(), lineTokens, tokenOffsets);
+
+                // As we find matches against the query, we'll populate this list with the marked
+                // (or unchanged) tokens.
+                List<String> markedTokens = new ArrayList<String>();
+
+                int firstToken = -1;
+                int lastToken = -1;
+                for (int i = 0; i < lineTokens.size(); i++) {
+                    String token = lineTokens.get(i);
+                    String lowerToken = token.toLowerCase();
+                    if (lowerToken.startsWith(lowerQuery)) {
+
+                        // Query term matched; surround the token with match markers.
+                        markedTokens.add(snippetStartMatch + token + snippetEndMatch);
+
+                        // If this is the first token found with a match, mark the token
+                        // positions to use for assembling the snippet.
+                        if (firstToken == -1) {
+                            firstToken =
+                                    Math.max(0, i - (int) Math.floor(
+                                            Math.abs(snippetMaxTokens)
+                                            / 2.0));
+                            lastToken =
+                                    Math.min(lineTokens.size(), firstToken +
+                                            Math.abs(snippetMaxTokens));
+                        }
+                    } else {
+                        markedTokens.add(token);
+                    }
+                }
+
+                // Assemble the snippet by piecing the tokens back together.
+                if (firstToken > -1) {
+                    StringBuilder sb = new StringBuilder();
+                    if (firstToken > 0) {
+                        sb.append(snippetEllipsis);
+                    }
+                    for (int i = firstToken; i < lastToken; i++) {
+                        String markedToken = markedTokens.get(i);
+                        String originalToken = lineTokens.get(i);
+                        sb.append(markedToken);
+                        if (i < lastToken - 1) {
+                            // Add the characters that appeared between this token and the next.
+                            sb.append(contentLine.substring(
+                                    tokenOffsets.get(i) + originalToken.length(),
+                                    tokenOffsets.get(i + 1)));
+                        }
+                    }
+                    if (lastToken < lineTokens.size()) {
+                        sb.append(snippetEllipsis);
+                    }
+                    return sb.toString();
+                }
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Pattern for splitting a line into tokens.  This matches e-mail addresses as a single token,
+     * otherwise splitting on any group of non-alphanumeric characters.
+     *
+     * @hide
+     */
+    private static Pattern SPLIT_PATTERN =
+        Pattern.compile("([\\w-\\.]+)@((?:[\\w]+\\.)+)([a-zA-Z]{2,4})|[\\w]+");
+
+    /**
+     * Helper method for splitting a string into tokens.  The lists passed in are populated with the
+     * tokens and offsets into the content of each token.  The tokenization function parses e-mail
+     * addresses as a single token; otherwise it splits on any non-alphanumeric character.
+     * @param content Content to split.
+     * @param tokens List of token strings to populate.
+     * @param offsets List of offsets into the content for each token returned.
+     *
+     * @hide
+     */
+    private static void split(String content, List<String> tokens, List<Integer> offsets) {
+        Matcher matcher = SPLIT_PATTERN.matcher(content);
+        while (matcher.find()) {
+            tokens.add(matcher.group());
+            offsets.add(matcher.start());
+        }
+    }
+
+
 }
diff --git a/core/java/android/server/BluetoothHealthProfileHandler.java b/core/java/android/server/BluetoothHealthProfileHandler.java
index 51c995e..a6ada2b 100644
--- a/core/java/android/server/BluetoothHealthProfileHandler.java
+++ b/core/java/android/server/BluetoothHealthProfileHandler.java
@@ -29,6 +29,8 @@
 import android.os.RemoteException;
 import android.util.Log;
 
+import java.io.FileDescriptor;
+import java.io.IOException;
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
@@ -47,7 +49,6 @@
     private static final boolean DBG = true;
 
     private static BluetoothHealthProfileHandler sInstance;
-    private Context mContext;
     private BluetoothService mBluetoothService;
     private ArrayList<HealthChannel> mHealthChannels;
     private HashMap <BluetoothHealthAppConfiguration, String> mHealthAppConfigs;
@@ -76,6 +77,17 @@
              mConfig = config;
              mState = BluetoothHealth.STATE_CHANNEL_DISCONNECTED;
         }
+
+        @Override
+        public int hashCode() {
+            int result = 17;
+            result = 31 * result + (mChannelPath == null ? 0 : mChannelPath.hashCode());
+            result = 31 * result + mDevice.hashCode();
+            result = 31 * result + mConfig.hashCode();
+            result = 31 * result + mState;
+            result = 31 * result + mChannelType;
+            return result;
+        }
     }
 
     private final Handler mHandler = new Handler() {
@@ -98,28 +110,38 @@
                 }
 
                 if (path == null) {
-                    mCallbacks.remove(registerApp);
                     callHealthApplicationStatusCallback(registerApp,
-                            BluetoothHealth.APPLICATION_REGISTRATION_FAILURE);
+                            BluetoothHealth.APP_CONFIG_REGISTRATION_FAILURE);
+                    mCallbacks.remove(registerApp);
                 } else {
                     mHealthAppConfigs.put(registerApp, path);
                     callHealthApplicationStatusCallback(registerApp,
-                            BluetoothHealth.APPLICATION_REGISTRATION_SUCCESS);
+                            BluetoothHealth.APP_CONFIG_REGISTRATION_SUCCESS);
                 }
 
                 break;
             case MESSAGE_UNREGISTER_APPLICATION:
                 BluetoothHealthAppConfiguration unregisterApp =
                     (BluetoothHealthAppConfiguration) msg.obj;
+
+                // Disconnect all the channels
+                for (HealthChannel chan : mHealthChannels) {
+                    if (chan.mConfig.equals(unregisterApp) &&
+                            chan.mState != BluetoothHealth.STATE_CHANNEL_DISCONNECTED) {
+                        disconnectChannel(chan.mDevice, unregisterApp, chan.hashCode());
+                    }
+                }
+
                 boolean result = mBluetoothService.unregisterHealthApplicationNative(
                         mHealthAppConfigs.get(unregisterApp));
                 if (result) {
-                    mCallbacks.remove(unregisterApp);
                     callHealthApplicationStatusCallback(unregisterApp,
-                            BluetoothHealth.APPLICATION_UNREGISTRATION_SUCCESS);
+                            BluetoothHealth.APP_CONFIG_UNREGISTRATION_SUCCESS);
+                    mCallbacks.remove(unregisterApp);
+                    mHealthAppConfigs.remove(unregisterApp);
                 } else {
                     callHealthApplicationStatusCallback(unregisterApp,
-                            BluetoothHealth.APPLICATION_UNREGISTRATION_FAILURE);
+                            BluetoothHealth.APP_CONFIG_UNREGISTRATION_FAILURE);
                 }
                 break;
             case MESSAGE_CONNECT_CHANNEL:
@@ -133,7 +155,8 @@
                           channelType)) {
                     int prevState = chan.mState;
                     int state = BluetoothHealth.STATE_CHANNEL_DISCONNECTED;
-                    callHealthChannelCallback(chan.mConfig, chan.mDevice, prevState, state, null);
+                    callHealthChannelCallback(chan.mConfig, chan.mDevice, prevState, state, null,
+                            chan.hashCode());
                     mHealthChannels.remove(chan);
                 }
             }
@@ -141,7 +164,6 @@
     };
 
     private BluetoothHealthProfileHandler(Context context, BluetoothService service) {
-        mContext = context;
         mBluetoothService = service;
         mHealthAppConfigs = new HashMap<BluetoothHealthAppConfiguration, String>();
         mHealthChannels = new ArrayList<HealthChannel>();
@@ -205,7 +227,7 @@
 
         int prevState = BluetoothHealth.STATE_CHANNEL_DISCONNECTED;
         int state = BluetoothHealth.STATE_CHANNEL_CONNECTING;
-        callHealthChannelCallback(config, device, prevState, state, null);
+        callHealthChannelCallback(config, device, prevState, state, null, chan.hashCode());
 
         Message msg = mHandler.obtainMessage(MESSAGE_CONNECT_CHANNEL);
         msg.obj = chan;
@@ -235,37 +257,44 @@
     }
 
     boolean disconnectChannel(BluetoothDevice device,
-            BluetoothHealthAppConfiguration config, ParcelFileDescriptor fd) {
-        HealthChannel chan = findChannelByFd(device, config, fd);
-        if (chan == null) return false;
+            BluetoothHealthAppConfiguration config, int id) {
+        HealthChannel chan = findChannelById(device, config, id);
+        if (chan == null) {
+          return false;
+        }
 
         String deviceObjectPath =
                 mBluetoothService.getObjectPathFromAddress(device.getAddress());
-        if (mBluetoothService.destroyChannelNative(deviceObjectPath, chan.mChannelPath)) {
-            int prevState = chan.mState;
-            chan.mState = BluetoothHealth.STATE_CHANNEL_DISCONNECTING;
+
+        mBluetoothService.releaseChannelFdNative(chan.mChannelPath);
+
+        int prevState = chan.mState;
+        chan.mState = BluetoothHealth.STATE_CHANNEL_DISCONNECTING;
+        callHealthChannelCallback(config, device, prevState, chan.mState,
+                null, chan.hashCode());
+
+        if (!mBluetoothService.destroyChannelNative(deviceObjectPath, chan.mChannelPath)) {
+            prevState = chan.mState;
+            chan.mState = BluetoothHealth.STATE_CHANNEL_CONNECTED;
             callHealthChannelCallback(config, device, prevState, chan.mState,
-                    chan.mChannelFd);
-            return true;
-        } else {
+                    chan.mChannelFd, chan.hashCode());
             return false;
+        } else {
+            return true;
         }
     }
 
-    private HealthChannel findChannelByFd(BluetoothDevice device,
-            BluetoothHealthAppConfiguration config, ParcelFileDescriptor fd) {
+    private HealthChannel findChannelById(BluetoothDevice device,
+            BluetoothHealthAppConfiguration config, int id) {
         for (HealthChannel chan : mHealthChannels) {
-            if (chan.mChannelFd.equals(fd) && chan.mDevice.equals(device) &&
-                    chan.mConfig.equals(config)) return chan;
+            if (chan.hashCode() == id) return chan;
         }
         return null;
     }
 
-    private HealthChannel findChannelByPath(BluetoothDevice device,
-            BluetoothHealthAppConfiguration config, String path) {
+    private HealthChannel findChannelByPath(BluetoothDevice device, String path) {
         for (HealthChannel chan : mHealthChannels) {
-            if (chan.mChannelPath.equals(path) && chan.mDevice.equals(device) &&
-                    chan.mConfig.equals(config)) return chan;
+            if (path.equals(chan.mChannelPath) && device.equals(chan.mDevice)) return chan;
         }
         return null;
     }
@@ -296,7 +325,15 @@
     ParcelFileDescriptor getMainChannelFd(BluetoothDevice device,
             BluetoothHealthAppConfiguration config) {
         HealthChannel chan = getMainChannel(device, config);
-        if (chan != null) return chan.mChannelFd;
+        if (chan != null) {
+            ParcelFileDescriptor pfd =  null;
+            try {
+                pfd = chan.mChannelFd.dup();
+                return pfd;
+            } catch (IOException e) {
+                return null;
+            }
+        }
 
         String objectPath =
                 mBluetoothService.getObjectPathFromAddress(device.getAddress());
@@ -308,14 +345,18 @@
         // We had no record of the main channel but querying Bluez we got a
         // main channel. We might not have received the PropertyChanged yet for
         // the main channel creation so update our data structure here.
-        chan = findChannelByPath(device, config, mainChannelPath);
+        chan = findChannelByPath(device, mainChannelPath);
         if (chan == null) {
             errorLog("Main Channel present but we don't have any account of it:" +
                     device +":" + config);
             return null;
         }
         chan.mMainChannel = true;
-        return chan.mChannelFd;
+        try {
+            return chan.mChannelFd.dup();
+        } catch (IOException e) {
+            return null;
+        }
     }
 
     /*package*/ void onHealthDevicePropertyChanged(String devicePath,
@@ -334,7 +375,7 @@
         BluetoothHealthAppConfiguration config = findHealthApplication(device,
                 channelPath);
         if (config != null) {
-            HealthChannel chan = findChannelByPath(device, config, channelPath);
+            HealthChannel chan = findChannelByPath(device, channelPath);
             if (chan == null) {
                 errorLog("Health Channel is not present:" + channelPath);
             } else {
@@ -346,21 +387,22 @@
     private BluetoothHealthAppConfiguration findHealthApplication(
             BluetoothDevice device, String channelPath) {
         BluetoothHealthAppConfiguration config = null;
-        String configPath = mBluetoothService.getChannelApplicationNative(channelPath);
+        HealthChannel chan = findChannelByPath(device, channelPath);
 
-        if (configPath == null) {
-            errorLog("No associated application for Health Channel:" + channelPath);
-            return null;
+        if (chan != null) {
+            config = chan.mConfig;
         } else {
-            for (Entry<BluetoothHealthAppConfiguration, String> e :
-                    mHealthAppConfigs.entrySet()) {
-                if (e.getValue().equals(configPath)) {
-                    config = e.getKey();
+            String configPath = mBluetoothService.getChannelApplicationNative(channelPath);
+            if (configPath == null) {
+                errorLog("Config path is null for application");
+            } else {
+                for (Entry<BluetoothHealthAppConfiguration, String> e :
+                        mHealthAppConfigs.entrySet()) {
+                    if (e.getValue().equals(configPath)) {
+                        config = e.getKey();
+                    }
                 }
-            }
-            if (config == null) {
-                errorLog("No associated application for application path:" + configPath);
-                return null;
+                if (config == null) errorLog("No associated application for path:" + configPath);
             }
         }
         return config;
@@ -375,78 +417,83 @@
         if (address == null) return;
 
         BluetoothDevice device = adapter.getRemoteDevice(address);
-
-        BluetoothHealthAppConfiguration config = findHealthApplication(device,
-                channelPath);
+        BluetoothHealthAppConfiguration config;
         int state, prevState = BluetoothHealth.STATE_CHANNEL_DISCONNECTED;
         ParcelFileDescriptor fd;
         HealthChannel channel;
+        config = findHealthApplication(device, channelPath);
 
-        if (config != null) {
-             if (exists) {
-                 fd = mBluetoothService.getChannelFdNative(channelPath);
+        if (exists) {
+            fd = mBluetoothService.getChannelFdNative(channelPath);
+            if (fd == null) {
+                errorLog("Error obtaining fd for channel:" + channelPath);
+                return;
+            }
+            boolean mainChannel =
+                    getMainChannel(device, config) == null ? false : true;
+            if (!mainChannel) {
+                String mainChannelPath =
+                        mBluetoothService.getMainChannelNative(devicePath);
+                if (mainChannelPath == null) {
+                    errorLog("Main Channel Path is null for devicePath:" + devicePath);
+                    return;
+                }
+                if (mainChannelPath.equals(channelPath)) mainChannel = true;
+            }
+            channel = findConnectingChannel(device, config);
+            if (channel != null) {
+               channel.mChannelFd = fd;
+               channel.mMainChannel = mainChannel;
+               channel.mChannelPath = channelPath;
+               prevState = channel.mState;
+            } else {
+               channel = new HealthChannel(device, config, fd, mainChannel,
+                       channelPath);
+               mHealthChannels.add(channel);
+               prevState = BluetoothHealth.STATE_CHANNEL_DISCONNECTED;
+            }
+            state = BluetoothHealth.STATE_CHANNEL_CONNECTED;
+        } else {
+            channel = findChannelByPath(device, channelPath);
+            if (channel == null) {
+                errorLog("Channel not found:" + config + ":" + channelPath);
+                return;
+            }
+            mHealthChannels.remove(channel);
 
-                 if (fd == null) {
-                     errorLog("Error obtaining fd for channel:" + channelPath);
-                     return;
-                 }
-
-                 boolean mainChannel =
-                         getMainChannel(device, config) == null ? false : true;
-                 if (!mainChannel) {
-                     String mainChannelPath =
-                             mBluetoothService.getMainChannelNative(devicePath);
-                     if (mainChannelPath == null) {
-                         errorLog("Main Channel Path is null for devicePath:" + devicePath);
-                         return;
-                     }
-                     if (mainChannelPath.equals(channelPath)) mainChannel = true;
-                 }
-
-                 channel = findConnectingChannel(device, config);
-                 if (channel != null) {
-                    channel.mChannelFd = fd;
-                    channel.mMainChannel = mainChannel;
-                    channel.mChannelPath = channelPath;
-                    prevState = channel.mState;
-                 } else {
-                    channel = new HealthChannel(device, config, fd, mainChannel,
-                            channelPath);
-                    mHealthChannels.add(channel);
-                    prevState = BluetoothHealth.STATE_CHANNEL_DISCONNECTED;
-                 }
-                 state = BluetoothHealth.STATE_CHANNEL_CONNECTED;
-             } else {
-                 channel = findChannelByPath(device, config, channelPath);
-                 if (channel == null) {
-                     errorLog("Channel not found:" + config + ":" + channelPath);
-                     return;
-                 }
-
-                 fd = channel.mChannelFd;
-                 // CLOSE FD
-                 mBluetoothService.releaseChannelFdNative(channel.mChannelPath);
-                 mHealthChannels.remove(channel);
-
-                 prevState = channel.mState;
-                 state = BluetoothHealth.STATE_CHANNEL_DISCONNECTED;
-             }
-             channel.mState = state;
-             callHealthChannelCallback(config, device, prevState, state, fd);
+            channel.mChannelFd = null;
+            prevState = channel.mState;
+            state = BluetoothHealth.STATE_CHANNEL_DISCONNECTED;
         }
+        channel.mState = state;
+        callHealthChannelCallback(config, device, prevState, state, channel.mChannelFd,
+                channel.hashCode());
     }
 
     private void callHealthChannelCallback(BluetoothHealthAppConfiguration config,
-            BluetoothDevice device, int prevState, int state, ParcelFileDescriptor fd) {
+            BluetoothDevice device, int prevState, int state, ParcelFileDescriptor fd, int id) {
         broadcastHealthDeviceStateChange(device, prevState, state);
 
         debugLog("Health Device Callback: " + device + " State Change: "
                 + prevState + "->" + state);
+
+        ParcelFileDescriptor dupedFd = null;
+        if (fd != null) {
+            try {
+                dupedFd = fd.dup();
+            } catch (IOException e) {
+                dupedFd = null;
+                errorLog("Exception while duping: " + e);
+            }
+        }
+
         IBluetoothHealthCallback callback = mCallbacks.get(config);
         if (callback != null) {
             try {
-                callback.onHealthChannelStateChange(config, device, prevState, state, fd);
-            } catch (RemoteException e) {}
+                callback.onHealthChannelStateChange(config, device, prevState, state, dupedFd, id);
+            } catch (RemoteException e) {
+                errorLog("Remote Exception:" + e);
+            }
         }
     }
 
@@ -458,7 +505,9 @@
         if (callback != null) {
             try {
                 callback.onHealthAppConfigurationStatusChange(config, status);
-            } catch (RemoteException e) {}
+            } catch (RemoteException e) {
+                errorLog("Remote Exception:" + e);
+            }
         }
     }
 
diff --git a/core/java/android/server/BluetoothService.java b/core/java/android/server/BluetoothService.java
index 55a0624..95474fe 100755
--- a/core/java/android/server/BluetoothService.java
+++ b/core/java/android/server/BluetoothService.java
@@ -2243,11 +2243,11 @@
     }
 
     public boolean disconnectChannel(BluetoothDevice device,
-            BluetoothHealthAppConfiguration config, ParcelFileDescriptor fd) {
+            BluetoothHealthAppConfiguration config, int id) {
         mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM,
                 "Need BLUETOOTH permission");
         synchronized (mBluetoothHealthProfileHandler) {
-            return mBluetoothHealthProfileHandler.disconnectChannel(device, config, fd);
+            return mBluetoothHealthProfileHandler.disconnectChannel(device, config, id);
         }
     }
 
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index fd60813f..4a9c5bd 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -9995,6 +9995,7 @@
             }
 
             final HardwareCanvas canvas = mDisplayList.start();
+            int restoreCount = 0;
             try {
                 int width = mRight - mLeft;
                 int height = mBottom - mTop;
@@ -10004,6 +10005,8 @@
                 canvas.onPreDraw(null);
 
                 computeScroll();
+
+                restoreCount = canvas.save();
                 canvas.translate(-mScrollX, -mScrollY);
                 mPrivateFlags |= DRAWN | DRAWING_CACHE_VALID;
                 mPrivateFlags &= ~DIRTY_MASK;
@@ -10015,6 +10018,7 @@
                     draw(canvas);
                 }
             } finally {
+                canvas.restoreToCount(restoreCount);
                 canvas.onPostDraw();
 
                 mDisplayList.end();
diff --git a/core/java/android/widget/FrameLayout.java b/core/java/android/widget/FrameLayout.java
index 0b0b812..398a7eb 100644
--- a/core/java/android/widget/FrameLayout.java
+++ b/core/java/android/widget/FrameLayout.java
@@ -465,23 +465,42 @@
     }
 
     /**
-     * Determines whether to measure all children or just those in 
-     * the VISIBLE or INVISIBLE state when measuring. Defaults to false.
+     * Sets whether to consider all children, or just those in
+     * the VISIBLE or INVISIBLE state, when measuring. Defaults to false.
+     *
      * @param measureAll true to consider children marked GONE, false otherwise.
      * Default value is false.
-     * 
+     *
      * @attr ref android.R.styleable#FrameLayout_measureAllChildren
      */
     @android.view.RemotableViewMethod
     public void setMeasureAllChildren(boolean measureAll) {
         mMeasureAllChildren = measureAll;
     }
-    
+
     /**
-     * Determines whether to measure all children or just those in 
-     * the VISIBLE or INVISIBLE state when measuring. 
+     * Determines whether all children, or just those in the VISIBLE or
+     * INVISIBLE state, are considered when measuring.
+     *
+     * @return Whether all children are considered when measuring.
+     *
+     * @deprecated This method is deprecated in favor of
+     * {@link #getMeasureAllChildren() getMeasureAllChildren()}, which was
+     * renamed for consistency with
+     * {@link #setMeasureAllChildren(boolean) setMeasureAllChildren()}.
      */
+    @Deprecated
     public boolean getConsiderGoneChildrenWhenMeasuring() {
+        return getMeasureAllChildren();
+    }
+
+    /**
+     * Determines whether all children, or just those in the VISIBLE or
+     * INVISIBLE state, are considered when measuring.
+     *
+     * @return Whether all children are considered when measuring.
+     */
+    public boolean getMeasureAllChildren() {
         return mMeasureAllChildren;
     }
 
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index d88999b..c61aad1 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -5746,7 +5746,7 @@
             MetaKeyKeyListener.stopSelecting(this, sp);
         }
     }
-    
+
     /**
      * @hide
      */
@@ -5754,10 +5754,12 @@
         if (mInputMethodState != null) {
             mInputMethodState.mExtracting = req;
         }
-        // This stops a possible text selection mode. Maybe not intended.
+        // This would stop a possible selection mode, but no such mode is started in case
+        // extracted mode will start. Some text is selected though, and will trigger an action mode
+        // in the extracted view.
         hideControllers();
     }
-    
+
     /**
      * Called by the framework in response to a text completion from
      * the current input method, provided by it calling
@@ -9226,21 +9228,23 @@
 
     @Override
     public boolean performLongClick() {
+        boolean handled = false;
+        boolean vibrate = true;
+
         if (super.performLongClick()) {
             mDiscardNextActionUp = true;
-            return true;
+            handled = true;
         }
 
-        boolean handled = false;
-
         // Long press in empty space moves cursor and shows the Paste affordance if available.
-        if (!isPositionOnText(mLastDownPositionX, mLastDownPositionY) &&
+        if (!handled && !isPositionOnText(mLastDownPositionX, mLastDownPositionY) &&
                 mInsertionControllerEnabled) {
             final int offset = getOffsetForPosition(mLastDownPositionX, mLastDownPositionY);
             stopSelectionActionMode();
             Selection.setSelection((Spannable) mText, offset);
             getInsertionController().showWithActionPopup();
             handled = true;
+            vibrate = false;
         }
 
         if (!handled && mSelectionActionMode != null) {
@@ -9262,10 +9266,15 @@
         }
 
         // Start a new selection
-        handled |= !handled && startSelectionActionMode();
+        if (!handled) {
+            handled = startSelectionActionMode();
+        }
+
+        if (vibrate) {
+            performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
+        }
 
         if (handled) {
-            performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
             mDiscardNextActionUp = true;
         }
 
@@ -10013,14 +10022,22 @@
             }
         }
 
-        ActionMode.Callback actionModeCallback = new SelectionActionModeCallback();
-        mSelectionActionMode = startActionMode(actionModeCallback);
-        final boolean selectionStarted = mSelectionActionMode != null;
+        final InputMethodManager imm = InputMethodManager.peekInstance();
+        boolean extractedTextModeWillBeStartedFullScreen = !(this instanceof ExtractEditText) &&
+                imm != null && imm.isFullscreenMode();
 
-        if (selectionStarted && !mTextIsSelectable) {
+        // Do not start the action mode when extracted text will show up full screen, thus
+        // immediately hiding the newly created action bar, which would be visually distracting.
+        if (!extractedTextModeWillBeStartedFullScreen) {
+            ActionMode.Callback actionModeCallback = new SelectionActionModeCallback();
+            mSelectionActionMode = startActionMode(actionModeCallback);
+        }
+        final boolean selectionStarted = mSelectionActionMode != null ||
+                extractedTextModeWillBeStartedFullScreen;
+
+        if (selectionStarted && !mTextIsSelectable && imm != null) {
             // Show the IME to be able to replace text, except when selecting non editable text.
-            final InputMethodManager imm = InputMethodManager.peekInstance();
-            if (imm != null) imm.showSoftInput(this, 0, null);
+            imm.showSoftInput(this, 0, null);
         }
 
         return selectionStarted;
@@ -11339,7 +11356,7 @@
     private final TextPaint         mTextPaint;
     private boolean                 mUserSetTextScaleX;
     private final Paint             mHighlightPaint;
-    private int                     mHighlightColor = 0x4C33B5E5;
+    private int                     mHighlightColor = 0x6633B5E5;
     /**
      * This is temporarily visible to fix bug 3085564 in webView. Do not rely on
      * this field being protected. Will be restored as private when lineHeight
diff --git a/core/java/com/android/internal/app/ResolverActivity.java b/core/java/com/android/internal/app/ResolverActivity.java
index ba2f5d4..3fba1be 100644
--- a/core/java/com/android/internal/app/ResolverActivity.java
+++ b/core/java/com/android/internal/app/ResolverActivity.java
@@ -58,9 +58,20 @@
     private TextView mClearDefaultHint;
     private PackageManager mPm;
 
+    private Intent makeMyIntent() {
+        Intent intent = new Intent(getIntent());
+        // The resolver activity is set to be hidden from recent tasks.
+        // we don't want this attribute to be propagated to the next activity
+        // being launched.  Note that if the original Intent also had this
+        // flag set, we are now losing it.  That should be a very rare case
+        // and we can live with this.
+        intent.setFlags(intent.getFlags()&~Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
+        return intent;
+    }
+
     @Override
     protected void onCreate(Bundle savedInstanceState) {
-        onCreate(savedInstanceState, new Intent(getIntent()),
+        onCreate(savedInstanceState, makeMyIntent(),
                 getResources().getText(com.android.internal.R.string.whichApplication),
                 null, null, true);
     }
diff --git a/core/java/com/android/internal/view/menu/ListMenuPresenter.java b/core/java/com/android/internal/view/menu/ListMenuPresenter.java
index 146c7ac..e6538b0 100644
--- a/core/java/com/android/internal/view/menu/ListMenuPresenter.java
+++ b/core/java/com/android/internal/view/menu/ListMenuPresenter.java
@@ -34,6 +34,8 @@
  * MenuPresenter for list-style menus.
  */
 public class ListMenuPresenter implements MenuPresenter, AdapterView.OnItemClickListener {
+    private static final String TAG = "ListMenuPresenter";
+
     Context mContext;
     LayoutInflater mInflater;
     MenuBuilder mMenu;
@@ -76,7 +78,7 @@
     public void initForMenu(Context context, MenuBuilder menu) {
         if (mThemeRes != 0) {
             mContext = new ContextThemeWrapper(context, mThemeRes);
-        } else if (mContext == null) {
+        } else if (mContext != null) {
             mContext = context;
         }
         mInflater = LayoutInflater.from(mContext);
diff --git a/core/java/com/android/internal/widget/ScrollingTabContainerView.java b/core/java/com/android/internal/widget/ScrollingTabContainerView.java
index 5baed75..b7bc366 100644
--- a/core/java/com/android/internal/widget/ScrollingTabContainerView.java
+++ b/core/java/com/android/internal/widget/ScrollingTabContainerView.java
@@ -444,7 +444,9 @@
                     mTextView.setText(null);
                 }
 
-                setContentDescription(tab.getContentDescription());
+                if (mIconView != null) {
+                    mIconView.setContentDescription(tab.getContentDescription());
+                }
             }
         }
 
diff --git a/core/jni/android_server_BluetoothService.cpp b/core/jni/android_server_BluetoothService.cpp
index 819449a..292047b 100644
--- a/core/jni/android_server_BluetoothService.cpp
+++ b/core/jni/android_server_BluetoothService.cpp
@@ -1659,6 +1659,7 @@
         if (fileDesc == NULL) {
             // FileDescriptor constructor has thrown an exception
             releaseChannelFdNative(env, object, channelPath);
+            close(fd);
             return NULL;
         }
 
@@ -1667,7 +1668,7 @@
         if (parcelFileDesc == NULL) {
             // ParcelFileDescriptor constructor has thrown an exception
             releaseChannelFdNative(env, object, channelPath);
-            LOGE("---Parcel File Desc is null");
+            close(fd);
             return NULL;
         }
 
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 16490da..72863a2 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -1499,19 +1499,23 @@
                 android:theme="@style/Theme.Holo.Dialog"
                 android:label="@string/heavy_weight_switcher_title"
                 android:finishOnCloseSystemDialogs="true"
-                android:excludeFromRecents="true">
+                android:excludeFromRecents="true"
+                android:process=":ui">
         </activity>
         <activity android:name="com.android.internal.app.PlatLogoActivity"
-                android:theme="@style/Theme.Wallpaper.NoTitleBar.Fullscreen">
+                android:theme="@style/Theme.Wallpaper.NoTitleBar.Fullscreen"
+                android:process=":ui">
         </activity>
         <activity android:name="com.android.internal.app.DisableCarModeActivity"
                 android:theme="@style/Theme.NoDisplay"
-                android:excludeFromRecents="true">
+                android:excludeFromRecents="true"
+                android:process=":ui">
         </activity>
         <activity android:name="com.android.internal.app.RingtonePickerActivity"
                 android:theme="@style/Theme.Holo.Dialog.Alert"
                 android:excludeFromRecents="true"
-                android:multiprocess="true">
+                android:multiprocess="true"
+                android:process=":ui">
             <intent-filter>
                 <action android:name="android.intent.action.RINGTONE_PICKER" />
                 <category android:name="android.intent.category.DEFAULT" />
@@ -1522,18 +1526,21 @@
                 android:excludeFromRecents="true"
                 android:exported="true"
                 android:theme="@android:style/Theme.Holo.Dialog"
-                android:label="@string/choose_account_label">
+                android:label="@string/choose_account_label"
+                android:process=":ui">
         </activity>
 
         <activity android:name="android.accounts.GrantCredentialsPermissionActivity"
                 android:excludeFromRecents="true"
                 android:exported="true"
-                android:theme="@android:style/Theme.Holo.DialogWhenLarge">
+                android:theme="@android:style/Theme.Holo.DialogWhenLarge"
+                android:process=":ui">
         </activity>
 
         <activity android:name="android.content.SyncActivityTooManyDeletes"
                android:theme="@android:style/Theme.Holo.Dialog"
-               android:label="@string/sync_too_many_deletes">
+               android:label="@string/sync_too_many_deletes"
+               android:process=":ui">
         </activity>
 
         <activity android:name="com.android.server.ShutdownActivity"
@@ -1551,7 +1558,8 @@
 
         <activity android:name="com.android.internal.app.NetInitiatedActivity"
                 android:theme="@style/Theme.Holo.Dialog.Alert"
-                android:excludeFromRecents="true">
+                android:excludeFromRecents="true"
+                android:process=":ui">
         </activity>
 
         <receiver android:name="com.android.server.BootReceiver" >
diff --git a/core/res/res/values/themes.xml b/core/res/res/values/themes.xml
index f434ce8..6f98e02 100644
--- a/core/res/res/values/themes.xml
+++ b/core/res/res/values/themes.xml
@@ -878,8 +878,8 @@
         <item name="textColorSearchUrl">@android:color/search_url_text_holo</item>
         <item name="textColorHighlight">@android:color/highlighted_text_holo_dark</item>
         <item name="textColorHighlightInverse">@android:color/highlighted_text_holo_light</item>
-        <item name="textColorLink">@android:color/link_text_holo_dark</item>
-        <item name="textColorLinkInverse">@android:color/link_text_holo_light</item>
+        <item name="textColorLink">@android:color/holo_blue_light</item>
+        <item name="textColorLinkInverse">@android:color/holo_blue_light</item>
         <item name="textColorAlertDialogListItem">@android:color/primary_text_holo_dark</item>
 
         <item name="textAppearanceLarge">@android:style/TextAppearance.Holo.Large</item>
@@ -1182,8 +1182,8 @@
         <item name="textColorSearchUrl">@android:color/search_url_text_holo</item>
         <item name="textColorHighlight">@android:color/highlighted_text_holo_light</item>
         <item name="textColorHighlightInverse">@android:color/highlighted_text_holo_dark</item>
-        <item name="textColorLink">@android:color/link_text_holo_light</item>
-        <item name="textColorLinkInverse">@android:color/link_text_holo_dark</item>
+        <item name="textColorLink">@android:color/holo_blue_light</item>
+        <item name="textColorLinkInverse">@android:color/holo_blue_light</item>
         <item name="textColorAlertDialogListItem">@android:color/primary_text_holo_light</item>
 
         <item name="textAppearanceLarge">@android:style/TextAppearance.Holo.Light.Large</item>
diff --git a/libs/binder/IPCThreadState.cpp b/libs/binder/IPCThreadState.cpp
index 392193b..5ccf87f 100644
--- a/libs/binder/IPCThreadState.cpp
+++ b/libs/binder/IPCThreadState.cpp
@@ -78,12 +78,8 @@
 // conditionals don't get stripped...  but that is probably what we want.
 #if !LOG_NDEBUG
 static const char *kReturnStrings[] = {
-#if 1 /* TODO: error update strings */
-    "unknown",
-#else
+    "BR_ERROR",
     "BR_OK",
-    "BR_TIMEOUT",
-    "BR_WAKEUP",
     "BR_TRANSACTION",
     "BR_REPLY",
     "BR_ACQUIRE_RESULT",
@@ -94,25 +90,19 @@
     "BR_RELEASE",
     "BR_DECREFS",
     "BR_ATTEMPT_ACQUIRE",
-    "BR_EVENT_OCCURRED",
     "BR_NOOP",
     "BR_SPAWN_LOOPER",
     "BR_FINISHED",
     "BR_DEAD_BINDER",
-    "BR_CLEAR_DEATH_NOTIFICATION_DONE"
-#endif
+    "BR_CLEAR_DEATH_NOTIFICATION_DONE",
+    "BR_FAILED_REPLY"
 };
 
 static const char *kCommandStrings[] = {
-#if 1 /* TODO: error update strings */
-    "unknown",
-#else
-    "BC_NOOP",
     "BC_TRANSACTION",
     "BC_REPLY",
     "BC_ACQUIRE_RESULT",
     "BC_FREE_BUFFER",
-    "BC_TRANSACTION_COMPLETE",
     "BC_INCREFS",
     "BC_ACQUIRE",
     "BC_RELEASE",
@@ -120,18 +110,12 @@
     "BC_INCREFS_DONE",
     "BC_ACQUIRE_DONE",
     "BC_ATTEMPT_ACQUIRE",
-    "BC_RETRIEVE_ROOT_OBJECT",
-    "BC_SET_THREAD_ENTRY",
     "BC_REGISTER_LOOPER",
     "BC_ENTER_LOOPER",
     "BC_EXIT_LOOPER",
-    "BC_SYNC",
-    "BC_STOP_PROCESS",
-    "BC_STOP_SELF",
     "BC_REQUEST_DEATH_NOTIFICATION",
     "BC_CLEAR_DEATH_NOTIFICATION",
     "BC_DEAD_BINDER_DONE"
-#endif
 };
 
 static const char* getReturnString(size_t idx)
@@ -154,30 +138,36 @@
 {
     const binder_transaction_data* btd =
         (const binder_transaction_data*)data;
-    out << "target=" << btd->target.ptr << " (cookie " << btd->cookie << ")" << endl
+    if (btd->target.handle < 1024) {
+        /* want to print descriptors in decimal; guess based on value */
+        out << "target.desc=" << btd->target.handle;
+    } else {
+        out << "target.ptr=" << btd->target.ptr;
+    }
+    out << " (cookie " << btd->cookie << ")" << endl
         << "code=" << TypeCode(btd->code) << ", flags=" << (void*)btd->flags << endl
         << "data=" << btd->data.ptr.buffer << " (" << (void*)btd->data_size
         << " bytes)" << endl
         << "offsets=" << btd->data.ptr.offsets << " (" << (void*)btd->offsets_size
-        << " bytes)" << endl;
+        << " bytes)";
     return btd+1;
 }
 
 static const void* printReturnCommand(TextOutput& out, const void* _cmd)
 {
-    static const int32_t N = sizeof(kReturnStrings)/sizeof(kReturnStrings[0]);
-    
+    static const size_t N = sizeof(kReturnStrings)/sizeof(kReturnStrings[0]);
     const int32_t* cmd = (const int32_t*)_cmd;
     int32_t code = *cmd++;
-    if (code == BR_ERROR) {
+    size_t cmdIndex = code & 0xff;
+    if (code == (int32_t) BR_ERROR) {
         out << "BR_ERROR: " << (void*)(*cmd++) << endl;
         return cmd;
-    } else if (code < 0 || code >= N) {
+    } else if (cmdIndex >= N) {
         out << "Unknown reply: " << code << endl;
         return cmd;
     }
+    out << kReturnStrings[cmdIndex];
     
-    out << kReturnStrings[code];
     switch (code) {
         case BR_TRANSACTION:
         case BR_REPLY: {
@@ -213,6 +203,11 @@
             const int32_t c = *cmd++;
             out << ": death cookie " << (void*)c;
         } break;
+
+        default:
+            // no details to show for: BR_OK, BR_DEAD_REPLY,
+            // BR_TRANSACTION_COMPLETE, BR_FINISHED
+            break;
     }
     
     out << endl;
@@ -221,16 +216,17 @@
 
 static const void* printCommand(TextOutput& out, const void* _cmd)
 {
-    static const int32_t N = sizeof(kCommandStrings)/sizeof(kCommandStrings[0]);
-    
+    static const size_t N = sizeof(kCommandStrings)/sizeof(kCommandStrings[0]);
     const int32_t* cmd = (const int32_t*)_cmd;
     int32_t code = *cmd++;
-    if (code < 0 || code >= N) {
+    size_t cmdIndex = code & 0xff;
+
+    if (cmdIndex >= N) {
         out << "Unknown command: " << code << endl;
         return cmd;
     }
-    
-    out << kCommandStrings[code];
+    out << kCommandStrings[cmdIndex];
+
     switch (code) {
         case BC_TRANSACTION:
         case BC_REPLY: {
@@ -254,7 +250,7 @@
         case BC_RELEASE:
         case BC_DECREFS: {
             const int32_t d = *cmd++;
-            out << ": descriptor=" << (void*)d;
+            out << ": desc=" << d;
         } break;
     
         case BC_INCREFS_DONE:
@@ -267,7 +263,7 @@
         case BC_ATTEMPT_ACQUIRE: {
             const int32_t p = *cmd++;
             const int32_t d = *cmd++;
-            out << ": decriptor=" << (void*)d << ", pri=" << p;
+            out << ": desc=" << d << ", pri=" << p;
         } break;
         
         case BC_REQUEST_DEATH_NOTIFICATION:
@@ -281,6 +277,11 @@
             const int32_t c = *cmd++;
             out << ": death cookie " << (void*)c;
         } break;
+
+        default:
+            // no details to show for: BC_REGISTER_LOOPER, BC_ENTER_LOOPER,
+            // BC_EXIT_LOOPER
+            break;
     }
     
     out << endl;
@@ -592,6 +593,7 @@
 
 status_t IPCThreadState::attemptIncStrongHandle(int32_t handle)
 {
+    LOG_REMOTEREFS("IPCThreadState::attemptIncStrongHandle(%d)\n", handle);
     mOut.writeInt32(BC_ATTEMPT_ACQUIRE);
     mOut.writeInt32(0); // xxx was thread priority
     mOut.writeInt32(handle);
@@ -772,7 +774,7 @@
     } else {
         bwr.read_size = 0;
     }
-    
+
     IF_LOG_COMMANDS() {
         TextOutput::Bundle _b(alog);
         if (outAvail != 0) {
@@ -789,7 +791,7 @@
     
     // Return immediately if there is nothing to do.
     if ((bwr.write_size == 0) && (bwr.read_size == 0)) return NO_ERROR;
-    
+
     bwr.write_consumed = 0;
     bwr.read_consumed = 0;
     status_t err;
@@ -809,7 +811,7 @@
             alog << "Finished read/write, write size = " << mOut.dataSize() << endl;
         }
     } while (err == -EINTR);
-    
+
     IF_LOG_COMMANDS() {
         alog << "Our err: " << (void*)err << ", write consumed: "
             << bwr.write_consumed << " (of " << mOut.dataSize()
diff --git a/libs/utils/Static.cpp b/libs/utils/Static.cpp
index 4dfa578..ceca435 100644
--- a/libs/utils/Static.cpp
+++ b/libs/utils/Static.cpp
@@ -56,7 +56,9 @@
 protected:
     virtual status_t writeLines(const struct iovec& vec, size_t N)
     {
-        android_writevLog(&vec, N);
+        //android_writevLog(&vec, N);       <-- this is now a no-op
+        if (N != 1) LOGI("WARNING: writeLines N=%d\n", N);
+        LOGI("%.*s", vec.iov_len, (const char*) vec.iov_base);
         return NO_ERROR;
     }
 };
diff --git a/media/java/android/media/videoeditor/MediaArtistNativeHelper.java b/media/java/android/media/videoeditor/MediaArtistNativeHelper.java
index aa0a2e9..d7b8eaa 100644
--- a/media/java/android/media/videoeditor/MediaArtistNativeHelper.java
+++ b/media/java/android/media/videoeditor/MediaArtistNativeHelper.java
@@ -3758,65 +3758,33 @@
 
     /**
      * This method extracts a frame from the input file
-     * and returns the frame as a bitmap
-     *
-     * @param inputFile The inputFile
-     * @param width The width of the output frame
-     * @param height The height of the output frame
-     * @param timeMS The time in ms at which the frame has to be extracted
+     * and returns the frame as a bitmap. See getPixelsList() for more information.
      */
-    Bitmap getPixels(String inputFile, int width, int height, long timeMS) {
-        if (inputFile == null) {
-            throw new IllegalArgumentException("Invalid input file");
-        }
-
-        /* Make width and height as even */
-        final int newWidth = (width + 1) & 0xFFFFFFFE;
-        final int newHeight = (height + 1) & 0xFFFFFFFE;
-
-        /* Create a temp bitmap for resized thumbnails */
-        Bitmap tempBitmap = null;
-        if ((newWidth != width) || (newHeight != height)) {
-             tempBitmap = Bitmap.createBitmap(newWidth, newHeight, Bitmap.Config.ARGB_8888);
-        }
-
-        IntBuffer rgb888 = IntBuffer.allocate(newWidth * newHeight * 4);
-        Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
-        nativeGetPixels(inputFile, rgb888.array(), newWidth, newHeight, timeMS);
-
-        if ((newWidth == width) && (newHeight == height)) {
-            bitmap.copyPixelsFromBuffer(rgb888);
-        } else {
-            /* Create a temp bitmap to be used for resize */
-            tempBitmap.copyPixelsFromBuffer(rgb888);
-
-            /* Create a canvas to resize */
-            final Canvas canvas = new Canvas(bitmap);
-            canvas.drawBitmap(tempBitmap, new Rect(0, 0, newWidth, newHeight),
-                                          new Rect(0, 0, width, height), sResizePaint);
-            canvas.setBitmap(null);
-        }
-
-        if (tempBitmap != null) {
-            tempBitmap.recycle();
-        }
-
-        return bitmap;
+    Bitmap getPixels(String filename, int width, int height, long timeMs,
+            int videoRotation) {
+        final Bitmap result[] = new Bitmap[1];
+        getPixelsList(filename, width, height, timeMs, timeMs, 1, new int[] {0},
+                new MediaItem.GetThumbnailListCallback() {
+            public void onThumbnail(Bitmap bitmap, int index) {
+                result[0] = bitmap;
+            }
+        }, videoRotation);
+        return result[0];
     }
 
     /**
      * This method extracts a list of frame from the
      * input file and returns the frame in bitmap array
      *
-     * @param filename The inputFile
-     * @param width The width of the output frame
-     * @param height The height of the output frame
+     * @param filename The input file name
+     * @param width The width of the output frame, before rotation
+     * @param height The height of the output frame, before rotation
      * @param startMs The starting time in ms
      * @param endMs The end time in ms
      * @param thumbnailCount The number of frames to be extracted
      * @param indices The indices of thumbnails wanted
      * @param callback The callback used to pass back the bitmaps
-     * from startMs to endMs
+     * @param videoRotation The rotation degree need to be done for the bitmap
      *
      * @return The frames as bitmaps in bitmap array
      **/
@@ -3824,62 +3792,69 @@
             long startMs, long endMs, int thumbnailCount, int[] indices,
             final MediaItem.GetThumbnailListCallback callback,
             final int videoRotation) {
-        /* Make width and height as even */
-        final int newWidth = (width + 1) & 0xFFFFFFFE;
-        final int newHeight = (height + 1) & 0xFFFFFFFE;
-        final int thumbnailSize = newWidth * newHeight;
 
-        /* Create a temp bitmap for resized thumbnails */
-        final Bitmap tempBitmap =
-                (newWidth != width || newHeight != height)
-                ? Bitmap.createBitmap(newWidth, newHeight, Bitmap.Config.ARGB_8888)
+        // The decoder needs output width and height as even
+        final int decWidth = (width + 1) & 0xFFFFFFFE;
+        final int decHeight = (height + 1) & 0xFFFFFFFE;
+        final int thumbnailSize = decWidth * decHeight;
+
+        // We convert the decoder output (in int[]) to a bitmap by first
+        // copy it into an IntBuffer, then use Bitmap.copyPixelsFromBuffer to
+        // copy it to the bitmap.
+        final int[] decArray = new int[thumbnailSize];
+        final IntBuffer decBuffer = IntBuffer.allocate(thumbnailSize);
+
+        // If we need to resize and/or rotate the decoder output, we need a
+        // temporary bitmap to hold the decoded output.
+        final boolean needToMassage =
+                (decWidth != width || decHeight != height || videoRotation != 0);
+        final Bitmap tmpBitmap = needToMassage
+                ? Bitmap.createBitmap(decWidth, decHeight, Bitmap.Config.ARGB_8888)
                 : null;
 
-        final int[] rgb888 = new int[thumbnailSize];
-        final IntBuffer tmpBuffer = IntBuffer.allocate(thumbnailSize);
-        nativeGetPixelsList(filename, rgb888, newWidth, newHeight,
-                thumbnailCount, videoRotation, startMs, endMs, indices,
+        // The final output bitmap width/height may swap because of rotation.
+        final boolean needToSwapWH = (videoRotation == 90 || videoRotation == 270);
+        final int outWidth = needToSwapWH ? height : width;
+        final int outHeight = needToSwapWH ? width : height;
+
+        nativeGetPixelsList(filename, decArray, decWidth, decHeight,
+                thumbnailCount, startMs, endMs, indices,
                 new NativeGetPixelsListCallback() {
             public void onThumbnail(int index) {
-                Bitmap bitmap = Bitmap.createBitmap(
-                        width, height, Bitmap.Config.ARGB_8888);
-                tmpBuffer.put(rgb888, 0, thumbnailSize);
-                tmpBuffer.rewind();
+                // This is the bitmap we will output to the client
+                Bitmap outBitmap = Bitmap.createBitmap(
+                        outWidth, outHeight, Bitmap.Config.ARGB_8888);
 
-                if ((newWidth == width) && (newHeight == height)) {
-                    bitmap.copyPixelsFromBuffer(tmpBuffer);
+                // Copy int[] to IntBuffer
+                decBuffer.put(decArray, 0, thumbnailSize);
+                decBuffer.rewind();
+
+                if (!needToMassage) {
+                    // We can directly read the decoded result to output bitmap
+                    outBitmap.copyPixelsFromBuffer(decBuffer);
                 } else {
-                    /* Copy the out rgb buffer to temp bitmap */
-                    tempBitmap.copyPixelsFromBuffer(tmpBuffer);
+                    // Copy the decoded result to an intermediate bitmap first
+                    tmpBitmap.copyPixelsFromBuffer(decBuffer);
 
-                    /* Create a canvas to resize */
-                    final Canvas canvas = new Canvas(bitmap);
-                    canvas.drawBitmap(tempBitmap,
-                            new Rect(0, 0, newWidth, newHeight),
-                            new Rect(0, 0, width, height), sResizePaint);
-
-                    canvas.setBitmap(null);
+                    // Create a canvas to resize/rotate the bitmap
+                    // First scale the decoded bitmap to (0,0)-(1,1), rotate it
+                    // with (0.5, 0.5) as center, then scale it to
+                    // (outWidth, outHeight).
+                    final Canvas canvas = new Canvas(outBitmap);
+                    Matrix m = new Matrix();
+                    float sx = 1f / decWidth;
+                    float sy = 1f / decHeight;
+                    m.postScale(sx, sy);
+                    m.postRotate(videoRotation, 0.5f, 0.5f);
+                    m.postScale(outWidth, outHeight);
+                    canvas.drawBitmap(tmpBitmap, m, sResizePaint);
                 }
-
-                if (videoRotation == 0) {
-                    callback.onThumbnail(bitmap, index);
-                } else {
-                    Matrix mtx = new Matrix();
-                    mtx.postRotate(videoRotation);
-                    Bitmap rotatedBmp =
-                        Bitmap.createBitmap(bitmap, 0, 0, width, height, mtx, false);
-                    callback.onThumbnail(rotatedBmp, index);
-
-                    if (bitmap != null) {
-                        bitmap.recycle();
-                    }
-                }
-
+                callback.onThumbnail(outBitmap, index);
             }
         });
 
-        if (tempBitmap != null) {
-            tempBitmap.recycle();
+        if (tmpBitmap != null) {
+            tmpBitmap.recycle();
         }
     }
 
@@ -3996,7 +3971,7 @@
             long timeMS);
 
     private native int nativeGetPixelsList(String fileName, int[] pixelArray,
-            int width, int height, int nosofTN, int videoRotation, long startTimeMs,
+            int width, int height, int nosofTN, long startTimeMs,
             long endTimeMs, int[] indices, NativeGetPixelsListCallback callback);
 
     /**
diff --git a/media/java/android/media/videoeditor/MediaImageItem.java b/media/java/android/media/videoeditor/MediaImageItem.java
index 65a9e19..a862d00 100755
--- a/media/java/android/media/videoeditor/MediaImageItem.java
+++ b/media/java/android/media/videoeditor/MediaImageItem.java
@@ -606,7 +606,7 @@
     public Bitmap getThumbnail(int width, int height, long timeMs) throws IOException {
         if (getGeneratedImageClip() != null) {
             return mMANativeHelper.getPixels(getGeneratedImageClip(),
-                width, height,timeMs);
+                width, height, timeMs, 0);
         } else {
             return scaleImage(mFilename, width, height);
         }
diff --git a/media/java/android/media/videoeditor/MediaVideoItem.java b/media/java/android/media/videoeditor/MediaVideoItem.java
index 2ce857c..bbcdf57 100755
--- a/media/java/android/media/videoeditor/MediaVideoItem.java
+++ b/media/java/android/media/videoeditor/MediaVideoItem.java
@@ -293,7 +293,14 @@
             throw new IllegalArgumentException("Invalid Dimensions");
         }
 
-        return mMANativeHelper.getPixels(super.getFilename(), width, height,timeMs);
+        if (mVideoRotationDegree == 90 || mVideoRotationDegree == 270) {
+            int temp = width;
+            width = height;
+            height = temp;
+        }
+
+        return mMANativeHelper.getPixels(
+                getFilename(), width, height, timeMs, mVideoRotationDegree);
     }
 
     /*
@@ -318,8 +325,14 @@
             throw new IllegalArgumentException("Invalid dimension");
         }
 
-        mMANativeHelper.getPixelsList(super.getFilename(), width,
-                height, startMs, endMs, thumbnailCount, indices, callback,
+        if (mVideoRotationDegree == 90 || mVideoRotationDegree == 270) {
+            int temp = width;
+            width = height;
+            height = temp;
+        }
+
+        mMANativeHelper.getPixelsList(getFilename(), width, height,
+                startMs, endMs, thumbnailCount, indices, callback,
                 mVideoRotationDegree);
     }
 
diff --git a/media/java/android/media/videoeditor/VideoEditorImpl.java b/media/java/android/media/videoeditor/VideoEditorImpl.java
index f18dd88..2446c2f 100755
--- a/media/java/android/media/videoeditor/VideoEditorImpl.java
+++ b/media/java/android/media/videoeditor/VideoEditorImpl.java
@@ -1825,27 +1825,10 @@
         if (mMediaItems.size() > 0) {
             MediaItem mI = mMediaItems.get(0);
             /*
-             * Lets initialize the width for default aspect ratio i.e 16:9
+             * Keep aspect ratio of the image
              */
             int height = 480;
-            int width = 854;
-            switch (mI.getAspectRatio()) {
-                case MediaProperties.ASPECT_RATIO_3_2:
-                    width = 720;
-                    break;
-                case MediaProperties.ASPECT_RATIO_4_3:
-                    width = 640;
-                    break;
-                case MediaProperties.ASPECT_RATIO_5_3:
-                    width = 800;
-                    break;
-                case MediaProperties.ASPECT_RATIO_11_9:
-                    width = 586;
-                    break;
-                case MediaProperties.ASPECT_RATIO_16_9:
-                case MediaProperties.ASPECT_RATIO_UNDEFINED:
-                    break;
-            }
+            int width = mI.getWidth() * height / mI.getHeight();
 
             Bitmap projectBitmap = null;
             String filename = mI.getFilename();
diff --git a/media/jni/mediaeditor/VideoEditorMain.cpp b/media/jni/mediaeditor/VideoEditorMain.cpp
index 4e73581..4e954fc 100755
--- a/media/jni/mediaeditor/VideoEditorMain.cpp
+++ b/media/jni/mediaeditor/VideoEditorMain.cpp
@@ -185,7 +185,6 @@
                                      M4OSA_UInt32             width,
                                      M4OSA_UInt32             height,
                                      M4OSA_UInt32             noOfThumbnails,
-                                     M4OSA_UInt32             videoRotation,
                                      jlong                    startTime,
                                      jlong                    endTime,
                                      jintArray                indexArray,
@@ -292,7 +291,7 @@
                                 (void *)videoEditor_release            },
     {"nativeGetPixels",         "(Ljava/lang/String;[IIIJ)I",
                                 (void*)videoEditor_getPixels               },
-    {"nativeGetPixelsList",     "(Ljava/lang/String;[IIIIIJJ[ILandroid/media/videoeditor/MediaArtistNativeHelper$NativeGetPixelsListCallback;)I",
+    {"nativeGetPixelsList",     "(Ljava/lang/String;[IIIIJJ[ILandroid/media/videoeditor/MediaArtistNativeHelper$NativeGetPixelsListCallback;)I",
                                 (void*)videoEditor_getPixelsList           },
     {"getMediaProperties",
     "(Ljava/lang/String;)Landroid/media/videoeditor/MediaArtistNativeHelper$Properties;",
@@ -2286,7 +2285,6 @@
                 M4OSA_UInt32            width,
                 M4OSA_UInt32            height,
                 M4OSA_UInt32            noOfThumbnails,
-                M4OSA_UInt32            videoRotation,
                 jlong                   startTime,
                 jlong                   endTime,
                 jintArray               indexArray,
diff --git a/media/libstagefright/AudioPlayer.cpp b/media/libstagefright/AudioPlayer.cpp
index d41ab1b..ba076f5 100644
--- a/media/libstagefright/AudioPlayer.cpp
+++ b/media/libstagefright/AudioPlayer.cpp
@@ -20,8 +20,8 @@
 
 #include <binder/IPCThreadState.h>
 #include <media/AudioTrack.h>
+#include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/AudioPlayer.h>
-#include <media/stagefright/MediaDebug.h>
 #include <media/stagefright/MediaDefs.h>
 #include <media/stagefright/MediaErrors.h>
 #include <media/stagefright/MediaSource.h>
@@ -60,7 +60,7 @@
 }
 
 void AudioPlayer::setSource(const sp<MediaSource> &source) {
-    CHECK_EQ(mSource, NULL);
+    CHECK(mSource == NULL);
     mSource = source;
 }
 
@@ -466,6 +466,8 @@
 }
 
 int64_t AudioPlayer::getRealTimeUsLocked() const {
+    CHECK(mStarted);
+    CHECK_NE(mSampleRate, 0);
     return -mLatencyUs + (mNumFramesPlayed * 1000000) / mSampleRate;
 }
 
diff --git a/media/libstagefright/AwesomePlayer.cpp b/media/libstagefright/AwesomePlayer.cpp
index 47224cc..07a46bd 100644
--- a/media/libstagefright/AwesomePlayer.cpp
+++ b/media/libstagefright/AwesomePlayer.cpp
@@ -1736,7 +1736,9 @@
         modifyFlags(TEXT_RUNNING, SET);
     }
 
-    TimeSource *ts = (mFlags & AUDIO_AT_EOS) ? &mSystemTimeSource : mTimeSource;
+    TimeSource *ts =
+        ((mFlags & AUDIO_AT_EOS) || !(mFlags & AUDIOPLAYER_STARTED))
+            ? &mSystemTimeSource : mTimeSource;
 
     if (mFlags & FIRST_FRAME) {
         modifyFlags(FIRST_FRAME, CLEAR);
diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java b/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java
index 43905dd..10e7602 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java
@@ -96,11 +96,13 @@
     /* package */ final class ActivityDescription {
         final ActivityManager.RecentTaskInfo recentTaskInfo;
         final ResolveInfo resolveInfo;
-        int taskId; // application task id for curating apps
-        Intent intent; // launch intent for application
+        final int taskId; // application task id for curating apps
+        final int persistentTaskId; // persistent id
+        final Intent intent; // launch intent for application
+        final String packageName; // used to override animations (see onClick())
+        final int position; // position in list
+
         Matrix matrix; // arbitrary rotation matrix to correct orientation
-        String packageName; // used to override animations (see onClick())
-        int position; // position in list
 
         private Bitmap mThumbnail; // generated by Activity.onCreateThumbnail()
         private Drawable mIcon; // application package icon
@@ -108,11 +110,12 @@
 
         public ActivityDescription(ActivityManager.RecentTaskInfo _recentInfo,
                 ResolveInfo _resolveInfo, Intent _intent,
-                int _id, int _pos, String _packageName) {
+                int _pos, String _packageName) {
             recentTaskInfo = _recentInfo;
             resolveInfo = _resolveInfo;
             intent = _intent;
-            taskId = _id;
+            taskId = _recentInfo.id;
+            persistentTaskId = _recentInfo.persistentId;
             position = _pos;
             packageName = _packageName;
         }
@@ -496,17 +499,17 @@
                 final String title = info.loadLabel(pm).toString();
                 // Drawable icon = info.loadIcon(pm);
                 Drawable icon = getFullResIcon(resolveInfo, pm);
-                int id = recentInfo.id;
                 if (title != null && title.length() > 0 && icon != null) {
-                    if (DEBUG) Log.v(TAG, "creating activity desc for id=" + id + ", label=" + title);
+                    if (DEBUG) Log.v(TAG, "creating activity desc for id="
+                            + recentInfo.id + ", label=" + title);
                     ActivityManager.TaskThumbnails thumbs = am.getTaskThumbnails(
                             recentInfo.persistentId);
                     ActivityDescription item = new ActivityDescription(recentInfo,
-                            resolveInfo, intent, id, index, info.packageName);
+                            resolveInfo, intent, index, info.packageName);
                     activityDescriptions.add(item);
                     ++index;
                 } else {
-                    if (DEBUG) Log.v(TAG, "SKIPPING item " + id);
+                    if (DEBUG) Log.v(TAG, "SKIPPING item " + recentInfo.id);
                 }
             }
         }
@@ -727,7 +730,7 @@
         // the task.
         final ActivityManager am = (ActivityManager)
                 mContext.getSystemService(Context.ACTIVITY_SERVICE);
-        am.removeTask(ad.taskId, ActivityManager.REMOVE_TASK_KILL_PROCESS);
+        am.removeTask(ad.persistentTaskId, ActivityManager.REMOVE_TASK_KILL_PROCESS);
     }
 
     private void startApplicationDetailsActivity(String packageName) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NotificationRowLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NotificationRowLayout.java
index e287b7a..06798c6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NotificationRowLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NotificationRowLayout.java
@@ -20,7 +20,7 @@
 import android.animation.AnimatorListenerAdapter;
 import android.animation.AnimatorSet;
 import android.animation.ObjectAnimator;
-import android.animation.TimeAnimator;
+import android.animation.ValueAnimator;
 import android.content.Context;
 import android.content.res.Configuration;
 import android.content.res.TypedArray;
@@ -37,12 +37,12 @@
 import com.android.systemui.R;
 import com.android.systemui.SwipeHelper;
 
-import java.util.HashSet;
+import java.util.HashMap;
 
 public class NotificationRowLayout extends ViewGroup implements SwipeHelper.Callback {
     private static final String TAG = "NotificationRowLayout";
     private static final boolean DEBUG = false;
-    private static final boolean SLOW_ANIMATIONS = false; // DEBUG;
+    private static final boolean SLOW_ANIMATIONS = DEBUG;
 
     private static final boolean ANIMATE_LAYOUT = true;
 
@@ -54,8 +54,8 @@
     int mRowHeight = 0;
     int mHeight = 0;
 
-    HashSet<View> mAppearingViews = new HashSet<View>();
-    HashSet<View> mDisappearingViews = new HashSet<View>();
+    HashMap<View, ValueAnimator> mAppearingViews = new HashMap<View, ValueAnimator>();
+    HashMap<View, ValueAnimator> mDisappearingViews = new HashMap<View, ValueAnimator>();
 
     private SwipeHelper mSwipeHelper;
 
@@ -166,8 +166,6 @@
         final View childF = child;
 
         if (ANIMATE_LAYOUT) {
-            mAppearingViews.add(child);
-
             child.setPivotY(0);
             final ObjectAnimator alphaFade = ObjectAnimator.ofFloat(child, "alpha", 0f, 1f);
             alphaFade.setDuration(APPEAR_ANIM_LEN);
@@ -178,7 +176,11 @@
                     requestLayout(); // pick up any final changes in position
                 }
             });
+
             alphaFade.start();
+
+            mAppearingViews.put(child, alphaFade);
+
             requestLayout(); // start the container animation
         }
     }
@@ -187,27 +189,27 @@
     public void removeView(View child) {
         final View childF = child;
         if (ANIMATE_LAYOUT) {
-            if (mAppearingViews.contains(child)) {
+            if (mAppearingViews.containsKey(child)) {
                 mAppearingViews.remove(child);
             }
-            mDisappearingViews.add(child);
-
             child.setPivotY(0);
 
             final ObjectAnimator alphaFade = ObjectAnimator.ofFloat(child, "alpha", 0f);
+            alphaFade.setDuration(DISAPPEAR_ANIM_LEN);
             alphaFade.addListener(new AnimatorListenerAdapter() {
                 @Override
                 public void onAnimationEnd(Animator animation) {
                     if (DEBUG) Slog.d(TAG, "actually removing child: " + childF);
                     NotificationRowLayout.super.removeView(childF);
-                    childF.setAlpha(1f);
                     mDisappearingViews.remove(childF);
                     requestLayout(); // pick up any final changes in position
                 }
             });
 
-            alphaFade.setDuration(DISAPPEAR_ANIM_LEN);
             alphaFade.start();
+
+            mDisappearingViews.put(child, alphaFade);
+
             requestLayout(); // start the container animation
         } else {
             super.removeView(child);
@@ -246,7 +248,7 @@
             if (child.getVisibility() == GONE) {
                 continue;
             }
-            if (mDisappearingViews.contains(child)) {
+            if (mDisappearingViews.containsKey(child)) {
                 continue;
             }
             numRows++;
@@ -304,14 +306,19 @@
             if (child.getVisibility() == GONE) {
                 continue;
             }
-            float alpha = child.getAlpha();
-            if (alpha > 1.0f) {
-                if (DEBUG) {
-                    Slog.w(TAG, "alpha=" + alpha + " > 1!!! " + child);
-                }
-                alpha = 1f;
+            float progress = 1.0f;
+            if (mDisappearingViews.containsKey(child)) {
+                progress = 1.0f - mDisappearingViews.get(child).getAnimatedFraction();
+            } else if (mAppearingViews.containsKey(child)) {
+                progress = 1.0f - mAppearingViews.get(child).getAnimatedFraction();
             }
-            final int thisRowHeight = (int)(alpha * mRowHeight);
+            if (progress > 1.0f) {
+                if (DEBUG) {
+                    Slog.w(TAG, "progress=" + progress + " > 1!!! " + child);
+                }
+                progress = 1f;
+            }
+            final int thisRowHeight = (int)(progress * mRowHeight);
             if (DEBUG) {
                 Slog.d(TAG, String.format(
                             "laying out child #%d: (0, %d, %d, %d) h=%d",
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindow.java b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
index b69a7c2..f5e3a45 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneWindow.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
@@ -384,7 +384,7 @@
                 st.menu.stopDispatchingItemsChanged();
                 if ((cb == null) || !cb.onCreatePanelMenu(st.featureId, st.menu)) {
                     // Ditch the menu created above
-                    st.menu = null;
+                    st.setMenu(null);
 
                     if (mActionBar != null) {
                         // Don't show it in the action bar either
@@ -3207,7 +3207,17 @@
         }
 
         void setMenu(MenuBuilder menu) {
+            if (menu == this.menu) return;
+
+            if (this.menu != null) {
+                this.menu.removeMenuPresenter(iconMenuPresenter);
+                this.menu.removeMenuPresenter(listMenuPresenter);
+            }
             this.menu = menu;
+            if (menu != null) {
+                if (iconMenuPresenter != null) menu.addMenuPresenter(iconMenuPresenter);
+                if (listMenuPresenter != null) menu.addMenuPresenter(listMenuPresenter);
+            }
         }
 
         MenuView getListMenuView(MenuPresenter.Callback cb) {
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index 9db56ce..d6d3b9d 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -106,6 +106,7 @@
 import android.os.SystemProperties;
 import android.provider.Settings;
 import android.util.EventLog;
+import android.util.Pair;
 import android.util.Slog;
 import android.util.Log;
 import android.util.PrintWriterPrinter;
@@ -5004,7 +5005,13 @@
                             maxNum < N ? maxNum : N);
             for (int i=0; i<N && maxNum > 0; i++) {
                 TaskRecord tr = mRecentTasks.get(i);
-                if (((flags&ActivityManager.RECENT_WITH_EXCLUDED) != 0)
+                // Return the entry if desired by the caller.  We always return
+                // the first entry, because callers always expect this to be the
+                // forground app.  We may filter others if the caller has
+                // not supplied RECENT_WITH_EXCLUDED and there is some reason
+                // we should exclude the entry.
+                if (i == 0
+                        || ((flags&ActivityManager.RECENT_WITH_EXCLUDED) != 0)
                         || (tr.intent == null)
                         || ((tr.intent.getFlags()
                                 &Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS) == 0)) {
@@ -5152,6 +5159,29 @@
                     cleanUpRemovedTaskLocked(r,
                             (flags&ActivityManager.REMOVE_TASK_KILL_PROCESS) != 0);
                     return true;
+                } else {
+                    TaskRecord tr = null;
+                    int i=0;
+                    while (i < mRecentTasks.size()) {
+                        TaskRecord t = mRecentTasks.get(i);
+                        if (t.taskId == taskId) {
+                            tr = t;
+                            break;
+                        }
+                        i++;
+                    }
+                    if (tr != null) {
+                        if (tr.numActivities <= 0) {
+                            // Caller is just removing a recent task that is
+                            // not actively running.  That is easy!
+                            mRecentTasks.remove(i);
+                        } else {
+                            Slog.w(TAG, "removeTask: task " + taskId
+                                    + " does not have activities to remove, "
+                                    + " but numActivities=" + tr.numActivities
+                                    + ": " + tr);
+                        }
+                    }
                 }
             } finally {
                 Binder.restoreCallingIdentity(ident);
@@ -7546,7 +7576,33 @@
 
         return errList;
     }
-    
+
+    static int oomAdjToImportance(int adj, ActivityManager.RunningAppProcessInfo currApp) {
+        if (adj >= ProcessList.EMPTY_APP_ADJ) {
+            return ActivityManager.RunningAppProcessInfo.IMPORTANCE_EMPTY;
+        } else if (adj >= ProcessList.HIDDEN_APP_MIN_ADJ) {
+            if (currApp != null) {
+                currApp.lru = adj - ProcessList.HIDDEN_APP_MIN_ADJ + 1;
+            }
+            return ActivityManager.RunningAppProcessInfo.IMPORTANCE_BACKGROUND;
+        } else if (adj >= ProcessList.HOME_APP_ADJ) {
+            if (currApp != null) {
+                currApp.lru = 0;
+            }
+            return ActivityManager.RunningAppProcessInfo.IMPORTANCE_BACKGROUND;
+        } else if (adj >= ProcessList.SECONDARY_SERVER_ADJ) {
+            return ActivityManager.RunningAppProcessInfo.IMPORTANCE_SERVICE;
+        } else if (adj >= ProcessList.HEAVY_WEIGHT_APP_ADJ) {
+            return ActivityManager.RunningAppProcessInfo.IMPORTANCE_CANT_SAVE_STATE;
+        } else if (adj >= ProcessList.PERCEPTIBLE_APP_ADJ) {
+            return ActivityManager.RunningAppProcessInfo.IMPORTANCE_PERCEPTIBLE;
+        } else if (adj >= ProcessList.VISIBLE_APP_ADJ) {
+            return ActivityManager.RunningAppProcessInfo.IMPORTANCE_VISIBLE;
+        } else {
+            return ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND;
+        }
+    }
+
     public List<ActivityManager.RunningAppProcessInfo> getRunningAppProcesses() {
         // Lazy instantiation of list
         List<ActivityManager.RunningAppProcessInfo> runList = null;
@@ -7567,28 +7623,12 @@
                         currApp.flags |= ActivityManager.RunningAppProcessInfo.FLAG_PERSISTENT;
                     }
                     int adj = app.curAdj;
-                    if (adj >= ProcessList.EMPTY_APP_ADJ) {
-                        currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_EMPTY;
-                    } else if (adj >= ProcessList.HIDDEN_APP_MIN_ADJ) {
-                        currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_BACKGROUND;
-                        currApp.lru = adj - ProcessList.HIDDEN_APP_MIN_ADJ + 1;
-                    } else if (adj >= ProcessList.HOME_APP_ADJ) {
-                        currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_BACKGROUND;
-                        currApp.lru = 0;
-                    } else if (adj >= ProcessList.SECONDARY_SERVER_ADJ) {
-                        currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_SERVICE;
-                    } else if (adj >= ProcessList.HEAVY_WEIGHT_APP_ADJ) {
-                        currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_CANT_SAVE_STATE;
-                    } else if (adj >= ProcessList.PERCEPTIBLE_APP_ADJ) {
-                        currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_PERCEPTIBLE;
-                    } else if (adj >= ProcessList.VISIBLE_APP_ADJ) {
-                        currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_VISIBLE;
-                    } else {
-                        currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND;
-                    }
+                    currApp.importance = oomAdjToImportance(adj, currApp);
                     currApp.importanceReasonCode = app.adjTypeCode;
                     if (app.adjSource instanceof ProcessRecord) {
                         currApp.importanceReasonPid = ((ProcessRecord)app.adjSource).pid;
+                        currApp.importanceReasonImportance = oomAdjToImportance(
+                                app.adjSourceOom, null);
                     } else if (app.adjSource instanceof ActivityRecord) {
                         ActivityRecord r = (ActivityRecord)app.adjSource;
                         if (r.app != null) currApp.importanceReasonPid = r.app.pid;
@@ -7891,7 +7931,7 @@
         if (mLruProcesses.size() > 0) {
             if (needSep) pw.println(" ");
             needSep = true;
-            pw.println("  Process LRU list (most recent first):");
+            pw.println("  Process LRU list (sorted by oom_adj):");
             dumpProcessOomList(pw, this, mLruProcesses, "    ",
                     "Proc", "PERS", false);
             needSep = true;
@@ -8069,29 +8109,6 @@
         boolean needSep = false;
 
         if (mLruProcesses.size() > 0) {
-            ArrayList<ProcessRecord> procs = new ArrayList<ProcessRecord>(mLruProcesses);
-
-            Comparator<ProcessRecord> comparator = new Comparator<ProcessRecord>() {
-                @Override
-                public int compare(ProcessRecord object1, ProcessRecord object2) {
-                    if (object1.setAdj != object2.setAdj) {
-                        return object1.setAdj > object2.setAdj ? -1 : 1;
-                    }
-                    if (object1.setSchedGroup != object2.setSchedGroup) {
-                        return object1.setSchedGroup > object2.setSchedGroup ? -1 : 1;
-                    }
-                    if (object1.keeping != object2.keeping) {
-                        return object1.keeping ? -1 : 1;
-                    }
-                    if (object1.pid != object2.pid) {
-                        return object1.pid > object2.pid ? -1 : 1;
-                    }
-                    return 0;
-                }
-            };
-
-            Collections.sort(procs, comparator);
-
             if (needSep) pw.println(" ");
             needSep = true;
             pw.println("  OOM levels:");
@@ -8110,7 +8127,7 @@
             if (needSep) pw.println(" ");
             needSep = true;
             pw.println("  Process OOM control:");
-            dumpProcessOomList(pw, this, procs, "    ",
+            dumpProcessOomList(pw, this, mLruProcesses, "    ",
                     "Proc", "PERS", true);
             needSep = true;
         }
@@ -8859,10 +8876,33 @@
     }
 
     private static final void dumpProcessOomList(PrintWriter pw,
-            ActivityManagerService service, List<ProcessRecord> list,
+            ActivityManagerService service, List<ProcessRecord> origList,
             String prefix, String normalLabel, String persistentLabel,
             boolean inclDetails) {
 
+        ArrayList<Pair<ProcessRecord, Integer>> list
+                = new ArrayList<Pair<ProcessRecord, Integer>>(origList.size());
+        for (int i=0; i<origList.size(); i++) {
+            list.add(new Pair<ProcessRecord, Integer>(origList.get(i), i));
+        }
+
+        Comparator<Pair<ProcessRecord, Integer>> comparator
+                = new Comparator<Pair<ProcessRecord, Integer>>() {
+            @Override
+            public int compare(Pair<ProcessRecord, Integer> object1,
+                    Pair<ProcessRecord, Integer> object2) {
+                if (object1.first.setAdj != object2.first.setAdj) {
+                    return object1.first.setAdj > object2.first.setAdj ? -1 : 1;
+                }
+                if (object1.second.intValue() != object2.second.intValue()) {
+                    return object1.second.intValue() > object2.second.intValue() ? -1 : 1;
+                }
+                return 0;
+            }
+        };
+
+        Collections.sort(list, comparator);
+
         final long curRealtime = SystemClock.elapsedRealtime();
         final long realtimeSince = curRealtime - service.mLastPowerCheckRealtime;
         final long curUptime = SystemClock.uptimeMillis();
@@ -8870,7 +8910,7 @@
 
         final int N = list.size()-1;
         for (int i=N; i>=0; i--) {
-            ProcessRecord r = list.get(i);
+            ProcessRecord r = list.get(i).first;
             String oomAdj;
             if (r.setAdj >= ProcessList.EMPTY_APP_ADJ) {
                 oomAdj = buildOomTag("empty", null, r.setAdj, ProcessList.EMPTY_APP_ADJ);
@@ -8919,7 +8959,7 @@
             }
             pw.println(String.format("%s%s #%2d: adj=%s/%s%s trm=%2d %s (%s)",
                     prefix, (r.persistent ? persistentLabel : normalLabel),
-                    N-i, oomAdj, schedGroup, foreground, r.trimMemoryLevel,
+                    N-list.get(i).second, oomAdj, schedGroup, foreground, r.trimMemoryLevel,
                     r.toShortString(), r.adjType));
             if (r.adjSource != null || r.adjTarget != null) {
                 pw.print(prefix);
@@ -13118,6 +13158,7 @@
                                     app.adjTypeCode = ActivityManager.RunningAppProcessInfo
                                             .REASON_SERVICE_IN_USE;
                                     app.adjSource = cr.binding.client;
+                                    app.adjSourceOom = clientAdj;
                                     app.adjTarget = s.name;
                                 }
                                 if ((cr.flags&Context.BIND_NOT_FOREGROUND) == 0) {
@@ -13140,6 +13181,7 @@
                                     app.adjTypeCode = ActivityManager.RunningAppProcessInfo
                                             .REASON_SERVICE_IN_USE;
                                     app.adjSource = a;
+                                    app.adjSourceOom = adj;
                                     app.adjTarget = s.name;
                                 }
                             }
@@ -13201,6 +13243,7 @@
                             app.adjTypeCode = ActivityManager.RunningAppProcessInfo
                                     .REASON_PROVIDER_IN_USE;
                             app.adjSource = client;
+                            app.adjSourceOom = clientAdj;
                             app.adjTarget = cpr.name;
                         }
                         if (client.curSchedGroup == Process.THREAD_GROUP_DEFAULT) {
@@ -13511,16 +13554,21 @@
         computeOomAdjLocked(app, hiddenAdj, TOP_APP, false);
 
         if (app.curRawAdj != app.setRawAdj) {
-            if (app.curRawAdj > ProcessList.FOREGROUND_APP_ADJ
-                    && app.setRawAdj <= ProcessList.FOREGROUND_APP_ADJ) {
-                // If this app is transitioning from foreground to
-                // non-foreground, have it do a gc.
-                scheduleAppGcLocked(app);
-            } else if (app.curRawAdj >= ProcessList.HIDDEN_APP_MIN_ADJ
-                    && app.setRawAdj < ProcessList.HIDDEN_APP_MIN_ADJ) {
-                // Likewise do a gc when an app is moving in to the
-                // background (such as a service stopping).
-                scheduleAppGcLocked(app);
+            if (false) {
+                // Removing for now.  Forcing GCs is not so useful anymore
+                // with Dalvik, and the new memory level hint facility is
+                // better for what we need to do these days.
+                if (app.curRawAdj > ProcessList.FOREGROUND_APP_ADJ
+                        && app.setRawAdj <= ProcessList.FOREGROUND_APP_ADJ) {
+                    // If this app is transitioning from foreground to
+                    // non-foreground, have it do a gc.
+                    scheduleAppGcLocked(app);
+                } else if (app.curRawAdj >= ProcessList.HIDDEN_APP_MIN_ADJ
+                        && app.setRawAdj < ProcessList.HIDDEN_APP_MIN_ADJ) {
+                    // Likewise do a gc when an app is moving in to the
+                    // background (such as a service stopping).
+                    scheduleAppGcLocked(app);
+                }
             }
 
             if (wasKeeping && !app.keeping) {
diff --git a/services/java/com/android/server/am/ActivityStack.java b/services/java/com/android/server/am/ActivityStack.java
index 4ad0f45..a0aedf9 100644
--- a/services/java/com/android/server/am/ActivityStack.java
+++ b/services/java/com/android/server/am/ActivityStack.java
@@ -1151,6 +1151,7 @@
                     try {
                         mService.mWindowManager.setAppVisibility(r, true);
                         r.sleeping = false;
+                        r.app.pendingUiClean = true;
                         r.app.thread.scheduleWindowVisibility(r, true);
                         r.stopFreezingScreenLocked(false);
                     } catch (Exception e) {
@@ -1497,6 +1498,7 @@
                 
                 next.sleeping = false;
                 showAskCompatModeDialogLocked(next);
+                next.app.pendingUiClean = true;
                 next.app.thread.scheduleResumeActivity(next,
                         mService.isNextTransitionForward());
                 
diff --git a/services/java/com/android/server/am/ProcessRecord.java b/services/java/com/android/server/am/ProcessRecord.java
index 24d92cf..9392bb4 100644
--- a/services/java/com/android/server/am/ProcessRecord.java
+++ b/services/java/com/android/server/am/ProcessRecord.java
@@ -99,6 +99,7 @@
     String adjType;             // Debugging: primary thing impacting oom_adj.
     int adjTypeCode;            // Debugging: adj code to report to app.
     Object adjSource;           // Debugging: option dependent object.
+    int adjSourceOom;           // Debugging: oom_adj of adjSource's process.
     Object adjTarget;           // Debugging: target component impacting oom_adj.
     
     // contains HistoryRecord objects
diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java
index 755a268..211c4da 100644
--- a/services/java/com/android/server/wm/WindowManagerService.java
+++ b/services/java/com/android/server/wm/WindowManagerService.java
@@ -5824,27 +5824,6 @@
         config.compatScreenHeightDp = (int)(config.screenHeightDp / mCompatibleScreenScale);
         config.compatSmallestScreenWidthDp = computeCompatSmallestWidth(rotated, dm, dw, dh);
 
-        // We need to determine the smallest width that will occur under normal
-        // operation.  To this, start with the base screen size and compute the
-        // width under the different possible rotations.  We need to un-rotate
-        // the current screen dimensions before doing this.
-        int unrotDw, unrotDh;
-        if (rotated) {
-            unrotDw = dh;
-            unrotDh = dw;
-        } else {
-            unrotDw = dw;
-            unrotDh = dh;
-        }
-        config.smallestScreenWidthDp = reduceConfigWidthSize(unrotDw,
-                Surface.ROTATION_0, dm.density, unrotDw);
-        config.smallestScreenWidthDp = reduceConfigWidthSize(config.smallestScreenWidthDp,
-                Surface.ROTATION_90, dm.density, unrotDh);
-        config.smallestScreenWidthDp = reduceConfigWidthSize(config.smallestScreenWidthDp,
-                Surface.ROTATION_180, dm.density, unrotDw);
-        config.smallestScreenWidthDp = reduceConfigWidthSize(config.smallestScreenWidthDp,
-                Surface.ROTATION_270, dm.density, unrotDh);
-
         // Compute the screen layout size class.
         int screenLayout;
         int longSize = dw;
diff --git a/tests/DataIdleTest/Android.mk b/tests/DataIdleTest/Android.mk
new file mode 100644
index 0000000..acb46c5
--- /dev/null
+++ b/tests/DataIdleTest/Android.mk
@@ -0,0 +1,29 @@
+#
+# Copyright (C) 2011 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.
+#
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+
+# We only want this apk build for tests.
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_PACKAGE_NAME := DataIdleTest
+LOCAL_JAVA_LIBRARIES := android.test.runner
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+# We need to sign it to get access to the network usage history.
+LOCAL_CERTIFICATE := platform
+
+include $(BUILD_PACKAGE)
diff --git a/tests/DataIdleTest/AndroidManifest.xml b/tests/DataIdleTest/AndroidManifest.xml
new file mode 100644
index 0000000..2792eec
--- /dev/null
+++ b/tests/DataIdleTest/AndroidManifest.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 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.
+-->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+  package="com.android.tests.dataidle"
+  android:sharedUserId="android.uid.system">
+    <uses-permission android:name="android.permission.INTERNET" />
+    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
+    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
+    <uses-permission android:name="android.permission.READ_NETWORK_USAGE_HISTORY" />
+    <application >
+        <uses-library android:name="android.test.runner" />
+    </application>
+
+    <instrumentation
+        android:name="android.test.InstrumentationTestRunner"
+        android:targetPackage="com.android.tests.dataidle"
+        android:label="Idle Bandwidth Tests" />
+
+</manifest>
diff --git a/tests/DataIdleTest/src/com/android/tests/dataidle/DataIdleTest.java b/tests/DataIdleTest/src/com/android/tests/dataidle/DataIdleTest.java
new file mode 100644
index 0000000..637f0d2
--- /dev/null
+++ b/tests/DataIdleTest/src/com/android/tests/dataidle/DataIdleTest.java
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2011 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.tests.dataidle;
+
+import android.content.Context;
+import android.net.INetworkStatsService;
+import android.net.NetworkStats.Entry;
+import android.net.NetworkTemplate;
+import android.net.NetworkStats;
+import android.os.Bundle;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.telephony.TelephonyManager;
+import android.test.InstrumentationTestCase;
+import android.test.InstrumentationTestRunner;
+import android.util.Log;
+
+/**
+ * A test that dumps data usage to instrumentation out, used for measuring data usage for idle
+ * devices.
+ */
+public class DataIdleTest extends InstrumentationTestCase {
+
+    private TelephonyManager mTelephonyManager;
+    private INetworkStatsService mStatsService;
+
+    private static final String LOG_TAG = "DataIdleTest";
+    private final static int INSTRUMENTATION_IN_PROGRESS = 2;
+
+    protected void setUp() throws Exception {
+        super.setUp();
+        Context c = getInstrumentation().getTargetContext();
+        mStatsService = INetworkStatsService.Stub.asInterface(
+                ServiceManager.getService(Context.NETWORK_STATS_SERVICE));
+        mTelephonyManager = (TelephonyManager) c.getSystemService(Context.TELEPHONY_SERVICE);
+    }
+
+    /**
+     * Test that dumps all the data usage metrics for wifi to instrumentation out.
+     */
+    public void testWifiIdle() {
+        NetworkTemplate template = NetworkTemplate.buildTemplateWifi();
+        fetchStats(template);
+    }
+
+    /**
+     * Test that dumps all the data usage metrics for all mobile to instrumentation out.
+     */
+    public void testMobile() {
+        String subscriberId = mTelephonyManager.getSubscriberId();
+        NetworkTemplate template = NetworkTemplate.buildTemplateMobileAll(subscriberId);
+        fetchStats(template);
+    }
+
+    /**
+     * Helper method that fetches all the network stats available and reports it
+     * to instrumentation out.
+     * @param template {link {@link NetworkTemplate} to match.
+     */
+    private void fetchStats(NetworkTemplate template) {
+        try {
+            NetworkStats stats = mStatsService.getSummaryForAllUid(template, Long.MIN_VALUE,
+                    Long.MAX_VALUE, false);
+            reportStats(stats);
+        } catch (RemoteException e) {
+            Log.w(LOG_TAG, "Failed to fetch network stats for wifi.");
+        }
+    }
+
+    /**
+     * Print network data usage stats to instrumentation out
+     * @param stats {@link NetworkorStats} to print
+     */
+    void reportStats(NetworkStats stats) {
+        for (int i = 0; i < stats.size(); ++i) {
+            Entry  statsEntry = stats.getValues(i, null);
+            Bundle result = new Bundle();
+            result.putInt("uid", statsEntry.uid);
+            result.putInt("tag", statsEntry.tag);
+            result.putInt("set", statsEntry.set);
+            result.putString("iface", statsEntry.iface);
+            result.putLong("rxBytes", statsEntry.rxBytes);
+            result.putLong("txBytes", statsEntry.txBytes);
+            getInstrumentation().sendStatus(INSTRUMENTATION_IN_PROGRESS, result);
+        }
+    }
+}
diff --git a/tests/RenderScriptTests/ImageProcessing/Android.mk b/tests/RenderScriptTests/ImageProcessing/Android.mk
index 507cc92..d7486e8 100644
--- a/tests/RenderScriptTests/ImageProcessing/Android.mk
+++ b/tests/RenderScriptTests/ImageProcessing/Android.mk
@@ -17,7 +17,9 @@
 LOCAL_PATH := $(call my-dir)
 include $(CLEAR_VARS)
 
-LOCAL_MODULE_TAGS := optional
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_JAVA_LIBRARIES := android.test.runner
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src) \
                    $(call all-renderscript-files-under, src)
diff --git a/tests/RenderScriptTests/ImageProcessing/AndroidManifest.xml b/tests/RenderScriptTests/ImageProcessing/AndroidManifest.xml
index 174cc65..2232b98 100644
--- a/tests/RenderScriptTests/ImageProcessing/AndroidManifest.xml
+++ b/tests/RenderScriptTests/ImageProcessing/AndroidManifest.xml
@@ -2,10 +2,11 @@
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
     package="com.android.rs.image">
-    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />    
+    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
     <uses-sdk android:minSdkVersion="11" />
     <application android:label="Image Processing"
                  android:hardwareAccelerated="true">
+        <uses-library android:name="android.test.runner" />
         <activity android:name="ImageProcessingActivity">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />
@@ -13,4 +14,9 @@
             </intent-filter>
         </activity>
     </application>
+
+    <instrumentation android:name=".ImageProcessingTestRunner"
+      android:targetPackage="com.android.rs.image"
+      android:label="Test runner for Image Processing Benchmark Test"
+    />
 </manifest>
diff --git a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/ImageProcessingActivity.java b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/ImageProcessingActivity.java
index 9aa70b0..3615f60 100644
--- a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/ImageProcessingActivity.java
+++ b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/ImageProcessingActivity.java
@@ -33,11 +33,13 @@
 import android.widget.SeekBar;
 import android.widget.TextView;
 import android.view.View;
+import android.util.Log;
 import java.lang.Math;
 
 public class ImageProcessingActivity extends Activity
                                        implements SurfaceHolder.Callback,
                                        SeekBar.OnSeekBarChangeListener {
+    private final String TAG = "Img";
     private Bitmap mBitmapIn;
     private Bitmap mBitmapOut;
     private ScriptC_threshold mScript;
@@ -268,7 +270,15 @@
 
     // button hook
     public void benchmark(View v) {
-        android.util.Log.v("Img", "Benchmarking");
+        long t = getBenchmark();
+        //long javaTime = javaFilter();
+        //mBenchmarkResult.setText("RS: " + t + " ms  Java: " + javaTime + " ms");
+        mBenchmarkResult.setText("Result: " + t + " ms");
+    }
+
+    // For benchmark test
+    public long getBenchmark() {
+        Log.v(TAG, "Benchmarking");
         int oldRadius = mRadius;
         mRadius = MAX_RADIUS;
         mScript.set_radius(mRadius);
@@ -279,16 +289,12 @@
         mOutPixelsAllocation.copyTo(mBitmapOut);
 
         t = java.lang.System.currentTimeMillis() - t;
-        android.util.Log.v("Img", "Renderscript frame time core ms " + t);
-
-        //long javaTime = javaFilter();
-        //mBenchmarkResult.setText("RS: " + t + " ms  Java: " + javaTime + " ms");
-        mBenchmarkResult.setText("Result: " + t + " ms");
-
+        Log.v(TAG, "getBenchmark: Renderscript frame time core ms " + t);
         mRadius = oldRadius;
         mScript.set_radius(mRadius);
 
         mScript.invoke_filter();
         mOutPixelsAllocation.copyTo(mBitmapOut);
+        return t;
     }
 }
diff --git a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/ImageProcessingTest.java b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/ImageProcessingTest.java
new file mode 100644
index 0000000..d2298da
--- /dev/null
+++ b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/ImageProcessingTest.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2011 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.rs.image;
+
+import android.os.Bundle;
+import android.os.Environment;
+import android.app.Instrumentation;
+import android.content.Context;
+import android.content.Intent;
+import android.net.Uri;
+import android.test.ActivityInstrumentationTestCase2;
+import android.test.suitebuilder.annotation.LargeTest;
+import android.util.Log;
+
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+
+/**
+ * ImageProcessing benchmark test.
+ * To run the test, please use command
+ *
+ * adb shell am instrument -w com.android.rs.image/.ImageProcessingTestRunner
+ *
+ */
+public class ImageProcessingTest extends ActivityInstrumentationTestCase2<ImageProcessingActivity> {
+    private final String TAG = "ImageProcessingTest";
+    private final String RESULT_FILE = "image_processing_result.txt";
+    private ImageProcessingActivity mAct;
+
+    public ImageProcessingTest() {
+        super(ImageProcessingActivity.class);
+    }
+
+    @Override
+    public void setUp() throws Exception {
+        super.setUp();
+        mAct = getActivity();
+   }
+
+    @Override
+    public void tearDown() throws Exception {
+        super.tearDown();
+    }
+
+    /**
+     * ImageProcessing benchmark test
+     */
+    @LargeTest
+    public void testImageProcessingBench() {
+        long t = mAct.getBenchmark();
+        Log.v(TAG, "t = " + t);
+
+        // write result into a file
+        File externalStorage = Environment.getExternalStorageDirectory();
+        if (!externalStorage.canWrite()) {
+            Log.v(TAG, "sdcard is not writable");
+            return;
+        }
+        File resultFile = new File(externalStorage, RESULT_FILE);
+        resultFile.setWritable(true, false);
+        try {
+            BufferedWriter results = new BufferedWriter(new FileWriter(resultFile));
+            results.write("Renderscript frame time core: " + t + " ms");
+            results.close();
+            Log.v(TAG, "Saved results in: " + resultFile.getAbsolutePath());
+        } catch (IOException e) {
+            Log.v(TAG, "Unable to write result file " + e.getMessage());
+        }
+    }
+}
diff --git a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/ImageProcessingTestRunner.java b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/ImageProcessingTestRunner.java
new file mode 100644
index 0000000..4e27b7f
--- /dev/null
+++ b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/ImageProcessingTestRunner.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2011 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.rs.image;
+
+import com.android.rs.image.ImageProcessingTest;
+import android.os.Bundle;
+import android.test.InstrumentationTestRunner;
+import android.test.InstrumentationTestSuite;
+import junit.framework.TestSuite;
+
+/**
+ * Run the ImageProcessing benchmark test
+ * adb shell am instrument -w com.android.rs.image/.ImageProcessingTestRunner
+ *
+ */
+public class ImageProcessingTestRunner extends InstrumentationTestRunner {
+    @Override
+    public TestSuite getAllTests() {
+        TestSuite suite = new InstrumentationTestSuite(this);
+        suite.addTestSuite(ImageProcessingTest.class);
+        return suite;
+    }
+}
diff --git a/voip/jni/rtp/AmrCodec.cpp b/voip/jni/rtp/AmrCodec.cpp
index 84c7166..e2d820e 100644
--- a/voip/jni/rtp/AmrCodec.cpp
+++ b/voip/jni/rtp/AmrCodec.cpp
@@ -52,7 +52,7 @@
 
     int set(int sampleRate, const char *fmtp);
     int encode(void *payload, int16_t *samples);
-    int decode(int16_t *samples, void *payload, int length);
+    int decode(int16_t *samples, int count, void *payload, int length);
 
 private:
     void *mEncoder;
@@ -128,7 +128,7 @@
     return length;
 }
 
-int AmrCodec::decode(int16_t *samples, void *payload, int length)
+int AmrCodec::decode(int16_t *samples, int count, void *payload, int length)
 {
     unsigned char *bytes = (unsigned char *)payload;
     Frame_Type_3GPP type;
@@ -213,7 +213,7 @@
     }
 
     int encode(void *payload, int16_t *samples);
-    int decode(int16_t *samples, void *payload, int length);
+    int decode(int16_t *samples, int count, void *payload, int length);
 
 private:
     void *mEncoder;
@@ -239,20 +239,24 @@
     return -1;
 }
 
-int GsmEfrCodec::decode(int16_t *samples, void *payload, int length)
+int GsmEfrCodec::decode(int16_t *samples, int count, void *payload, int length)
 {
     unsigned char *bytes = (unsigned char *)payload;
-    if (length == 31 && (bytes[0] >> 4) == 0x0C) {
+    int n = 0;
+    while (n + 160 <= count && length >= 31 && (bytes[0] >> 4) == 0x0C) {
         for (int i = 0; i < 30; ++i) {
             bytes[i] = (bytes[i] << 4) | (bytes[i + 1] >> 4);
         }
         bytes[30] <<= 4;
 
-        if (AMRDecode(mDecoder, AMR_122, bytes, samples, MIME_IETF) == 31) {
-            return 160;
+        if (AMRDecode(mDecoder, AMR_122, bytes, &samples[n], MIME_IETF) != 31) {
+            break;
         }
+        n += 160;
+        length -= 31;
+        bytes += 31;
     }
-    return -1;
+    return n;
 }
 
 } // namespace
diff --git a/voip/jni/rtp/AudioCodec.h b/voip/jni/rtp/AudioCodec.h
index e389255..741730b 100644
--- a/voip/jni/rtp/AudioCodec.h
+++ b/voip/jni/rtp/AudioCodec.h
@@ -30,7 +30,7 @@
     // Returns the length of payload in bytes.
     virtual int encode(void *payload, int16_t *samples) = 0;
     // Returns the number of decoded samples.
-    virtual int decode(int16_t *samples, void *payload, int length) = 0;
+    virtual int decode(int16_t *samples, int count, void *payload, int length) = 0;
 };
 
 AudioCodec *newAudioCodec(const char *codecName);
diff --git a/voip/jni/rtp/AudioGroup.cpp b/voip/jni/rtp/AudioGroup.cpp
index 5f07bb5..93c809e 100644
--- a/voip/jni/rtp/AudioGroup.cpp
+++ b/voip/jni/rtp/AudioGroup.cpp
@@ -395,7 +395,8 @@
         mLatencyTimer = tick;
     }
 
-    if (mBufferTail - mBufferHead > BUFFER_SIZE - mInterval) {
+    int count = (BUFFER_SIZE - (mBufferTail - mBufferHead)) * mSampleRate;
+    if (count < mSampleCount) {
         // Buffer overflow. Drop the packet.
         LOGV("stream[%d] buffer overflow", mSocket);
         recv(mSocket, &c, 1, MSG_DONTWAIT);
@@ -403,19 +404,18 @@
     }
 
     // Receive the packet and decode it.
-    int16_t samples[mSampleCount];
-    int length = 0;
+    int16_t samples[count];
     if (!mCodec) {
         // Special case for device stream.
-        length = recv(mSocket, samples, sizeof(samples),
+        count = recv(mSocket, samples, sizeof(samples),
             MSG_TRUNC | MSG_DONTWAIT) >> 1;
     } else {
         __attribute__((aligned(4))) uint8_t buffer[2048];
         sockaddr_storage remote;
-        socklen_t len = sizeof(remote);
+        socklen_t addrlen = sizeof(remote);
 
-        length = recvfrom(mSocket, buffer, sizeof(buffer),
-            MSG_TRUNC | MSG_DONTWAIT, (sockaddr *)&remote, &len);
+        int length = recvfrom(mSocket, buffer, sizeof(buffer),
+            MSG_TRUNC | MSG_DONTWAIT, (sockaddr *)&remote, &addrlen);
 
         // Do we need to check SSRC, sequence, and timestamp? They are not
         // reliable but at least they can be used to identify duplicates?
@@ -433,14 +433,15 @@
         }
         length -= offset;
         if (length >= 0) {
-            length = mCodec->decode(samples, &buffer[offset], length);
+            length = mCodec->decode(samples, count, &buffer[offset], length);
         }
         if (length > 0 && mFixRemote) {
             mRemote = remote;
             mFixRemote = false;
         }
+        count = length;
     }
-    if (length <= 0) {
+    if (count <= 0) {
         LOGV("stream[%d] decoder error", mSocket);
         return;
     }
@@ -462,7 +463,7 @@
 
     // Append to the jitter buffer.
     int tail = mBufferTail * mSampleRate;
-    for (int i = 0; i < mSampleCount; ++i) {
+    for (int i = 0; i < count; ++i) {
         mBuffer[tail & mBufferMask] = samples[i];
         ++tail;
     }
diff --git a/voip/jni/rtp/G711Codec.cpp b/voip/jni/rtp/G711Codec.cpp
index a467acf..ef54863 100644
--- a/voip/jni/rtp/G711Codec.cpp
+++ b/voip/jni/rtp/G711Codec.cpp
@@ -39,7 +39,7 @@
         return mSampleCount;
     }
     int encode(void *payload, int16_t *samples);
-    int decode(int16_t *samples, void *payload, int length);
+    int decode(int16_t *samples, int count, void *payload, int length);
 private:
     int mSampleCount;
 };
@@ -64,9 +64,12 @@
     return mSampleCount;
 }
 
-int UlawCodec::decode(int16_t *samples, void *payload, int length)
+int UlawCodec::decode(int16_t *samples, int count, void *payload, int length)
 {
     int8_t *ulaws = (int8_t *)payload;
+    if (length > count) {
+        length = count;
+    }
     for (int i = 0; i < length; ++i) {
         int ulaw = ~ulaws[i];
         int exponent = (ulaw >> 4) & 0x07;
@@ -87,7 +90,7 @@
         return mSampleCount;
     }
     int encode(void *payload, int16_t *samples);
-    int decode(int16_t *samples, void *payload, int length);
+    int decode(int16_t *samples, int count, void *payload, int length);
 private:
     int mSampleCount;
 };
@@ -111,9 +114,12 @@
     return mSampleCount;
 }
 
-int AlawCodec::decode(int16_t *samples, void *payload, int length)
+int AlawCodec::decode(int16_t *samples, int count, void *payload, int length)
 {
     int8_t *alaws = (int8_t *)payload;
+    if (length > count) {
+        length = count;
+    }
     for (int i = 0; i < length; ++i) {
         int alaw = alaws[i] ^ 0x55;
         int exponent = (alaw >> 4) & 0x07;
diff --git a/voip/jni/rtp/GsmCodec.cpp b/voip/jni/rtp/GsmCodec.cpp
index 8d2286e..61dfdc9 100644
--- a/voip/jni/rtp/GsmCodec.cpp
+++ b/voip/jni/rtp/GsmCodec.cpp
@@ -44,7 +44,7 @@
     }
 
     int encode(void *payload, int16_t *samples);
-    int decode(int16_t *samples, void *payload, int length);
+    int decode(int16_t *samples, int count, void *payload, int length);
 
 private:
     gsm mEncode;
@@ -57,13 +57,17 @@
     return 33;
 }
 
-int GsmCodec::decode(int16_t *samples, void *payload, int length)
+int GsmCodec::decode(int16_t *samples, int count, void *payload, int length)
 {
-    if (length == 33 &&
-        gsm_decode(mDecode, (unsigned char *)payload, samples) == 0) {
-        return 160;
+    unsigned char *bytes = (unsigned char *)payload;
+    int n = 0;
+    while (n + 160 <= count && length >= 33 &&
+        gsm_decode(mDecode, bytes, &samples[n]) == 0) {
+        n += 160;
+        length -= 33;
+        bytes += 33;
     }
-    return -1;
+    return n;
 }
 
 } // namespace