Merge "Inter process interrogation ocassionally gets stuck."
diff --git a/Android.mk b/Android.mk
index d4dc088..352e5eb 100644
--- a/Android.mk
+++ b/Android.mk
@@ -150,6 +150,8 @@
 	core/java/com/android/internal/appwidget/IAppWidgetService.aidl \
 	core/java/com/android/internal/appwidget/IAppWidgetHost.aidl \
 	core/java/com/android/internal/backup/IBackupTransport.aidl \
+	core/java/com/android/internal/policy/IFaceLockCallback.aidl \
+	core/java/com/android/internal/policy/IFaceLockInterface.aidl \
 	core/java/com/android/internal/os/IDropBoxManagerService.aidl \
 	core/java/com/android/internal/os/IResultReceiver.aidl \
 	core/java/com/android/internal/statusbar/IStatusBar.aidl \
diff --git a/api/current.txt b/api/current.txt
index dfd8a33..1acc7a1 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -435,7 +435,7 @@
     field public static final int fadeEnabled = 16843390; // 0x101027e
     field public static final int fadeOffset = 16843383; // 0x1010277
     field public static final int fadeScrollbars = 16843434; // 0x10102aa
-    field public static final int fadingEdge = 16842975; // 0x10100df
+    field public static final deprecated int fadingEdge = 16842975; // 0x10100df
     field public static final int fadingEdgeLength = 16842976; // 0x10100e0
     field public static final int fastScrollAlwaysVisible = 16843573; // 0x1010335
     field public static final int fastScrollEnabled = 16843302; // 0x1010226
@@ -644,6 +644,8 @@
     field public static final int listPreferredItemHeight = 16842829; // 0x101004d
     field public static final int listPreferredItemHeightLarge = 16843668; // 0x1010394
     field public static final int listPreferredItemHeightSmall = 16843669; // 0x1010395
+    field public static final int listPreferredItemPaddingLeft = 16843697; // 0x10103b1
+    field public static final int listPreferredItemPaddingRight = 16843698; // 0x10103b2
     field public static final int listSelector = 16843003; // 0x10100fb
     field public static final int listSeparatorTextViewStyle = 16843272; // 0x1010208
     field public static final int listViewStyle = 16842868; // 0x1010074
@@ -788,6 +790,7 @@
     field public static final int reqNavigation = 16843306; // 0x101022a
     field public static final int reqTouchScreen = 16843303; // 0x1010227
     field public static final int required = 16843406; // 0x101028e
+    field public static final int requiresFadingEdge = 16843699; // 0x10103b3
     field public static final int requiresSmallestWidthDp = 16843620; // 0x1010364
     field public static final int resizeMode = 16843619; // 0x1010363
     field public static final int resizeable = 16843405; // 0x101028d
@@ -2075,7 +2078,8 @@
     method public android.accounts.Account[] getAccountsByType(java.lang.String);
     method public android.accounts.AccountManagerFuture<android.accounts.Account[]> getAccountsByTypeAndFeatures(java.lang.String, java.lang.String[], android.accounts.AccountManagerCallback<android.accounts.Account[]>, android.os.Handler);
     method public android.accounts.AccountManagerFuture<android.os.Bundle> getAuthToken(android.accounts.Account, java.lang.String, android.os.Bundle, android.app.Activity, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler);
-    method public android.accounts.AccountManagerFuture<android.os.Bundle> getAuthToken(android.accounts.Account, java.lang.String, boolean, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler);
+    method public deprecated android.accounts.AccountManagerFuture<android.os.Bundle> getAuthToken(android.accounts.Account, java.lang.String, boolean, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler);
+    method public android.accounts.AccountManagerFuture<android.os.Bundle> getAuthToken(android.accounts.Account, java.lang.String, android.os.Bundle, boolean, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler);
     method public android.accounts.AccountManagerFuture<android.os.Bundle> getAuthTokenByFeatures(java.lang.String, java.lang.String, java.lang.String[], android.app.Activity, android.os.Bundle, android.os.Bundle, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler);
     method public android.accounts.AuthenticatorDescription[] getAuthenticatorTypes();
     method public java.lang.String getPassword(android.accounts.Account);
@@ -2104,6 +2108,7 @@
     field public static final java.lang.String KEY_ACCOUNT_MANAGER_RESPONSE = "accountManagerResponse";
     field public static final java.lang.String KEY_ACCOUNT_NAME = "authAccount";
     field public static final java.lang.String KEY_ACCOUNT_TYPE = "accountType";
+    field public static final java.lang.String KEY_ANDROID_PACKAGE_NAME = "androidPackageName";
     field public static final java.lang.String KEY_AUTHENTICATOR_TYPES = "authenticator_types";
     field public static final java.lang.String KEY_AUTHTOKEN = "authtoken";
     field public static final java.lang.String KEY_AUTH_FAILED_MESSAGE = "authFailedMessage";
@@ -4528,6 +4533,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);
@@ -10288,6 +10331,7 @@
     method public void playSoundEffect(int);
     method public void playSoundEffect(int, float);
     method public void registerMediaButtonEventReceiver(android.content.ComponentName);
+    method public void registerRemoteControlClient(android.media.RemoteControlClient);
     method public int requestAudioFocus(android.media.AudioManager.OnAudioFocusChangeListener, int, int);
     method public deprecated void setBluetoothA2dpOn(boolean);
     method public void setBluetoothScoOn(boolean);
@@ -10307,6 +10351,7 @@
     method public void stopBluetoothSco();
     method public void unloadSoundEffects();
     method public void unregisterMediaButtonEventReceiver(android.content.ComponentName);
+    method public void unregisterRemoteControlClient(android.media.RemoteControlClient);
     field public static final java.lang.String ACTION_AUDIO_BECOMING_NOISY = "android.media.AUDIO_BECOMING_NOISY";
     field public static final deprecated java.lang.String ACTION_SCO_AUDIO_STATE_CHANGED = "android.media.SCO_AUDIO_STATE_CHANGED";
     field public static final java.lang.String ACTION_SCO_AUDIO_STATE_UPDATED = "android.media.ACTION_SCO_AUDIO_STATE_UPDATED";
@@ -10847,6 +10892,40 @@
     field public static final int SEEK_FORWARD_AVAILABLE = 3; // 0x3
   }
 
+  public class RemoteControlClient {
+    ctor public RemoteControlClient(android.content.ComponentName);
+    ctor public RemoteControlClient(android.content.ComponentName, android.os.Looper);
+    method public android.media.RemoteControlClient.MetadataEditor editMetadata(boolean);
+    method public void setPlaybackState(int);
+    method public void setTransportControlFlags(int);
+    field public static final int FLAG_KEY_MEDIA_FAST_FORWARD = 64; // 0x40
+    field public static final int FLAG_KEY_MEDIA_NEXT = 128; // 0x80
+    field public static final int FLAG_KEY_MEDIA_PAUSE = 16; // 0x10
+    field public static final int FLAG_KEY_MEDIA_PLAY = 4; // 0x4
+    field public static final int FLAG_KEY_MEDIA_PLAY_PAUSE = 8; // 0x8
+    field public static final int FLAG_KEY_MEDIA_PREVIOUS = 1; // 0x1
+    field public static final int FLAG_KEY_MEDIA_REWIND = 2; // 0x2
+    field public static final int FLAG_KEY_MEDIA_STOP = 32; // 0x20
+    field public static final int PLAYSTATE_BUFFERING = 8; // 0x8
+    field public static final int PLAYSTATE_ERROR = 9; // 0x9
+    field public static final int PLAYSTATE_FAST_FORWARDING = 4; // 0x4
+    field public static final int PLAYSTATE_PAUSED = 2; // 0x2
+    field public static final int PLAYSTATE_PLAYING = 3; // 0x3
+    field public static final int PLAYSTATE_REWINDING = 5; // 0x5
+    field public static final int PLAYSTATE_SKIPPING_BACKWARDS = 7; // 0x7
+    field public static final int PLAYSTATE_SKIPPING_FORWARDS = 6; // 0x6
+    field public static final int PLAYSTATE_STOPPED = 1; // 0x1
+  }
+
+  public class RemoteControlClient.MetadataEditor {
+    method public synchronized void apply();
+    method public synchronized void clear();
+    method public synchronized android.media.RemoteControlClient.MetadataEditor putBitmap(int, android.graphics.Bitmap) throws java.lang.IllegalArgumentException;
+    method public synchronized android.media.RemoteControlClient.MetadataEditor putLong(int, long) throws java.lang.IllegalArgumentException;
+    method public synchronized android.media.RemoteControlClient.MetadataEditor putString(int, java.lang.String) throws java.lang.IllegalArgumentException;
+    field public static final int BITMAP_KEY_ARTWORK = 100; // 0x64
+  }
+
   public class Ringtone {
     method public int getStreamType();
     method public java.lang.String getTitle(android.content.Context);
@@ -16662,6 +16741,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 +16754,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";
diff --git a/core/java/android/accounts/AccountManager.java b/core/java/android/accounts/AccountManager.java
index 2156425..029d107 100644
--- a/core/java/android/accounts/AccountManager.java
+++ b/core/java/android/accounts/AccountManager.java
@@ -197,6 +197,16 @@
     public static final String KEY_CALLER_PID = "callerPid";
 
     /**
+     * The Android package of the caller will be set in the options bundle by the
+     * {@link AccountManager} and will be passed to the AccountManagerService and
+     * to the AccountAuthenticators. The uid of the caller will be known by the
+     * AccountManagerService as well as the AccountAuthenticators so they will be able to
+     * verify that the package is consistent with the uid (a uid might be shared by many
+     * packages).
+     */
+    public static final String KEY_ANDROID_PACKAGE_NAME = "androidPackageName";
+
+    /**
      * Boolean, if set and 'customTokens' the authenticator is responsible for
      * notifications.
      * @hide
@@ -880,7 +890,10 @@
      * If the account is no longer present on the device, the return value is
      * authenticator-dependent.  The caller should verify the validity of the
      * account before requesting an auth token.
+     * @deprecated use {@link #getAuthToken(Account, String, android.os.Bundle,
+     * boolean, AccountManagerCallback, android.os.Handler)} instead
      */
+    @Deprecated
     public AccountManagerFuture<Bundle> getAuthToken(
             final Account account, final String authTokenType, final boolean notifyAuthFailure,
             AccountManagerCallback<Bundle> callback, Handler handler) {
@@ -895,6 +908,90 @@
     }
 
     /**
+     * Gets an auth token of the specified type for a particular account,
+     * optionally raising a notification if the user must enter credentials.
+     * This method is intended for background tasks and services where the
+     * user should not be immediately interrupted with a password prompt.
+     *
+     * <p>If a previously generated auth token is cached for this account and
+     * type, then it is returned.  Otherwise, if a saved password is
+     * available, it is sent to the server to generate a new auth token.
+     * Otherwise, an {@link Intent} is returned which, when started, will
+     * prompt the user for a password.  If the notifyAuthFailure parameter is
+     * set, a status bar notification is also created with the same Intent,
+     * alerting the user that they need to enter a password at some point.
+     *
+     * <p>In that case, you may need to wait until the user responds, which
+     * could take hours or days or forever.  When the user does respond and
+     * supply a new password, the account manager will broadcast the
+     * {@link #LOGIN_ACCOUNTS_CHANGED_ACTION} Intent, which applications can
+     * use to try again.
+     *
+     * <p>If notifyAuthFailure is not set, it is the application's
+     * responsibility to launch the returned Intent at some point.
+     * Either way, the result from this call will not wait for user action.
+     *
+     * <p>Some authenticators have auth token <em>types</em>, whose value
+     * is authenticator-dependent.  Some services use different token types to
+     * access different functionality -- for example, Google uses different auth
+     * tokens to access Gmail and Google Calendar for the same account.
+     *
+     * <p>This method may be called from any thread, but the returned
+     * {@link AccountManagerFuture} must not be used on the main thread.
+     *
+     * <p>This method requires the caller to hold the permission
+     * {@link android.Manifest.permission#USE_CREDENTIALS}.
+     *
+     * @param account The account to fetch an auth token for
+     * @param authTokenType The auth token type, an authenticator-dependent
+     *     string token, must not be null
+     * @param options Authenticator-specific options for the request,
+     *     may be null or empty
+     * @param notifyAuthFailure True to add a notification to prompt the
+     *     user for a password if necessary, false to leave that to the caller
+     * @param callback Callback to invoke when the request completes,
+     *     null for no callback
+     * @param handler {@link Handler} identifying the callback thread,
+     *     null for the main thread
+     * @return An {@link AccountManagerFuture} which resolves to a Bundle with
+     *     at least the following fields on success:
+     * <ul>
+     * <li> {@link #KEY_ACCOUNT_NAME} - the name of the account you supplied
+     * <li> {@link #KEY_ACCOUNT_TYPE} - the type of the account
+     * <li> {@link #KEY_AUTHTOKEN} - the auth token you wanted
+     * </ul>
+     *
+     * (Other authenticator-specific values may be returned.)  If the user
+     * must enter credentials, the returned Bundle contains only
+     * {@link #KEY_INTENT} with the {@link Intent} needed to launch a prompt.
+     *
+     * If an error occurred, {@link AccountManagerFuture#getResult()} throws:
+     * <ul>
+     * <li> {@link AuthenticatorException} if the authenticator failed to respond
+     * <li> {@link OperationCanceledException} if the operation is canceled for
+     *      any reason, incluidng the user canceling a credential request
+     * <li> {@link IOException} if the authenticator experienced an I/O problem
+     *      creating a new auth token, usually because of network trouble
+     * </ul>
+     * If the account is no longer present on the device, the return value is
+     * authenticator-dependent.  The caller should verify the validity of the
+     * account before requesting an auth token.
+     */
+    public AccountManagerFuture<Bundle> getAuthToken(
+            final Account account, final String authTokenType,
+            final Bundle options, final boolean notifyAuthFailure,
+            AccountManagerCallback<Bundle> callback, Handler handler) {
+        if (account == null) throw new IllegalArgumentException("account is null");
+        if (authTokenType == null) throw new IllegalArgumentException("authTokenType is null");
+        return new AmsTask(null, handler, callback) {
+            public void doWork() throws RemoteException {
+                mService.getAuthToken(mResponse, account, authTokenType,
+                        notifyAuthFailure, false /* expectActivityLaunch */, options);
+            }
+        }.start();
+    }
+
+    /**
      * Asks the user to add an account of a specified type.  The authenticator
      * for this account type processes this request with the appropriate user
      * interface.  If the user does elect to create a new account, the account
diff --git a/core/java/android/app/ProgressDialog.java b/core/java/android/app/ProgressDialog.java
index f1a04f8..7f1f385 100644
--- a/core/java/android/app/ProgressDialog.java
+++ b/core/java/android/app/ProgressDialog.java
@@ -16,7 +16,10 @@
 
 package android.app;
 
+import com.android.internal.R;
+
 import android.content.Context;
+import android.content.res.TypedArray;
 import android.graphics.drawable.Drawable;
 import android.os.Bundle;
 import android.os.Handler;
@@ -29,8 +32,6 @@
 import android.widget.ProgressBar;
 import android.widget.TextView;
 
-import com.android.internal.R;
-
 import java.text.NumberFormat;
 
 /**
@@ -119,6 +120,9 @@
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         LayoutInflater inflater = LayoutInflater.from(mContext);
+        TypedArray a = mContext.obtainStyledAttributes(null,
+                com.android.internal.R.styleable.AlertDialog,
+                com.android.internal.R.attr.alertDialogStyle, 0);
         if (mProgressStyle == STYLE_HORIZONTAL) {
             
             /* Use a separate handler to update the text views as they
@@ -149,17 +153,22 @@
                     }
                 }
             };
-            View view = inflater.inflate(R.layout.alert_dialog_progress, null);
+            View view = inflater.inflate(a.getResourceId(
+                    com.android.internal.R.styleable.AlertDialog_horizontalProgressLayout,
+                    R.layout.alert_dialog_progress), null);
             mProgress = (ProgressBar) view.findViewById(R.id.progress);
             mProgressNumber = (TextView) view.findViewById(R.id.progress_number);
             mProgressPercent = (TextView) view.findViewById(R.id.progress_percent);
             setView(view);
         } else {
-            View view = inflater.inflate(R.layout.progress_dialog, null);
+            View view = inflater.inflate(a.getResourceId(
+                    com.android.internal.R.styleable.AlertDialog_progressLayout,
+                    R.layout.progress_dialog), null);
             mProgress = (ProgressBar) view.findViewById(R.id.progress);
             mMessageView = (TextView) view.findViewById(R.id.message);
             setView(view);
         }
+        a.recycle();
         if (mMax > 0) {
             setMax(mMax);
         }
diff --git a/core/java/android/bluetooth/BluetoothHealth.java b/core/java/android/bluetooth/BluetoothHealth.java
index 0a01dcf..9b2b8ca 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";
@@ -66,6 +81,20 @@
      */
     public static final int CHANNEL_TYPE_ANY = 12;
 
+    /** @hide */
+    public static final int HEALTH_OPERATION_SUCCESS = 6000;
+    /** @hide */
+    public static final int HEALTH_OPERATION_ERROR = 6001;
+    /** @hide */
+    public static final int HEALTH_OPERATION_INVALID_ARGS = 6002;
+    /** @hide */
+    public static final int HEALTH_OPERATION_GENERIC_FAILURE = 6003;
+    /** @hide */
+    public static final int HEALTH_OPERATION_NOT_FOUND = 6004;
+    /** @hide */
+    public static final int HEALTH_OPERATION_NOT_ALLOWED = 6005;
+
+
     /**
      * Register an application configuration that acts as a Health SINK.
      * This is the configuration that will be used to communicate with health devices
@@ -137,7 +166,6 @@
      *
      * @param config  The health app configuration
      * @return Success or failure.
-     * @hide
      */
     public boolean unregisterAppConfiguration(BluetoothHealthAppConfiguration config) {
         boolean result = false;
@@ -222,16 +250,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 +275,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 +329,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 +397,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 +419,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/SyncManager.java b/core/java/android/content/SyncManager.java
index ef6e131..9678d48 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
@@ -924,7 +924,7 @@
             mStartTime = SystemClock.elapsedRealtime();
             mTimeoutStartTime = mStartTime;
             mSyncWakeLock = mSyncHandler.getSyncWakeLock(
-                    mSyncOperation.account.type, mSyncOperation.authority);
+                    mSyncOperation.account, mSyncOperation.authority);
             mSyncWakeLock.setWorkSource(new WorkSource(syncAdapterUid));
             mSyncWakeLock.acquire();
         }
@@ -1365,7 +1365,7 @@
         public final SyncNotificationInfo mSyncNotificationInfo = new SyncNotificationInfo();
         private Long mAlarmScheduleTime = null;
         public final SyncTimeTracker mSyncTimeTracker = new SyncTimeTracker();
-        private final HashMap<Pair<String, String>, PowerManager.WakeLock> mWakeLocks =
+        private final HashMap<Pair<Account, String>, PowerManager.WakeLock> mWakeLocks =
                 Maps.newHashMap();
 
         private volatile CountDownLatch mReadyToRunLatch = new CountDownLatch(1);
@@ -1377,11 +1377,11 @@
             }
         }
 
-        private PowerManager.WakeLock getSyncWakeLock(String accountType, String authority) {
-            final Pair<String, String> wakeLockKey = Pair.create(accountType, authority);
+        private PowerManager.WakeLock getSyncWakeLock(Account account, String authority) {
+            final Pair<Account, String> wakeLockKey = Pair.create(account, authority);
             PowerManager.WakeLock wakeLock = mWakeLocks.get(wakeLockKey);
             if (wakeLock == null) {
-                final String name = SYNC_WAKE_LOCK_PREFIX + "_" + authority + "_" + accountType;
+                final String name = SYNC_WAKE_LOCK_PREFIX + "_" + authority + "_" + account;
                 wakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, name);
                 wakeLock.setReferenceCounted(false);
                 mWakeLocks.put(wakeLockKey, wakeLock);
diff --git a/core/java/android/net/MobileDataStateTracker.java b/core/java/android/net/MobileDataStateTracker.java
index 88abf1a..65c1bd5 100644
--- a/core/java/android/net/MobileDataStateTracker.java
+++ b/core/java/android/net/MobileDataStateTracker.java
@@ -195,6 +195,8 @@
                         intent.getStringExtra(Phone.STATE_KEY));
                 String reason = intent.getStringExtra(Phone.STATE_CHANGE_REASON_KEY);
                 String apnName = intent.getStringExtra(Phone.DATA_APN_KEY);
+                mNetworkInfo.setRoaming(intent.getBooleanExtra(Phone.DATA_NETWORK_ROAMING_KEY,
+                        false));
 
                 mNetworkInfo.setIsAvailable(!intent.getBooleanExtra(Phone.NETWORK_UNAVAILABLE_KEY,
                         false));
diff --git a/core/java/android/provider/ContactsContract.java b/core/java/android/provider/ContactsContract.java
index 5caea2b..ca1d0d9 100644
--- a/core/java/android/provider/ContactsContract.java
+++ b/core/java/android/provider/ContactsContract.java
@@ -4377,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";
@@ -7086,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>
diff --git a/core/java/android/provider/SyncStateContract.java b/core/java/android/provider/SyncStateContract.java
index e8177ca..f1189e4 100644
--- a/core/java/android/provider/SyncStateContract.java
+++ b/core/java/android/provider/SyncStateContract.java
@@ -74,6 +74,12 @@
                 Account account) throws RemoteException {
             Cursor c = provider.query(uri, DATA_PROJECTION, SELECT_BY_ACCOUNT,
                     new String[]{account.name, account.type}, null);
+
+            // Unable to query the provider
+            if (c == null) {
+                throw new RemoteException();
+            }
+
             try {
                 if (c.moveToNext()) {
                     return c.getBlob(c.getColumnIndexOrThrow(Columns.DATA));
@@ -123,6 +129,11 @@
                 Account account) throws RemoteException {
             Cursor c = provider.query(uri, DATA_PROJECTION, SELECT_BY_ACCOUNT,
                     new String[]{account.name, account.type}, null);
+
+            if (c == null) {
+                throw new RemoteException();
+            }
+
             try {
                 if (c.moveToNext()) {
                     long rowId = c.getLong(1);
diff --git a/core/java/android/server/BluetoothAdapterStateMachine.java b/core/java/android/server/BluetoothAdapterStateMachine.java
index 69fbca3..ac46ee2 100644
--- a/core/java/android/server/BluetoothAdapterStateMachine.java
+++ b/core/java/android/server/BluetoothAdapterStateMachine.java
@@ -109,6 +109,8 @@
     private static final int DEVICES_DISCONNECT_TIMEOUT = 104;
     // Prepare Bluetooth timeout happens
     private static final int PREPARE_BLUETOOTH_TIMEOUT = 105;
+    // Bluetooth Powerdown timeout happens
+    private static final int POWER_DOWN_TIMEOUT = 106;
 
     private Context mContext;
     private BluetoothService mBluetoothService;
@@ -129,6 +131,8 @@
 
     private static final int PREPARE_BLUETOOTH_TIMEOUT_TIME = 10000;
 
+    private static final int POWER_DOWN_TIMEOUT_TIME = 5000;
+
     BluetoothAdapterStateMachine(Context context, BluetoothService bluetoothService,
                                  BluetoothAdapter bluetoothAdapter) {
         super(TAG);
@@ -386,6 +390,11 @@
                     break;
                 case USER_TURN_OFF: // ignore
                     break;
+                case POWER_STATE_CHANGED:
+                    if ((Boolean) message.obj) {
+                        recoverStateMachine(TURN_HOT, null);
+                    }
+                    break;
                 default:
                     return NOT_HANDLED;
             }
@@ -420,14 +429,27 @@
                     }
                     break;
                 case POWER_STATE_CHANGED:
+                    removeMessages(POWER_DOWN_TIMEOUT);
                     if (!((Boolean) message.obj)) {
-                        transitionTo(mHotOff);
-                        finishSwitchingOff();
+                        if (mPublicState == BluetoothAdapter.STATE_TURNING_OFF) {
+                            transitionTo(mHotOff);
+                            finishSwitchingOff();
+                        }
+                    } else {
+                        if (mPublicState != BluetoothAdapter.STATE_TURNING_ON) {
+                            if (mContext.getResources().getBoolean
+                            (com.android.internal.R.bool.config_bluetooth_adapter_quick_switch)) {
+                                recoverStateMachine(TURN_HOT, null);
+                            } else {
+                                recoverStateMachine(TURN_COLD, null);
+                            }
+                        }
                     }
                     break;
                 case ALL_DEVICES_DISCONNECTED:
                     removeMessages(DEVICES_DISCONNECT_TIMEOUT);
                     mBluetoothService.switchConnectable(false);
+                    sendMessageDelayed(POWER_DOWN_TIMEOUT, POWER_DOWN_TIMEOUT_TIME);
                     break;
                 case DEVICES_DISCONNECT_TIMEOUT:
                     sendMessage(ALL_DEVICES_DISCONNECTED);
@@ -439,6 +461,17 @@
                         deferMessage(obtainMessage(TURN_HOT));
                     }
                     break;
+                case POWER_DOWN_TIMEOUT:
+                    transitionTo(mHotOff);
+                    finishSwitchingOff();
+                    // reset the hardware for error recovery
+                    Log.e(TAG, "Devices failed to power down, reseting...");
+                    deferMessage(obtainMessage(TURN_COLD));
+                    if (mContext.getResources().getBoolean
+                        (com.android.internal.R.bool.config_bluetooth_adapter_quick_switch)) {
+                        deferMessage(obtainMessage(TURN_HOT));
+                    }
+                    break;
                 case USER_TURN_ON:
                 case AIRPLANE_MODE_OFF:
                 case AIRPLANE_MODE_ON:
@@ -501,6 +534,7 @@
                                            DEVICES_DISCONNECT_TIMEOUT_TIME);
                     } else {
                         mBluetoothService.switchConnectable(false);
+                        sendMessageDelayed(POWER_DOWN_TIMEOUT, POWER_DOWN_TIMEOUT_TIME);
                     }
 
                     // we turn all the way to PowerOff with AIRPLANE_MODE_ON
@@ -520,6 +554,12 @@
                 case PER_PROCESS_TURN_OFF:
                     perProcessCallback(false, (IBluetoothStateChangeCallback)message.obj);
                     break;
+                case POWER_STATE_CHANGED:
+                    if ((Boolean) message.obj) {
+                        // reset the state machine and send it TURN_ON_CONTINUE message
+                        recoverStateMachine(USER_TURN_ON, false);
+                    }
+                    break;
                 default:
                     return NOT_HANDLED;
             }
@@ -540,7 +580,7 @@
 
             if (what == PER_PROCESS_TURN_ON) {
                 isTurningOn = true;
-            } else if (what == PER_PROCESS_TURN_OFF) {
+            } else if (what == USER_TURN_OFF) {
                 isTurningOn = false;
             } else {
                 Log.e(TAG, "enter PerProcessState: wrong msg: " + what);
@@ -568,12 +608,31 @@
                     }
                     break;
                 case POWER_STATE_CHANGED:
+                    removeMessages(POWER_DOWN_TIMEOUT);
                     if (!((Boolean) message.obj)) {
                         transitionTo(mHotOff);
                         if (!mContext.getResources().getBoolean
                             (com.android.internal.R.bool.config_bluetooth_adapter_quick_switch)) {
                             deferMessage(obtainMessage(TURN_COLD));
                         }
+                    } else {
+                        if (!isTurningOn) {
+                            recoverStateMachine(TURN_COLD, null);
+                            for (IBluetoothStateChangeCallback c:
+                                     mBluetoothService.getApplicationStateChangeCallbacks()) {
+                                perProcessCallback(false, c);
+                                deferMessage(obtainMessage(PER_PROCESS_TURN_ON, c));
+                            }
+                        }
+                    }
+                    break;
+                case POWER_DOWN_TIMEOUT:
+                    transitionTo(mHotOff);
+                    Log.e(TAG, "Power-down timed out, resetting...");
+                    deferMessage(obtainMessage(TURN_COLD));
+                    if (mContext.getResources().getBoolean
+                        (com.android.internal.R.bool.config_bluetooth_adapter_quick_switch)) {
+                        deferMessage(obtainMessage(TURN_HOT));
                     }
                     break;
                 case USER_TURN_ON:
@@ -616,10 +675,12 @@
                     perProcessCallback(false, (IBluetoothStateChangeCallback)message.obj);
                     if (mBluetoothService.isApplicationStateChangeTrackerEmpty()) {
                         mBluetoothService.switchConnectable(false);
+                        sendMessageDelayed(POWER_DOWN_TIMEOUT, POWER_DOWN_TIMEOUT_TIME);
                     }
                     break;
                 case AIRPLANE_MODE_ON:
                     mBluetoothService.switchConnectable(false);
+                    sendMessageDelayed(POWER_DOWN_TIMEOUT, POWER_DOWN_TIMEOUT_TIME);
                     allProcessesCallback(false);
                     // we turn all the way to PowerOff with AIRPLANE_MODE_ON
                     deferMessage(obtainMessage(AIRPLANE_MODE_ON));
@@ -699,6 +760,17 @@
         mContext.sendBroadcast(intent, BluetoothService.BLUETOOTH_PERM);
     }
 
+    /**
+     * bluetoothd has crashed and recovered, the adapter state machine has to
+     * reset itself and try to return to previous state
+     */
+    private void recoverStateMachine(int what, Object obj) {
+        Log.e(TAG, "Get unexpected power on event, reset with: " + what);
+        transitionTo(mHotOff);
+        deferMessage(obtainMessage(TURN_COLD));
+        deferMessage(obtainMessage(what, obj));
+    }
+
     private void dump(PrintWriter pw) {
         IState currentState = getCurrentState();
         if (currentState == mPowerOff) {
diff --git a/core/java/android/server/BluetoothEventLoop.java b/core/java/android/server/BluetoothEventLoop.java
index 6eff796..56da69d 100644
--- a/core/java/android/server/BluetoothEventLoop.java
+++ b/core/java/android/server/BluetoothEventLoop.java
@@ -20,6 +20,7 @@
 import android.bluetooth.BluetoothAdapter;
 import android.bluetooth.BluetoothClass;
 import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothHealth;
 import android.bluetooth.BluetoothInputDevice;
 import android.bluetooth.BluetoothPan;
 import android.bluetooth.BluetoothProfile;
@@ -59,9 +60,8 @@
     // from remote device when Android is in Suspend state.
     private PowerManager.WakeLock mWakeLock;
 
-    private static final int EVENT_RESTART_BLUETOOTH = 1;
-    private static final int EVENT_PAIRING_CONSENT_DELAYED_ACCEPT = 2;
-    private static final int EVENT_AGENT_CANCEL = 3;
+    private static final int EVENT_PAIRING_CONSENT_DELAYED_ACCEPT = 1;
+    private static final int EVENT_AGENT_CANCEL = 2;
 
     private static final int CREATE_DEVICE_ALREADY_EXISTS = 1;
     private static final int CREATE_DEVICE_SUCCESS = 0;
@@ -75,9 +75,6 @@
         public void handleMessage(Message msg) {
             String address = null;
             switch (msg.what) {
-            case EVENT_RESTART_BLUETOOTH:
-                mBluetoothService.restart();
-                break;
             case EVENT_PAIRING_CONSENT_DELAYED_ACCEPT:
                 address = (String)msg.obj;
                 if (address != null) {
@@ -375,9 +372,6 @@
         } else if (name.equals("Powered")) {
             mBluetoothState.sendMessage(BluetoothAdapterStateMachine.POWER_STATE_CHANGED,
                 propValues[1].equals("true") ? new Boolean(true) : new Boolean(false));
-            // bluetoothd has restarted, re-read all our properties.
-            // Note: bluez only sends this property change when it restarts.
-            onRestartRequired();
         } else if (name.equals("DiscoverableTimeout")) {
             adapterProperties.setProperty(name, propValues[1]);
         }
@@ -981,6 +975,22 @@
     }
 
     /**
+     * Called by native code for the async response to a Connect
+     * method call to org.bluez.Health
+     *
+     * @param chanCode The internal id of the channel
+     * @param result Result code of the operation.
+     */
+    private void onHealthDeviceConnectionResult(int chanCode, int result) {
+        log ("onHealthDeviceConnectionResult " + chanCode + " " + result);
+        // Success case gets handled by Property Change signal
+        if (result != BluetoothHealth.HEALTH_OPERATION_SUCCESS) {
+            mBluetoothService.onHealthDeviceChannelConnectionError(chanCode,
+                                                 BluetoothHealth.STATE_CHANNEL_DISCONNECTED);
+        }
+    }
+
+    /**
      * Called by native code on a DeviceDisconnected signal from
      * org.bluez.NetworkServer.
      *
@@ -1033,14 +1043,6 @@
         mBluetoothService.onHealthDeviceChannelChanged(devicePath, channelPath, exists);
     }
 
-    private void onRestartRequired() {
-        if (mBluetoothService.isEnabled()) {
-            Log.e(TAG, "*** A serious error occurred (did bluetoothd crash?) - " +
-                       "restarting Bluetooth ***");
-            mHandler.sendEmptyMessage(EVENT_RESTART_BLUETOOTH);
-        }
-    }
-
     private static void log(String msg) {
         Log.d(TAG, msg);
     }
diff --git a/core/java/android/server/BluetoothHealthProfileHandler.java b/core/java/android/server/BluetoothHealthProfileHandler.java
index 51c995e..2d80de4 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,16 @@
              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 + mChannelType;
+            return result;
+        }
     }
 
     private final Handler mHandler = new Handler() {
@@ -98,28 +109,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:
@@ -130,10 +151,11 @@
                 String channelType = getStringChannelType(chan.mChannelType);
 
                 if (!mBluetoothService.createChannelNative(deviceObjectPath, configPath,
-                          channelType)) {
+                          channelType, chan.hashCode())) {
                     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 +163,6 @@
     };
 
     private BluetoothHealthProfileHandler(Context context, BluetoothService service) {
-        mContext = context;
         mBluetoothService = service;
         mHealthAppConfigs = new HashMap<BluetoothHealthAppConfiguration, String>();
         mHealthChannels = new ArrayList<HealthChannel>();
@@ -205,7 +226,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 +256,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(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,
+                                                    chan.hashCode())) {
+            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(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 +324,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 +344,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 +374,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 {
@@ -343,24 +383,34 @@
         }
     }
 
+    /*package*/ void onHealthDeviceChannelConnectionError(int chanCode,
+                                                          int state) {
+        HealthChannel channel = findChannelById(chanCode);
+        if (channel == null) errorLog("No record of this channel:" + chanCode);
+
+        callHealthChannelCallback(channel.mConfig, channel.mDevice, channel.mState, state, null,
+                chanCode);
+    }
+
     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 +425,85 @@
         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) {
+            channel = findConnectingChannel(device, config);
+            if (channel == null) {
+               channel = new HealthChannel(device, config, null, false,
+                       channelPath);
+               channel.mState = BluetoothHealth.STATE_CHANNEL_DISCONNECTED;
+               mHealthChannels.add(channel);
+            }
+            channel.mChannelPath = channelPath;
 
-                 if (fd == null) {
-                     errorLog("Error obtaining fd for channel:" + channelPath);
-                     return;
-                 }
+            fd = mBluetoothService.getChannelFdNative(channelPath);
+            if (fd == null) {
+                errorLog("Error obtaining fd for channel:" + channelPath);
+                disconnectChannel(device, config, channel.hashCode());
+                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;
+            }
 
-                 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.mChannelFd = fd;
+            channel.mMainChannel = mainChannel;
+            prevState = channel.mState;
+            state = BluetoothHealth.STATE_CHANNEL_CONNECTED;
+        } else {
+            channel = findChannelByPath(device, channelPath);
+            if (channel == null) {
+                errorLog("Channel not found:" + config + ":" + channelPath);
+                return;
+            }
+            mHealthChannels.remove(channel);
 
-                 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 +515,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..00d3331 100755
--- a/core/java/android/server/BluetoothService.java
+++ b/core/java/android/server/BluetoothService.java
@@ -95,7 +95,6 @@
     private boolean mIsAirplaneSensitive;
     private boolean mIsAirplaneToggleable;
     private BluetoothAdapterStateMachine mBluetoothState;
-    private boolean mRestart = false;  // need to call enable() after disable()
     private int[] mAdapterSdpHandles;
     private ParcelUuid[] mAdapterUuids;
 
@@ -429,11 +428,6 @@
         } finally {
             Binder.restoreCallingIdentity(ident);
         }
-
-        if (mRestart) {
-            mRestart = false;
-            enable();
-        }
     }
 
     /**
@@ -456,10 +450,6 @@
         // the adapter property could be changed before event loop is stoped, clear it again
         mAdapterProperties.clear();
         disableNative();
-        if (mRestart) {
-            mRestart = false;
-            enable();
-        }
     }
 
     /** Bring up BT and persist BT on in settings */
@@ -500,17 +490,6 @@
         return true;
     }
 
-    /** Forcibly restart Bluetooth if it is on */
-    /* package */ synchronized void restart() {
-        if (getBluetoothStateInternal() != BluetoothAdapter.STATE_ON) {
-            return;
-        }
-        mRestart = true;
-        if (!disable(false)) {
-            mRestart = false;
-        }
-    }
-
     private final Handler mHandler = new Handler() {
         @Override
         public void handleMessage(Message msg) {
@@ -2243,11 +2222,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);
         }
     }
 
@@ -2276,6 +2255,14 @@
         }
     }
 
+    /*package*/ void onHealthDeviceChannelConnectionError(int channelCode,
+            int newState) {
+        synchronized(mBluetoothHealthProfileHandler) {
+            mBluetoothHealthProfileHandler.onHealthDeviceChannelConnectionError(channelCode,
+                                                                                newState);
+        }
+    }
+
     public int getHealthDeviceConnectionState(BluetoothDevice device) {
         mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM,
                 "Need BLUETOOTH permission");
@@ -2806,8 +2793,9 @@
             String channelType);
     native String registerHealthApplicationNative(int dataType, String role, String name);
     native boolean unregisterHealthApplicationNative(String path);
-    native boolean createChannelNative(String devicePath, String appPath, String channelType);
-    native boolean destroyChannelNative(String devicePath, String channelpath);
+    native boolean createChannelNative(String devicePath, String appPath, String channelType,
+                                       int code);
+    native boolean destroyChannelNative(String devicePath, String channelpath, int code);
     native String getMainChannelNative(String path);
     native String getChannelApplicationNative(String channelPath);
     native ParcelFileDescriptor getChannelFdNative(String channelPath);
diff --git a/core/java/android/service/wallpaper/WallpaperService.java b/core/java/android/service/wallpaper/WallpaperService.java
index 39f9367..713bb91 100644
--- a/core/java/android/service/wallpaper/WallpaperService.java
+++ b/core/java/android/service/wallpaper/WallpaperService.java
@@ -36,6 +36,7 @@
 import android.os.IBinder;
 import android.os.Looper;
 import android.os.Message;
+import android.os.PowerManager;
 import android.os.Process;
 import android.os.RemoteException;
 import android.util.Log;
@@ -716,7 +717,9 @@
             mSession = ViewRootImpl.getWindowSession(getMainLooper());
             
             mWindow.setSession(mSession);
-            
+
+            mScreenOn = ((PowerManager)getSystemService(Context.POWER_SERVICE)).isScreenOn();
+
             IntentFilter filter = new IntentFilter();
             filter.addAction(Intent.ACTION_SCREEN_ON);
             filter.addAction(Intent.ACTION_SCREEN_OFF);
diff --git a/core/java/android/text/style/SuggestionRangeSpan.java b/core/java/android/text/style/SuggestionRangeSpan.java
index a637b1c..2dbfc72 100644
--- a/core/java/android/text/style/SuggestionRangeSpan.java
+++ b/core/java/android/text/style/SuggestionRangeSpan.java
@@ -28,15 +28,11 @@
  * @hide
  */
 public class SuggestionRangeSpan extends CharacterStyle implements ParcelableSpan {
-    private final int mBackgroundColor;
+    private int mBackgroundColor;
 
-    @Override
-    public void updateDrawState(TextPaint tp) {
-        tp.bgColor = mBackgroundColor;
-    }
-
-    public SuggestionRangeSpan(int color) {
-        mBackgroundColor = color;
+    public SuggestionRangeSpan() {
+        // 0 is a fully transparent black. Has to be set using #setBackgroundColor
+        mBackgroundColor = 0;
     }
 
     public SuggestionRangeSpan(Parcel src) {
@@ -57,4 +53,13 @@
     public int getSpanTypeId() {
         return TextUtils.SUGGESTION_RANGE_SPAN;
     }
+
+    public void setBackgroundColor(int backgroundColor) {
+        mBackgroundColor = backgroundColor;
+    }
+
+    @Override
+    public void updateDrawState(TextPaint tp) {
+        tp.bgColor = mBackgroundColor;
+    }
 }
diff --git a/core/java/android/text/style/SuggestionSpan.java b/core/java/android/text/style/SuggestionSpan.java
index 693a7a9..51e9d7d 100644
--- a/core/java/android/text/style/SuggestionSpan.java
+++ b/core/java/android/text/style/SuggestionSpan.java
@@ -264,4 +264,16 @@
             tp.setUnderlineText(mEasyCorrectUnderlineColor, mEasyCorrectUnderlineThickness);
         }
     }
+
+    /**
+     * @return The color of the underline for that span, or 0 if there is no underline
+     *
+     * @hide
+     */
+    public int getUnderlineColor() {
+        // The order here should match what is used in updateDrawState
+        if ((mFlags & FLAG_MISSPELLED) != 0) return mMisspelledUnderlineColor;
+        if ((mFlags & FLAG_EASY_CORRECT) != 0) return mEasyCorrectUnderlineColor;
+        return 0;
+    }
 }
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index fd60813f..637f6466 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -27,6 +27,7 @@
 import android.graphics.Interpolator;
 import android.graphics.LinearGradient;
 import android.graphics.Matrix;
+import android.graphics.Matrix.ScaleToFit;
 import android.graphics.Paint;
 import android.graphics.PixelFormat;
 import android.graphics.Point;
@@ -68,6 +69,8 @@
 import android.view.inputmethod.InputMethodManager;
 import android.widget.ScrollBarDrawable;
 
+import static android.os.Build.VERSION_CODES.*;
+
 import com.android.internal.R;
 import com.android.internal.util.Predicate;
 import com.android.internal.view.menu.MenuBuilder;
@@ -584,7 +587,7 @@
  * @attr ref android.R.styleable#View_drawingCacheQuality
  * @attr ref android.R.styleable#View_duplicateParentState
  * @attr ref android.R.styleable#View_id
- * @attr ref android.R.styleable#View_fadingEdge
+ * @attr ref android.R.styleable#View_requiresFadingEdge
  * @attr ref android.R.styleable#View_fadingEdgeLength
  * @attr ref android.R.styleable#View_filterTouchesWhenObscured
  * @attr ref android.R.styleable#View_fitsSystemWindows
@@ -2001,64 +2004,133 @@
     @ViewDebug.ExportedProperty
     int mViewFlags;
 
-    /**
-     * The transform matrix for the View. This transform is calculated internally
-     * based on the rotation, scaleX, and scaleY properties. The identity matrix
-     * is used by default. Do *not* use this variable directly; instead call
-     * getMatrix(), which will automatically recalculate the matrix if necessary
-     * to get the correct matrix based on the latest rotation and scale properties.
-     */
-    private final Matrix mMatrix = new Matrix();
+    static class TransformationInfo {
+        /**
+         * The transform matrix for the View. This transform is calculated internally
+         * based on the rotation, scaleX, and scaleY properties. The identity matrix
+         * is used by default. Do *not* use this variable directly; instead call
+         * getMatrix(), which will automatically recalculate the matrix if necessary
+         * to get the correct matrix based on the latest rotation and scale properties.
+         */
+        private final Matrix mMatrix = new Matrix();
 
-    /**
-     * The transform matrix for the View. This transform is calculated internally
-     * based on the rotation, scaleX, and scaleY properties. The identity matrix
-     * is used by default. Do *not* use this variable directly; instead call
-     * getInverseMatrix(), which will automatically recalculate the matrix if necessary
-     * to get the correct matrix based on the latest rotation and scale properties.
-     */
-    private Matrix mInverseMatrix;
+        /**
+         * The transform matrix for the View. This transform is calculated internally
+         * based on the rotation, scaleX, and scaleY properties. The identity matrix
+         * is used by default. Do *not* use this variable directly; instead call
+         * getInverseMatrix(), which will automatically recalculate the matrix if necessary
+         * to get the correct matrix based on the latest rotation and scale properties.
+         */
+        private Matrix mInverseMatrix;
 
-    /**
-     * An internal variable that tracks whether we need to recalculate the
-     * transform matrix, based on whether the rotation or scaleX/Y properties
-     * have changed since the matrix was last calculated.
-     */
-    boolean mMatrixDirty = false;
+        /**
+         * An internal variable that tracks whether we need to recalculate the
+         * transform matrix, based on whether the rotation or scaleX/Y properties
+         * have changed since the matrix was last calculated.
+         */
+        boolean mMatrixDirty = false;
 
-    /**
-     * An internal variable that tracks whether we need to recalculate the
-     * transform matrix, based on whether the rotation or scaleX/Y properties
-     * have changed since the matrix was last calculated.
-     */
-    private boolean mInverseMatrixDirty = true;
+        /**
+         * An internal variable that tracks whether we need to recalculate the
+         * transform matrix, based on whether the rotation or scaleX/Y properties
+         * have changed since the matrix was last calculated.
+         */
+        private boolean mInverseMatrixDirty = true;
 
-    /**
-     * A variable that tracks whether we need to recalculate the
-     * transform matrix, based on whether the rotation or scaleX/Y properties
-     * have changed since the matrix was last calculated. This variable
-     * is only valid after a call to updateMatrix() or to a function that
-     * calls it such as getMatrix(), hasIdentityMatrix() and getInverseMatrix().
-     */
-    private boolean mMatrixIsIdentity = true;
+        /**
+         * A variable that tracks whether we need to recalculate the
+         * transform matrix, based on whether the rotation or scaleX/Y properties
+         * have changed since the matrix was last calculated. This variable
+         * is only valid after a call to updateMatrix() or to a function that
+         * calls it such as getMatrix(), hasIdentityMatrix() and getInverseMatrix().
+         */
+        private boolean mMatrixIsIdentity = true;
 
-    /**
-     * The Camera object is used to compute a 3D matrix when rotationX or rotationY are set.
-     */
-    private Camera mCamera = null;
+        /**
+         * The Camera object is used to compute a 3D matrix when rotationX or rotationY are set.
+         */
+        private Camera mCamera = null;
 
-    /**
-     * This matrix is used when computing the matrix for 3D rotations.
-     */
-    private Matrix matrix3D = null;
+        /**
+         * This matrix is used when computing the matrix for 3D rotations.
+         */
+        private Matrix matrix3D = null;
 
-    /**
-     * These prev values are used to recalculate a centered pivot point when necessary. The
-     * pivot point is only used in matrix operations (when rotation, scale, or translation are
-     * set), so thes values are only used then as well.
-     */
-    private int mPrevWidth = -1;
-    private int mPrevHeight = -1;
+        /**
+         * These prev values are used to recalculate a centered pivot point when necessary. The
+         * pivot point is only used in matrix operations (when rotation, scale, or translation are
+         * set), so thes values are only used then as well.
+         */
+        private int mPrevWidth = -1;
+        private int mPrevHeight = -1;
+        
+        /**
+         * The degrees rotation around the vertical axis through the pivot point.
+         */
+        @ViewDebug.ExportedProperty
+        float mRotationY = 0f;
+
+        /**
+         * The degrees rotation around the horizontal axis through the pivot point.
+         */
+        @ViewDebug.ExportedProperty
+        float mRotationX = 0f;
+
+        /**
+         * The degrees rotation around the pivot point.
+         */
+        @ViewDebug.ExportedProperty
+        float mRotation = 0f;
+
+        /**
+         * The amount of translation of the object away from its left property (post-layout).
+         */
+        @ViewDebug.ExportedProperty
+        float mTranslationX = 0f;
+
+        /**
+         * The amount of translation of the object away from its top property (post-layout).
+         */
+        @ViewDebug.ExportedProperty
+        float mTranslationY = 0f;
+
+        /**
+         * The amount of scale in the x direction around the pivot point. A
+         * value of 1 means no scaling is applied.
+         */
+        @ViewDebug.ExportedProperty
+        float mScaleX = 1f;
+
+        /**
+         * The amount of scale in the y direction around the pivot point. A
+         * value of 1 means no scaling is applied.
+         */
+        @ViewDebug.ExportedProperty
+        float mScaleY = 1f;
+
+        /**
+         * The amount of scale in the x direction around the pivot point. A
+         * value of 1 means no scaling is applied.
+         */
+        @ViewDebug.ExportedProperty
+        float mPivotX = 0f;
+
+        /**
+         * The amount of scale in the y direction around the pivot point. A
+         * value of 1 means no scaling is applied.
+         */
+        @ViewDebug.ExportedProperty
+        float mPivotY = 0f;
+
+        /**
+         * The opacity of the View. This is a value from 0 to 1, where 0 means
+         * completely transparent and 1 means completely opaque.
+         */
+        @ViewDebug.ExportedProperty
+        float mAlpha = 1f;
+    }
+
+    TransformationInfo mTransformationInfo;
 
     private boolean mLastIsOpaque;
 
@@ -2069,71 +2141,6 @@
     private static final float NONZERO_EPSILON = .001f;
 
     /**
-     * The degrees rotation around the vertical axis through the pivot point.
-     */
-    @ViewDebug.ExportedProperty
-    float mRotationY = 0f;
-
-    /**
-     * The degrees rotation around the horizontal axis through the pivot point.
-     */
-    @ViewDebug.ExportedProperty
-    float mRotationX = 0f;
-
-    /**
-     * The degrees rotation around the pivot point.
-     */
-    @ViewDebug.ExportedProperty
-    float mRotation = 0f;
-
-    /**
-     * The amount of translation of the object away from its left property (post-layout).
-     */
-    @ViewDebug.ExportedProperty
-    float mTranslationX = 0f;
-
-    /**
-     * The amount of translation of the object away from its top property (post-layout).
-     */
-    @ViewDebug.ExportedProperty
-    float mTranslationY = 0f;
-
-    /**
-     * The amount of scale in the x direction around the pivot point. A
-     * value of 1 means no scaling is applied.
-     */
-    @ViewDebug.ExportedProperty
-    float mScaleX = 1f;
-
-    /**
-     * The amount of scale in the y direction around the pivot point. A
-     * value of 1 means no scaling is applied.
-     */
-    @ViewDebug.ExportedProperty
-    float mScaleY = 1f;
-
-    /**
-     * The amount of scale in the x direction around the pivot point. A
-     * value of 1 means no scaling is applied.
-     */
-    @ViewDebug.ExportedProperty
-    float mPivotX = 0f;
-
-    /**
-     * The amount of scale in the y direction around the pivot point. A
-     * value of 1 means no scaling is applied.
-     */
-    @ViewDebug.ExportedProperty
-    float mPivotY = 0f;
-
-    /**
-     * The opacity of the View. This is a value from 0 to 1, where 0 means
-     * completely transparent and 1 means completely opaque.
-     */
-    @ViewDebug.ExportedProperty
-    float mAlpha = 1f;
-
-    /**
      * The distance in pixels from the left edge of this view's parent
      * to the left edge of this view.
      * {@hide}
@@ -2890,6 +2897,12 @@
                     }
                     break;
                 case R.styleable.View_fadingEdge:
+                    if (context.getApplicationInfo().targetSdkVersion >= ICE_CREAM_SANDWICH) {
+                        // Ignore the attribute starting with ICS
+                        break;
+                    }
+                    // With builds < ICS, fall through and apply fading edges
+                case R.styleable.View_requiresFadingEdge:
                     final int fadingEdge = a.getInt(attr, FADING_EDGE_NONE);
                     if (fadingEdge != FADING_EDGE_NONE) {
                         viewFlagValues |= fadingEdge;
@@ -6776,8 +6789,11 @@
      * @return The current transform matrix for the view
      */
     public Matrix getMatrix() {
-        updateMatrix();
-        return mMatrix;
+        if (mTransformationInfo != null) {
+            updateMatrix();
+            return mTransformationInfo.mMatrix;
+        }
+        return Matrix.IDENTITY_MATRIX;
     }
 
     /**
@@ -6797,49 +6813,63 @@
      * @return True if the transform matrix is the identity matrix, false otherwise.
      */
     final boolean hasIdentityMatrix() {
-        updateMatrix();
-        return mMatrixIsIdentity;
+        if (mTransformationInfo != null) {
+            updateMatrix();
+            return mTransformationInfo.mMatrixIsIdentity;
+        }
+        return true;
+    }
+
+    void ensureTransformationInfo() {
+        if (mTransformationInfo == null) {
+            mTransformationInfo = new TransformationInfo();
+        }
     }
 
     /**
      * Recomputes the transform matrix if necessary.
      */
     private void updateMatrix() {
-        if (mMatrixDirty) {
+        final TransformationInfo info = mTransformationInfo;
+        if (info == null) {
+            return;
+        }
+        if (info.mMatrixDirty) {
             // transform-related properties have changed since the last time someone
             // asked for the matrix; recalculate it with the current values
 
             // Figure out if we need to update the pivot point
             if ((mPrivateFlags & PIVOT_EXPLICITLY_SET) == 0) {
-                if ((mRight - mLeft) != mPrevWidth || (mBottom - mTop) != mPrevHeight) {
-                    mPrevWidth = mRight - mLeft;
-                    mPrevHeight = mBottom - mTop;
-                    mPivotX = mPrevWidth / 2f;
-                    mPivotY = mPrevHeight / 2f;
+                if ((mRight - mLeft) != info.mPrevWidth || (mBottom - mTop) != info.mPrevHeight) {
+                    info.mPrevWidth = mRight - mLeft;
+                    info.mPrevHeight = mBottom - mTop;
+                    info.mPivotX = info.mPrevWidth / 2f;
+                    info.mPivotY = info.mPrevHeight / 2f;
                 }
             }
-            mMatrix.reset();
-            if (!nonzero(mRotationX) && !nonzero(mRotationY)) {
-                mMatrix.setTranslate(mTranslationX, mTranslationY);
-                mMatrix.preRotate(mRotation, mPivotX, mPivotY);
-                mMatrix.preScale(mScaleX, mScaleY, mPivotX, mPivotY);
+            info.mMatrix.reset();
+            if (!nonzero(info.mRotationX) && !nonzero(info.mRotationY)) {
+                info.mMatrix.setTranslate(info.mTranslationX, info.mTranslationY);
+                info.mMatrix.preRotate(info.mRotation, info.mPivotX, info.mPivotY);
+                info.mMatrix.preScale(info.mScaleX, info.mScaleY, info.mPivotX, info.mPivotY);
             } else {
-                if (mCamera == null) {
-                    mCamera = new Camera();
-                    matrix3D = new Matrix();
+                if (info.mCamera == null) {
+                    info.mCamera = new Camera();
+                    info.matrix3D = new Matrix();
                 }
-                mCamera.save();
-                mMatrix.preScale(mScaleX, mScaleY, mPivotX, mPivotY);
-                mCamera.rotate(mRotationX, mRotationY, -mRotation);
-                mCamera.getMatrix(matrix3D);
-                matrix3D.preTranslate(-mPivotX, -mPivotY);
-                matrix3D.postTranslate(mPivotX + mTranslationX, mPivotY + mTranslationY);
-                mMatrix.postConcat(matrix3D);
-                mCamera.restore();
+                info.mCamera.save();
+                info.mMatrix.preScale(info.mScaleX, info.mScaleY, info.mPivotX, info.mPivotY);
+                info.mCamera.rotate(info.mRotationX, info.mRotationY, -info.mRotation);
+                info.mCamera.getMatrix(info.matrix3D);
+                info.matrix3D.preTranslate(-info.mPivotX, -info.mPivotY);
+                info.matrix3D.postTranslate(info.mPivotX + info.mTranslationX,
+                        info.mPivotY + info.mTranslationY);
+                info.mMatrix.postConcat(info.matrix3D);
+                info.mCamera.restore();
             }
-            mMatrixDirty = false;
-            mMatrixIsIdentity = mMatrix.isIdentity();
-            mInverseMatrixDirty = true;
+            info.mMatrixDirty = false;
+            info.mMatrixIsIdentity = info.mMatrix.isIdentity();
+            info.mInverseMatrixDirty = true;
         }
     }
 
@@ -6851,15 +6881,19 @@
      * @return The inverse of the current matrix of this view.
      */
     final Matrix getInverseMatrix() {
-        updateMatrix();
-        if (mInverseMatrixDirty) {
-            if (mInverseMatrix == null) {
-                mInverseMatrix = new Matrix();
+        final TransformationInfo info = mTransformationInfo;
+        if (info != null) {
+            updateMatrix();
+            if (info.mInverseMatrixDirty) {
+                if (info.mInverseMatrix == null) {
+                    info.mInverseMatrix = new Matrix();
+                }
+                info.mMatrix.invert(info.mInverseMatrix);
+                info.mInverseMatrixDirty = false;
             }
-            mMatrix.invert(mInverseMatrix);
-            mInverseMatrixDirty = false;
+            return info.mInverseMatrix;
         }
-        return mInverseMatrix;
+        return Matrix.IDENTITY_MATRIX;
     }
 
     /**
@@ -6905,14 +6939,16 @@
         invalidateParentCaches();
         invalidate(false);
 
+        ensureTransformationInfo();
         final float dpi = mResources.getDisplayMetrics().densityDpi;
-        if (mCamera == null) {
-            mCamera = new Camera();
-            matrix3D = new Matrix();
+        final TransformationInfo info = mTransformationInfo;
+        if (info.mCamera == null) {
+            info.mCamera = new Camera();
+            info.matrix3D = new Matrix();
         }
 
-        mCamera.setLocation(0.0f, 0.0f, -Math.abs(distance) / dpi);
-        mMatrixDirty = true;
+        info.mCamera.setLocation(0.0f, 0.0f, -Math.abs(distance) / dpi);
+        info.mMatrixDirty = true;
 
         invalidate(false);
     }
@@ -6927,7 +6963,7 @@
      * @return The degrees of rotation.
      */
     public float getRotation() {
-        return mRotation;
+        return mTransformationInfo != null ? mTransformationInfo.mRotation : 0;
     }
 
     /**
@@ -6945,12 +6981,14 @@
      * @attr ref android.R.styleable#View_rotation
      */
     public void setRotation(float rotation) {
-        if (mRotation != rotation) {
+        ensureTransformationInfo();
+        final TransformationInfo info = mTransformationInfo;
+        if (info.mRotation != rotation) {
             invalidateParentCaches();
             // Double-invalidation is necessary to capture view's old and new areas
             invalidate(false);
-            mRotation = rotation;
-            mMatrixDirty = true;
+            info.mRotation = rotation;
+            info.mMatrixDirty = true;
             mPrivateFlags |= DRAWN; // force another invalidation with the new orientation
             invalidate(false);
         }
@@ -6966,7 +7004,7 @@
      * @return The degrees of Y rotation.
      */
     public float getRotationY() {
-        return mRotationY;
+        return mTransformationInfo != null ? mTransformationInfo.mRotationY : 0;
     }
 
     /**
@@ -6989,12 +7027,14 @@
      * @attr ref android.R.styleable#View_rotationY
      */
     public void setRotationY(float rotationY) {
-        if (mRotationY != rotationY) {
+        ensureTransformationInfo();
+        final TransformationInfo info = mTransformationInfo;
+        if (info.mRotationY != rotationY) {
             invalidateParentCaches();
             // Double-invalidation is necessary to capture view's old and new areas
             invalidate(false);
-            mRotationY = rotationY;
-            mMatrixDirty = true;
+            info.mRotationY = rotationY;
+            info.mMatrixDirty = true;
             mPrivateFlags |= DRAWN; // force another invalidation with the new orientation
             invalidate(false);
         }
@@ -7010,7 +7050,7 @@
      * @return The degrees of X rotation.
      */
     public float getRotationX() {
-        return mRotationX;
+        return mTransformationInfo != null ? mTransformationInfo.mRotationX : 0;
     }
 
     /**
@@ -7033,12 +7073,14 @@
      * @attr ref android.R.styleable#View_rotationX
      */
     public void setRotationX(float rotationX) {
-        if (mRotationX != rotationX) {
+        ensureTransformationInfo();
+        final TransformationInfo info = mTransformationInfo;
+        if (info.mRotationX != rotationX) {
             invalidateParentCaches();
             // Double-invalidation is necessary to capture view's old and new areas
             invalidate(false);
-            mRotationX = rotationX;
-            mMatrixDirty = true;
+            info.mRotationX = rotationX;
+            info.mMatrixDirty = true;
             mPrivateFlags |= DRAWN; // force another invalidation with the new orientation
             invalidate(false);
         }
@@ -7055,7 +7097,7 @@
      * @return The scaling factor.
      */
     public float getScaleX() {
-        return mScaleX;
+        return mTransformationInfo != null ? mTransformationInfo.mScaleX : 1;
     }
 
     /**
@@ -7069,12 +7111,14 @@
      * @attr ref android.R.styleable#View_scaleX
      */
     public void setScaleX(float scaleX) {
-        if (mScaleX != scaleX) {
+        ensureTransformationInfo();
+        final TransformationInfo info = mTransformationInfo;
+        if (info.mScaleX != scaleX) {
             invalidateParentCaches();
             // Double-invalidation is necessary to capture view's old and new areas
             invalidate(false);
-            mScaleX = scaleX;
-            mMatrixDirty = true;
+            info.mScaleX = scaleX;
+            info.mMatrixDirty = true;
             mPrivateFlags |= DRAWN; // force another invalidation with the new orientation
             invalidate(false);
         }
@@ -7091,7 +7135,7 @@
      * @return The scaling factor.
      */
     public float getScaleY() {
-        return mScaleY;
+        return mTransformationInfo != null ? mTransformationInfo.mScaleY : 1;
     }
 
     /**
@@ -7105,12 +7149,14 @@
      * @attr ref android.R.styleable#View_scaleY
      */
     public void setScaleY(float scaleY) {
-        if (mScaleY != scaleY) {
+        ensureTransformationInfo();
+        final TransformationInfo info = mTransformationInfo;
+        if (info.mScaleY != scaleY) {
             invalidateParentCaches();
             // Double-invalidation is necessary to capture view's old and new areas
             invalidate(false);
-            mScaleY = scaleY;
-            mMatrixDirty = true;
+            info.mScaleY = scaleY;
+            info.mMatrixDirty = true;
             mPrivateFlags |= DRAWN; // force another invalidation with the new orientation
             invalidate(false);
         }
@@ -7127,7 +7173,7 @@
      * @return The x location of the pivot point.
      */
     public float getPivotX() {
-        return mPivotX;
+        return mTransformationInfo != null ? mTransformationInfo.mPivotX : 0;
     }
 
     /**
@@ -7146,13 +7192,15 @@
      * @attr ref android.R.styleable#View_transformPivotX
      */
     public void setPivotX(float pivotX) {
+        ensureTransformationInfo();
         mPrivateFlags |= PIVOT_EXPLICITLY_SET;
-        if (mPivotX != pivotX) {
+        final TransformationInfo info = mTransformationInfo;
+        if (info.mPivotX != pivotX) {
             invalidateParentCaches();
             // Double-invalidation is necessary to capture view's old and new areas
             invalidate(false);
-            mPivotX = pivotX;
-            mMatrixDirty = true;
+            info.mPivotX = pivotX;
+            info.mMatrixDirty = true;
             mPrivateFlags |= DRAWN; // force another invalidation with the new orientation
             invalidate(false);
         }
@@ -7169,7 +7217,7 @@
      * @return The y location of the pivot point.
      */
     public float getPivotY() {
-        return mPivotY;
+        return mTransformationInfo != null ? mTransformationInfo.mPivotY : 0;
     }
 
     /**
@@ -7187,13 +7235,15 @@
      * @attr ref android.R.styleable#View_transformPivotY
      */
     public void setPivotY(float pivotY) {
+        ensureTransformationInfo();
         mPrivateFlags |= PIVOT_EXPLICITLY_SET;
-        if (mPivotY != pivotY) {
+        final TransformationInfo info = mTransformationInfo;
+        if (info.mPivotY != pivotY) {
             invalidateParentCaches();
             // Double-invalidation is necessary to capture view's old and new areas
             invalidate(false);
-            mPivotY = pivotY;
-            mMatrixDirty = true;
+            info.mPivotY = pivotY;
+            info.mMatrixDirty = true;
             mPrivateFlags |= DRAWN; // force another invalidation with the new orientation
             invalidate(false);
         }
@@ -7207,7 +7257,7 @@
      * @return The opacity of the view.
      */
     public float getAlpha() {
-        return mAlpha;
+        return mTransformationInfo != null ? mTransformationInfo.mAlpha : 1;
     }
 
     /**
@@ -7226,7 +7276,8 @@
      * @attr ref android.R.styleable#View_alpha
      */
     public void setAlpha(float alpha) {
-        mAlpha = alpha;
+        ensureTransformationInfo();
+        mTransformationInfo.mAlpha = alpha;
         invalidateParentCaches();
         if (onSetAlpha((int) (alpha * 255))) {
             mPrivateFlags |= ALPHA_SET;
@@ -7248,7 +7299,8 @@
      * @return true if the View subclass handles alpha (the return value for onSetAlpha())
      */
     boolean setAlphaNoInvalidation(float alpha) {
-        mAlpha = alpha;
+        ensureTransformationInfo();
+        mTransformationInfo.mAlpha = alpha;
         boolean subclassHandlesAlpha = onSetAlpha((int) (alpha * 255));
         if (subclassHandlesAlpha) {
             mPrivateFlags |= ALPHA_SET;
@@ -7278,7 +7330,9 @@
     public final void setTop(int top) {
         if (top != mTop) {
             updateMatrix();
-            if (mMatrixIsIdentity) {
+            final boolean matrixIsIdentity = mTransformationInfo == null
+                    || mTransformationInfo.mMatrixIsIdentity;
+            if (matrixIsIdentity) {
                 if (mAttachInfo != null) {
                     int minTop;
                     int yLoc;
@@ -7303,10 +7357,10 @@
 
             onSizeChanged(width, mBottom - mTop, width, oldHeight);
 
-            if (!mMatrixIsIdentity) {
+            if (!matrixIsIdentity) {
                 if ((mPrivateFlags & PIVOT_EXPLICITLY_SET) == 0) {
                     // A change in dimension means an auto-centered pivot point changes, too
-                    mMatrixDirty = true;
+                    mTransformationInfo.mMatrixDirty = true;
                 }
                 mPrivateFlags |= DRAWN; // force another invalidation with the new orientation
                 invalidate(true);
@@ -7345,7 +7399,9 @@
     public final void setBottom(int bottom) {
         if (bottom != mBottom) {
             updateMatrix();
-            if (mMatrixIsIdentity) {
+            final boolean matrixIsIdentity = mTransformationInfo == null
+                    || mTransformationInfo.mMatrixIsIdentity;
+            if (matrixIsIdentity) {
                 if (mAttachInfo != null) {
                     int maxBottom;
                     if (bottom < mBottom) {
@@ -7367,10 +7423,10 @@
 
             onSizeChanged(width, mBottom - mTop, width, oldHeight);
 
-            if (!mMatrixIsIdentity) {
+            if (!matrixIsIdentity) {
                 if ((mPrivateFlags & PIVOT_EXPLICITLY_SET) == 0) {
                     // A change in dimension means an auto-centered pivot point changes, too
-                    mMatrixDirty = true;
+                    mTransformationInfo.mMatrixDirty = true;
                 }
                 mPrivateFlags |= DRAWN; // force another invalidation with the new orientation
                 invalidate(true);
@@ -7400,7 +7456,9 @@
     public final void setLeft(int left) {
         if (left != mLeft) {
             updateMatrix();
-            if (mMatrixIsIdentity) {
+            final boolean matrixIsIdentity = mTransformationInfo == null
+                    || mTransformationInfo.mMatrixIsIdentity;
+            if (matrixIsIdentity) {
                 if (mAttachInfo != null) {
                     int minLeft;
                     int xLoc;
@@ -7425,10 +7483,10 @@
 
             onSizeChanged(mRight - mLeft, height, oldWidth, height);
 
-            if (!mMatrixIsIdentity) {
+            if (!matrixIsIdentity) {
                 if ((mPrivateFlags & PIVOT_EXPLICITLY_SET) == 0) {
                     // A change in dimension means an auto-centered pivot point changes, too
-                    mMatrixDirty = true;
+                    mTransformationInfo.mMatrixDirty = true;
                 }
                 mPrivateFlags |= DRAWN; // force another invalidation with the new orientation
                 invalidate(true);
@@ -7458,7 +7516,9 @@
     public final void setRight(int right) {
         if (right != mRight) {
             updateMatrix();
-            if (mMatrixIsIdentity) {
+            final boolean matrixIsIdentity = mTransformationInfo == null
+                    || mTransformationInfo.mMatrixIsIdentity;
+            if (matrixIsIdentity) {
                 if (mAttachInfo != null) {
                     int maxRight;
                     if (right < mRight) {
@@ -7480,10 +7540,10 @@
 
             onSizeChanged(mRight - mLeft, height, oldWidth, height);
 
-            if (!mMatrixIsIdentity) {
+            if (!matrixIsIdentity) {
                 if ((mPrivateFlags & PIVOT_EXPLICITLY_SET) == 0) {
                     // A change in dimension means an auto-centered pivot point changes, too
-                    mMatrixDirty = true;
+                    mTransformationInfo.mMatrixDirty = true;
                 }
                 mPrivateFlags |= DRAWN; // force another invalidation with the new orientation
                 invalidate(true);
@@ -7501,7 +7561,7 @@
      * @return The visual x position of this view, in pixels.
      */
     public float getX() {
-        return mLeft + mTranslationX;
+        return mLeft + (mTransformationInfo != null ? mTransformationInfo.mTranslationX : 0);
     }
 
     /**
@@ -7523,7 +7583,7 @@
      * @return The visual y position of this view, in pixels.
      */
     public float getY() {
-        return mTop + mTranslationY;
+        return mTop + (mTransformationInfo != null ? mTransformationInfo.mTranslationY : 0);
     }
 
     /**
@@ -7546,7 +7606,7 @@
      * @return The horizontal position of this view relative to its left position, in pixels.
      */
     public float getTranslationX() {
-        return mTranslationX;
+        return mTransformationInfo != null ? mTransformationInfo.mTranslationX : 0;
     }
 
     /**
@@ -7560,12 +7620,14 @@
      * @attr ref android.R.styleable#View_translationX
      */
     public void setTranslationX(float translationX) {
-        if (mTranslationX != translationX) {
+        ensureTransformationInfo();
+        final TransformationInfo info = mTransformationInfo;
+        if (info.mTranslationX != translationX) {
             invalidateParentCaches();
             // Double-invalidation is necessary to capture view's old and new areas
             invalidate(false);
-            mTranslationX = translationX;
-            mMatrixDirty = true;
+            info.mTranslationX = translationX;
+            info.mMatrixDirty = true;
             mPrivateFlags |= DRAWN; // force another invalidation with the new orientation
             invalidate(false);
         }
@@ -7580,7 +7642,7 @@
      * in pixels.
      */
     public float getTranslationY() {
-        return mTranslationY;
+        return mTransformationInfo != null ? mTransformationInfo.mTranslationY : 0;
     }
 
     /**
@@ -7594,12 +7656,14 @@
      * @attr ref android.R.styleable#View_translationY
      */
     public void setTranslationY(float translationY) {
-        if (mTranslationY != translationY) {
+        ensureTransformationInfo();
+        final TransformationInfo info = mTransformationInfo;
+        if (info.mTranslationY != translationY) {
             invalidateParentCaches();
             // Double-invalidation is necessary to capture view's old and new areas
             invalidate(false);
-            mTranslationY = translationY;
-            mMatrixDirty = true;
+            info.mTranslationY = translationY;
+            info.mMatrixDirty = true;
             mPrivateFlags |= DRAWN; // force another invalidation with the new orientation
             invalidate(false);
         }
@@ -7609,63 +7673,78 @@
      * @hide
      */
     public void setFastTranslationX(float x) {
-        mTranslationX = x;
-        mMatrixDirty = true;
+        ensureTransformationInfo();
+        final TransformationInfo info = mTransformationInfo;
+        info.mTranslationX = x;
+        info.mMatrixDirty = true;
     }
 
     /**
      * @hide
      */
     public void setFastTranslationY(float y) {
-        mTranslationY = y;
-        mMatrixDirty = true;
+        ensureTransformationInfo();
+        final TransformationInfo info = mTransformationInfo;
+        info.mTranslationY = y;
+        info.mMatrixDirty = true;
     }
 
     /**
      * @hide
      */
     public void setFastX(float x) {
-        mTranslationX = x - mLeft;
-        mMatrixDirty = true;
+        ensureTransformationInfo();
+        final TransformationInfo info = mTransformationInfo;
+        info.mTranslationX = x - mLeft;
+        info.mMatrixDirty = true;
     }
 
     /**
      * @hide
      */
     public void setFastY(float y) {
-        mTranslationY = y - mTop;
-        mMatrixDirty = true;
+        ensureTransformationInfo();
+        final TransformationInfo info = mTransformationInfo;
+        info.mTranslationY = y - mTop;
+        info.mMatrixDirty = true;
     }
 
     /**
      * @hide
      */
     public void setFastScaleX(float x) {
-        mScaleX = x;
-        mMatrixDirty = true;
+        ensureTransformationInfo();
+        final TransformationInfo info = mTransformationInfo;
+        info.mScaleX = x;
+        info.mMatrixDirty = true;
     }
 
     /**
      * @hide
      */
     public void setFastScaleY(float y) {
-        mScaleY = y;
-        mMatrixDirty = true;
+        ensureTransformationInfo();
+        final TransformationInfo info = mTransformationInfo;
+        info.mScaleY = y;
+        info.mMatrixDirty = true;
     }
 
     /**
      * @hide
      */
     public void setFastAlpha(float alpha) {
-        mAlpha = alpha;
+        ensureTransformationInfo();
+        mTransformationInfo.mAlpha = alpha;
     }
 
     /**
      * @hide
      */
     public void setFastRotationY(float y) {
-        mRotationY = y;
-        mMatrixDirty = true;
+        ensureTransformationInfo();
+        final TransformationInfo info = mTransformationInfo;
+        info.mRotationY = y;
+        info.mMatrixDirty = true;
     }
 
     /**
@@ -7675,12 +7754,14 @@
      */
     public void getHitRect(Rect outRect) {
         updateMatrix();
-        if (mMatrixIsIdentity || mAttachInfo == null) {
+        final TransformationInfo info = mTransformationInfo;
+        if (info == null || info.mMatrixIsIdentity || mAttachInfo == null) {
             outRect.set(mLeft, mTop, mRight, mBottom);
         } else {
             final RectF tmpRect = mAttachInfo.mTmpTransformRect;
-            tmpRect.set(-mPivotX, -mPivotY, getWidth() - mPivotX, getHeight() - mPivotY);
-            mMatrix.mapRect(tmpRect);
+            tmpRect.set(-info.mPivotX, -info.mPivotY,
+                    getWidth() - info.mPivotX, getHeight() - info.mPivotY);
+            info.mMatrix.mapRect(tmpRect);
             outRect.set((int) tmpRect.left + mLeft, (int) tmpRect.top + mTop,
                     (int) tmpRect.right + mLeft, (int) tmpRect.bottom + mTop);
         }
@@ -7768,7 +7849,9 @@
     public void offsetTopAndBottom(int offset) {
         if (offset != 0) {
             updateMatrix();
-            if (mMatrixIsIdentity) {
+            final boolean matrixIsIdentity = mTransformationInfo == null
+                    || mTransformationInfo.mMatrixIsIdentity;
+            if (matrixIsIdentity) {
                 final ViewParent p = mParent;
                 if (p != null && mAttachInfo != null) {
                     final Rect r = mAttachInfo.mTmpInvalRect;
@@ -7794,7 +7877,7 @@
             mTop += offset;
             mBottom += offset;
 
-            if (!mMatrixIsIdentity) {
+            if (!matrixIsIdentity) {
                 mPrivateFlags |= DRAWN; // force another invalidation with the new orientation
                 invalidate(false);
             }
@@ -7810,7 +7893,9 @@
     public void offsetLeftAndRight(int offset) {
         if (offset != 0) {
             updateMatrix();
-            if (mMatrixIsIdentity) {
+            final boolean matrixIsIdentity = mTransformationInfo == null
+                    || mTransformationInfo.mMatrixIsIdentity;
+            if (matrixIsIdentity) {
                 final ViewParent p = mParent;
                 if (p != null && mAttachInfo != null) {
                     final Rect r = mAttachInfo.mTmpInvalRect;
@@ -7833,7 +7918,7 @@
             mLeft += offset;
             mRight += offset;
 
-            if (!mMatrixIsIdentity) {
+            if (!matrixIsIdentity) {
                 mPrivateFlags |= DRAWN; // force another invalidation with the new orientation
                 invalidate(false);
             }
@@ -8309,7 +8394,8 @@
     @ViewDebug.ExportedProperty(category = "drawing")
     public boolean isOpaque() {
         return (mPrivateFlags & OPAQUE_MASK) == OPAQUE_MASK &&
-                (mAlpha >= 1.0f - ViewConfiguration.ALPHA_THRESHOLD);
+                ((mTransformationInfo != null ? mTransformationInfo.mAlpha : 1)
+                        >= 1.0f - ViewConfiguration.ALPHA_THRESHOLD);
     }
 
     /**
@@ -8564,7 +8650,7 @@
      *         otherwise
      *
      * @see #setHorizontalFadingEdgeEnabled(boolean)
-     * @attr ref android.R.styleable#View_fadingEdge
+     * @attr ref android.R.styleable#View_requiresFadingEdge
      */
     public boolean isHorizontalFadingEdgeEnabled() {
         return (mViewFlags & FADING_EDGE_HORIZONTAL) == FADING_EDGE_HORIZONTAL;
@@ -8579,7 +8665,7 @@
      *                                    horizontally
      *
      * @see #isHorizontalFadingEdgeEnabled()
-     * @attr ref android.R.styleable#View_fadingEdge
+     * @attr ref android.R.styleable#View_requiresFadingEdge
      */
     public void setHorizontalFadingEdgeEnabled(boolean horizontalFadingEdgeEnabled) {
         if (isHorizontalFadingEdgeEnabled() != horizontalFadingEdgeEnabled) {
@@ -8599,7 +8685,7 @@
      *         otherwise
      *
      * @see #setVerticalFadingEdgeEnabled(boolean)
-     * @attr ref android.R.styleable#View_fadingEdge
+     * @attr ref android.R.styleable#View_requiresFadingEdge
      */
     public boolean isVerticalFadingEdgeEnabled() {
         return (mViewFlags & FADING_EDGE_VERTICAL) == FADING_EDGE_VERTICAL;
@@ -8614,7 +8700,7 @@
      *                                  vertically
      *
      * @see #isVerticalFadingEdgeEnabled()
-     * @attr ref android.R.styleable#View_fadingEdge
+     * @attr ref android.R.styleable#View_requiresFadingEdge
      */
     public void setVerticalFadingEdgeEnabled(boolean verticalFadingEdgeEnabled) {
         if (isVerticalFadingEdgeEnabled() != verticalFadingEdgeEnabled) {
@@ -9995,6 +10081,7 @@
             }
 
             final HardwareCanvas canvas = mDisplayList.start();
+            int restoreCount = 0;
             try {
                 int width = mRight - mLeft;
                 int height = mBottom - mTop;
@@ -10004,6 +10091,8 @@
                 canvas.onPreDraw(null);
 
                 computeScroll();
+
+                restoreCount = canvas.save();
                 canvas.translate(-mScrollX, -mScrollY);
                 mPrivateFlags |= DRAWN | DRAWING_CACHE_VALID;
                 mPrivateFlags &= ~DIRTY_MASK;
@@ -10015,6 +10104,7 @@
                     draw(canvas);
                 }
             } finally {
+                canvas.restoreToCount(restoreCount);
                 canvas.onPostDraw();
 
                 mDisplayList.end();
@@ -10950,7 +11040,9 @@
             if (sizeChanged) {
                 if ((mPrivateFlags & PIVOT_EXPLICITLY_SET) == 0) {
                     // A change in dimension means an auto-centered pivot point changes, too
-                    mMatrixDirty = true;
+                    if (mTransformationInfo != null) {
+                        mTransformationInfo.mMatrixDirty = true;
+                    }
                 }
                 onSizeChanged(newWidth, newHeight, oldWidth, oldHeight);
             }
@@ -11743,14 +11835,22 @@
                     + "two integers");
         }
 
-        location[0] = mLeft + (int) (mTranslationX + 0.5f);
-        location[1] = mTop + (int) (mTranslationY + 0.5f);
+        location[0] = mLeft;
+        location[1] = mTop;
+        if (mTransformationInfo != null) {
+            location[0] += (int) (mTransformationInfo.mTranslationX + 0.5f);
+            location[1] += (int) (mTransformationInfo.mTranslationY + 0.5f);
+        }
 
         ViewParent viewParent = mParent;
         while (viewParent instanceof View) {
             final View view = (View)viewParent;
-            location[0] += view.mLeft + (int) (view.mTranslationX + 0.5f) - view.mScrollX;
-            location[1] += view.mTop + (int) (view.mTranslationY + 0.5f) - view.mScrollY;
+            location[0] += view.mLeft - view.mScrollX;
+            location[1] += view.mTop - view.mScrollY;
+            if (view.mTransformationInfo != null) {
+                location[0] += (int) (view.mTransformationInfo.mTranslationX + 0.5f);
+                location[1] += (int) (view.mTransformationInfo.mTranslationY + 0.5f);
+            }
             viewParent = view.mParent;
         }
 
diff --git a/core/java/android/view/ViewPropertyAnimator.java b/core/java/android/view/ViewPropertyAnimator.java
index 6ed49ee..84dc7d8 100644
--- a/core/java/android/view/ViewPropertyAnimator.java
+++ b/core/java/android/view/ViewPropertyAnimator.java
@@ -51,7 +51,7 @@
      * The View whose properties are being animated by this class. This is set at
      * construction time.
      */
-    private View mView;
+    private final View mView;
 
     /**
      * The duration of the underlying Animator object. By default, we don't set the duration
@@ -225,6 +225,7 @@
      */
     ViewPropertyAnimator(View view) {
         mView = view;
+        view.ensureTransformationInfo();
     }
 
     /**
@@ -721,36 +722,37 @@
      * @param value The value to set the property to
      */
     private void setValue(int propertyConstant, float value) {
+        final View.TransformationInfo info = mView.mTransformationInfo;
         switch (propertyConstant) {
             case TRANSLATION_X:
-                mView.mTranslationX = value;
+                info.mTranslationX = value;
                 break;
             case TRANSLATION_Y:
-                mView.mTranslationY = value;
+                info.mTranslationY = value;
                 break;
             case ROTATION:
-                mView.mRotation = value;
+                info.mRotation = value;
                 break;
             case ROTATION_X:
-                mView.mRotationX = value;
+                info.mRotationX = value;
                 break;
             case ROTATION_Y:
-                mView.mRotationY = value;
+                info.mRotationY = value;
                 break;
             case SCALE_X:
-                mView.mScaleX = value;
+                info.mScaleX = value;
                 break;
             case SCALE_Y:
-                mView.mScaleY = value;
+                info.mScaleY = value;
                 break;
             case X:
-                mView.mTranslationX = value - mView.mLeft;
+                info.mTranslationX = value - mView.mLeft;
                 break;
             case Y:
-                mView.mTranslationY = value - mView.mTop;
+                info.mTranslationY = value - mView.mTop;
                 break;
             case ALPHA:
-                mView.mAlpha = value;
+                info.mAlpha = value;
                 break;
         }
     }
@@ -762,27 +764,28 @@
      * @return float The value of the named property
      */
     private float getValue(int propertyConstant) {
+        final View.TransformationInfo info = mView.mTransformationInfo;
         switch (propertyConstant) {
             case TRANSLATION_X:
-                return mView.mTranslationX;
+                return info.mTranslationX;
             case TRANSLATION_Y:
-                return mView.mTranslationY;
+                return info.mTranslationY;
             case ROTATION:
-                return mView.mRotation;
+                return info.mRotation;
             case ROTATION_X:
-                return mView.mRotationX;
+                return info.mRotationX;
             case ROTATION_Y:
-                return mView.mRotationY;
+                return info.mRotationY;
             case SCALE_X:
-                return mView.mScaleX;
+                return info.mScaleX;
             case SCALE_Y:
-                return mView.mScaleY;
+                return info.mScaleY;
             case X:
-                return mView.mLeft + mView.mTranslationX;
+                return mView.mLeft + info.mTranslationX;
             case Y:
-                return mView.mTop + mView.mTranslationY;
+                return mView.mTop + info.mTranslationY;
             case ALPHA:
-                return mView.mAlpha;
+                return info.mAlpha;
         }
         return 0;
     }
@@ -861,7 +864,7 @@
                 }
             }
             if ((propertyMask & TRANSFORM_MASK) != 0) {
-                mView.mMatrixDirty = true;
+                mView.mTransformationInfo.mMatrixDirty = true;
                 mView.mPrivateFlags |= View.DRAWN; // force another invalidation
             }
             // invalidate(false) in all cases except if alphaHandled gets set to true
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index 96c1512..17a516c 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -177,7 +177,14 @@
             @ViewDebug.IntToString(from = TYPE_SYSTEM_ERROR, to = "TYPE_SYSTEM_ERROR"),
             @ViewDebug.IntToString(from = TYPE_INPUT_METHOD, to = "TYPE_INPUT_METHOD"),
             @ViewDebug.IntToString(from = TYPE_INPUT_METHOD_DIALOG, to = "TYPE_INPUT_METHOD_DIALOG"),
+            @ViewDebug.IntToString(from = TYPE_WALLPAPER, to = "TYPE_WALLPAPER"),
+            @ViewDebug.IntToString(from = TYPE_STATUS_BAR_PANEL, to = "TYPE_STATUS_BAR_PANEL"),
             @ViewDebug.IntToString(from = TYPE_SECURE_SYSTEM_OVERLAY, to = "TYPE_SECURE_SYSTEM_OVERLAY"),
+            @ViewDebug.IntToString(from = TYPE_DRAG, to = "TYPE_DRAG"),
+            @ViewDebug.IntToString(from = TYPE_STATUS_BAR_SUB_PANEL, to = "TYPE_STATUS_BAR_SUB_PANEL"),
+            @ViewDebug.IntToString(from = TYPE_POINTER, to = "TYPE_POINTER"),
+            @ViewDebug.IntToString(from = TYPE_NAVIGATION_BAR, to = "TYPE_NAVIGATION_BAR"),
+            @ViewDebug.IntToString(from = TYPE_VOLUME_OVERLAY, to = "TYPE_VOLUME_OVERLAY"),
             @ViewDebug.IntToString(from = TYPE_BOOT_PROGRESS, to = "TYPE_BOOT_PROGRESS")
         })
         public int type;
diff --git a/core/java/android/view/inputmethod/InputMethodSubtype.java b/core/java/android/view/inputmethod/InputMethodSubtype.java
index 5670432..34c9c29 100644
--- a/core/java/android/view/inputmethod/InputMethodSubtype.java
+++ b/core/java/android/view/inputmethod/InputMethodSubtype.java
@@ -63,7 +63,7 @@
      */
     public InputMethodSubtype(int nameId, int iconId, String locale, String mode, String extraValue,
             boolean isAuxiliary) {
-        this(nameId, iconId, locale, mode, extraValue, false, false);
+        this(nameId, iconId, locale, mode, extraValue, isAuxiliary, false);
     }
 
     /**
diff --git a/core/java/android/webkit/BrowserFrame.java b/core/java/android/webkit/BrowserFrame.java
index 49b4f66..309857d 100644
--- a/core/java/android/webkit/BrowserFrame.java
+++ b/core/java/android/webkit/BrowserFrame.java
@@ -422,9 +422,9 @@
             final WebHistoryItem h = mCallbackProxy.getBackForwardList()
                     .getCurrentItem();
             if (h != null) {
-                String currentUrl = h.getUrl();
-                if (currentUrl != null) {
-                    mDatabase.setFormData(currentUrl, data);
+                String url = WebTextView.urlForAutoCompleteData(h.getUrl());
+                if (url != null) {
+                    mDatabase.setFormData(url, data);
                 }
             }
         }
diff --git a/core/java/android/webkit/HTML5VideoInline.java b/core/java/android/webkit/HTML5VideoInline.java
index 1b9a25e..97dc291 100644
--- a/core/java/android/webkit/HTML5VideoInline.java
+++ b/core/java/android/webkit/HTML5VideoInline.java
@@ -7,6 +7,7 @@
 import android.webkit.HTML5VideoViewProxy;
 import android.view.Surface;
 import android.opengl.GLES20;
+import android.os.PowerManager;
 
 /**
  * @hide This is only used by the browser
@@ -51,6 +52,7 @@
     public void prepareDataAndDisplayMode(HTML5VideoViewProxy proxy) {
         super.prepareDataAndDisplayMode(proxy);
         setFrameAvailableListener(proxy);
+        mPlayer.setWakeMode(proxy.getContext(), PowerManager.FULL_WAKE_LOCK);
     }
 
     // Pause the play and update the play/pause button
diff --git a/core/java/android/webkit/WebTextView.java b/core/java/android/webkit/WebTextView.java
index 2a79caa..217ad7c 100644
--- a/core/java/android/webkit/WebTextView.java
+++ b/core/java/android/webkit/WebTextView.java
@@ -60,6 +60,8 @@
 import android.widget.AutoCompleteTextView;
 import android.widget.TextView;
 
+import java.net.MalformedURLException;
+import java.net.URL;
 import java.util.ArrayList;
 
 import junit.framework.Assert;
@@ -1044,6 +1046,7 @@
                 break;
         }
         setHint(null);
+        setThreshold(1);
         if (single) {
             mWebView.requestLabel(mWebView.nativeFocusCandidateFramePointer(),
                     mNodePointer);
@@ -1077,4 +1080,16 @@
     /* package */ void setAutoFillProfileIsSet(boolean autoFillProfileIsSet) {
         mAutoFillProfileIsSet = autoFillProfileIsSet;
     }
+
+    static String urlForAutoCompleteData(String urlString) {
+        // Remove any fragment or query string.
+        URL url = null;
+        try {
+            url = new URL(urlString);
+        } catch (MalformedURLException e) {
+            Log.e(LOGTAG, "Unable to parse URL "+url);
+        }
+
+        return url != null ? url.getProtocol() + "://" + url.getHost() + url.getPath() : null;
+    }
 }
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 7ba93da0..47abbc2 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -4826,7 +4826,7 @@
         public RequestFormData(String name, String url, Message msg,
                 boolean autoFillable, boolean autoComplete) {
             mName = name;
-            mUrl = url;
+            mUrl = WebTextView.urlForAutoCompleteData(url);
             mUpdateMessage = msg;
             mAutoFillable = autoFillable;
             mAutoComplete = autoComplete;
diff --git a/core/java/android/widget/ActivityChooserModel.java b/core/java/android/widget/ActivityChooserModel.java
index 9fea506..bc44521 100644
--- a/core/java/android/widget/ActivityChooserModel.java
+++ b/core/java/android/widget/ActivityChooserModel.java
@@ -663,6 +663,17 @@
         }
     }
 
+    /**
+     * Gets the history size.
+     *
+     * @return The history size.
+     */
+    public int getHistorySize() {
+        synchronized (mInstanceLock) {
+            return mHistoricalRecords.size();
+        }
+    }
+
     @Override
     protected void finalize() throws Throwable {
         super.finalize();
diff --git a/core/java/android/widget/ActivityChooserView.java b/core/java/android/widget/ActivityChooserView.java
index fcc7938..312303d 100644
--- a/core/java/android/widget/ActivityChooserView.java
+++ b/core/java/android/widget/ActivityChooserView.java
@@ -28,6 +28,7 @@
 import android.util.AttributeSet;
 import android.view.LayoutInflater;
 import android.view.View;
+import android.view.View.MeasureSpec;
 import android.view.ViewGroup;
 import android.view.ViewTreeObserver;
 import android.view.ViewTreeObserver.OnGlobalLayoutListener;
@@ -76,6 +77,11 @@
     private final LinearLayout mActivityChooserContent;
 
     /**
+     * Stores the background drawable to allow hiding and latter showing.
+     */
+    private final Drawable mActivityChooserContentBackground;
+
+    /**
      * The expand activities action button;
      */
     private final FrameLayout mExpandActivityOverflowButton;
@@ -194,12 +200,15 @@
         Drawable expandActivityOverflowButtonDrawable = attributesArray.getDrawable(
                 R.styleable.ActivityChooserView_expandActivityOverflowButtonDrawable);
 
+        attributesArray.recycle();
+
         LayoutInflater inflater = LayoutInflater.from(mContext);
         inflater.inflate(R.layout.activity_chooser_view, this, true);
 
         mCallbacks = new Callbacks();
 
         mActivityChooserContent = (LinearLayout) findViewById(R.id.activity_chooser_view_content);
+        mActivityChooserContentBackground = mActivityChooserContent.getBackground();
 
         mDefaultActivityButton = (FrameLayout) findViewById(R.id.default_activity_button);
         mDefaultActivityButton.setOnClickListener(mCallbacks);
@@ -217,7 +226,7 @@
             @Override
             public void onChanged() {
                 super.onChanged();
-                updateButtons();
+                updateAppearance();
             }
         });
 
@@ -352,9 +361,16 @@
 
     @Override
     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
-        mActivityChooserContent.measure(widthMeasureSpec, heightMeasureSpec);
-        setMeasuredDimension(mActivityChooserContent.getMeasuredWidth(),
-                mActivityChooserContent.getMeasuredHeight());
+        View child = mActivityChooserContent;
+        // If the default action is not visible we want to be as tall as the
+        // ActionBar so if this widget is used in the latter it will look as
+        // a normal action button.
+        if (mDefaultActivityButton.getVisibility() != VISIBLE) {
+            heightMeasureSpec = MeasureSpec.makeMeasureSpec(MeasureSpec.getSize(heightMeasureSpec),
+                    MeasureSpec.EXACTLY);
+        }
+        measureChild(child, widthMeasureSpec, heightMeasureSpec);
+        setMeasuredDimension(child.getMeasuredWidth(), child.getMeasuredHeight());
     }
 
     @Override
@@ -367,11 +383,6 @@
         }
     }
 
-    @Override
-    protected void onDraw(Canvas canvas) {
-        mActivityChooserContent.onDraw(canvas);
-    }
-
     public ActivityChooserModel getDataModel() {
         return mAdapter.getDataModel();
     }
@@ -417,21 +428,29 @@
     /**
      * Updates the buttons state.
      */
-    private void updateButtons() {
+    private void updateAppearance() {
+        // Expand overflow button.
+        if (mAdapter.getCount() > 0) {
+            mExpandActivityOverflowButton.setEnabled(true);
+        } else {
+            mExpandActivityOverflowButton.setEnabled(false);
+        }
+        // Default activity button.
         final int activityCount = mAdapter.getActivityCount();
-        if (activityCount > 0) {
+        final int historySize = mAdapter.getHistorySize();
+        if (activityCount > 0 && historySize > 0) {
             mDefaultActivityButton.setVisibility(VISIBLE);
-            if (mAdapter.getCount() > 0) {
-                mExpandActivityOverflowButton.setEnabled(true);
-            } else {
-                mExpandActivityOverflowButton.setEnabled(false);
-            }
             ResolveInfo activity = mAdapter.getDefaultActivity();
             PackageManager packageManager = mContext.getPackageManager();
             mDefaultActivityButtonImage.setImageDrawable(activity.loadIcon(packageManager));
         } else {
-            mDefaultActivityButton.setVisibility(View.INVISIBLE);
-            mExpandActivityOverflowButton.setEnabled(false);
+            mDefaultActivityButton.setVisibility(View.GONE);
+        }
+        // Activity chooser content.
+        if (mDefaultActivityButton.getVisibility() == VISIBLE) {
+            mActivityChooserContent.setBackgroundDrawable(mActivityChooserContentBackground);
+        } else {
+            mActivityChooserContent.setBackgroundDrawable(null);
         }
     }
 
@@ -678,6 +697,10 @@
             return mDataModel.getActivityCount();
         }
 
+        public int getHistorySize() {
+            return mDataModel.getHistorySize();
+        }
+
         public int getMaxActivityCount() {
             return mMaxActivityCount;
         }
diff --git a/core/java/android/widget/DatePicker.java b/core/java/android/widget/DatePicker.java
index 3b67f44..5077be6 100644
--- a/core/java/android/widget/DatePicker.java
+++ b/core/java/android/widget/DatePicker.java
@@ -31,6 +31,7 @@
 import android.view.LayoutInflater;
 import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.AccessibilityManager;
+import android.view.inputmethod.EditorInfo;
 import android.widget.NumberPicker.OnValueChangeListener;
 
 import com.android.internal.R;
@@ -81,10 +82,10 @@
 
     private static final boolean DEFAULT_ENABLED_STATE = true;
 
-    private final NumberPicker mDaySpinner;
-
     private final LinearLayout mSpinners;
 
+    private final NumberPicker mDaySpinner;
+
     private final NumberPicker mMonthSpinner;
 
     private final NumberPicker mYearSpinner;
@@ -481,16 +482,20 @@
     private void reorderSpinners() {
         mSpinners.removeAllViews();
         char[] order = DateFormat.getDateFormatOrder(getContext());
-        for (int i = 0; i < order.length; i++) {
+        final int spinnerCount = order.length;
+        for (int i = 0; i < spinnerCount; i++) {
             switch (order[i]) {
                 case DateFormat.DATE:
                     mSpinners.addView(mDaySpinner);
+                    setImeOptions(mDaySpinner, spinnerCount, i);
                     break;
                 case DateFormat.MONTH:
                     mSpinners.addView(mMonthSpinner);
+                    setImeOptions(mMonthSpinner, spinnerCount, i);
                     break;
                 case DateFormat.YEAR:
                     mSpinners.addView(mYearSpinner);
+                    setImeOptions(mYearSpinner, spinnerCount, i);
                     break;
                 default:
                     throw new IllegalArgumentException();
@@ -669,6 +674,42 @@
     }
 
     /**
+     * Sets the IME options for a spinner based on its ordering.
+     *
+     * @param spinner The spinner.
+     * @param spinnerCount The total spinner count.
+     * @param spinnerIndex The index of the given spinner.
+     */
+    private void setImeOptions(NumberPicker spinner, int spinnerCount, int spinnerIndex) {
+        final int imeOptions;
+        if (spinnerIndex < spinnerCount - 1) {
+            imeOptions = EditorInfo.IME_ACTION_NEXT;
+        } else {
+            imeOptions = EditorInfo.IME_ACTION_DONE;
+        }
+        TextView input = (TextView) spinner.findViewById(R.id.numberpicker_input);
+        input.setImeOptions(imeOptions);
+    }
+
+    private void setContentDescriptions() {
+        // Day
+        String text = mContext.getString(R.string.date_picker_increment_day_button);
+        mDaySpinner.findViewById(R.id.increment).setContentDescription(text);
+        text = mContext.getString(R.string.date_picker_decrement_day_button);
+        mDaySpinner.findViewById(R.id.decrement).setContentDescription(text);
+        // Month
+        text = mContext.getString(R.string.date_picker_increment_month_button);
+        mMonthSpinner.findViewById(R.id.increment).setContentDescription(text);
+        text = mContext.getString(R.string.date_picker_decrement_month_button);
+        mMonthSpinner.findViewById(R.id.decrement).setContentDescription(text);
+        // Year
+        text = mContext.getString(R.string.date_picker_increment_year_button);
+        mYearSpinner.findViewById(R.id.increment).setContentDescription(text);
+        text = mContext.getString(R.string.date_picker_decrement_year_button);
+        mYearSpinner.findViewById(R.id.decrement).setContentDescription(text);
+    }
+
+    /**
      * Class for managing state storing/restoring.
      */
     private static class SavedState extends BaseSavedState {
@@ -720,22 +761,4 @@
             }
         };
     }
-
-    private void setContentDescriptions() {
-        // Day
-        String text = mContext.getString(R.string.date_picker_increment_day_button);
-        mDaySpinner.findViewById(R.id.increment).setContentDescription(text);
-        text = mContext.getString(R.string.date_picker_decrement_day_button);
-        mDaySpinner.findViewById(R.id.decrement).setContentDescription(text);
-        // Month
-        text = mContext.getString(R.string.date_picker_increment_month_button);
-        mMonthSpinner.findViewById(R.id.increment).setContentDescription(text);
-        text = mContext.getString(R.string.date_picker_decrement_month_button);
-        mMonthSpinner.findViewById(R.id.decrement).setContentDescription(text);
-        // Year
-        text = mContext.getString(R.string.date_picker_increment_year_button);
-        mYearSpinner.findViewById(R.id.increment).setContentDescription(text);
-        text = mContext.getString(R.string.date_picker_decrement_year_button);
-        mYearSpinner.findViewById(R.id.decrement).setContentDescription(text);
-    }
 }
diff --git a/core/java/android/widget/FrameLayout.java b/core/java/android/widget/FrameLayout.java
index 398a7eb..74a57b0 100644
--- a/core/java/android/widget/FrameLayout.java
+++ b/core/java/android/widget/FrameLayout.java
@@ -250,6 +250,27 @@
         return mForeground;
     }
 
+    private int getPaddingLeftWithForeground() {
+        return mForegroundInPadding ? Math.max(mPaddingLeft, mForegroundPaddingLeft) :
+            mPaddingLeft + mForegroundPaddingLeft;
+    }
+
+    private int getPaddingRightWithForeground() {
+        return mForegroundInPadding ? Math.max(mPaddingRight, mForegroundPaddingRight) :
+            mPaddingRight + mForegroundPaddingRight;
+    }
+
+    private int getPaddingTopWithForeground() {
+        return mForegroundInPadding ? Math.max(mPaddingTop, mForegroundPaddingTop) :
+            mPaddingTop + mForegroundPaddingTop;
+    }
+
+    private int getPaddingBottomWithForeground() {
+        return mForegroundInPadding ? Math.max(mPaddingBottom, mForegroundPaddingBottom) :
+            mPaddingBottom + mForegroundPaddingBottom;
+    }
+
+
     /**
      * {@inheritDoc}
      */
@@ -286,8 +307,8 @@
         }
 
         // Account for padding too
-        maxWidth += mPaddingLeft + mPaddingRight + mForegroundPaddingLeft + mForegroundPaddingRight;
-        maxHeight += mPaddingTop + mPaddingBottom + mForegroundPaddingTop + mForegroundPaddingBottom;
+        maxWidth += getPaddingLeftWithForeground() + getPaddingRightWithForeground();
+        maxHeight += getPaddingTopWithForeground() + getPaddingBottomWithForeground();
 
         // Check against our minimum height and width
         maxHeight = Math.max(maxHeight, getSuggestedMinimumHeight());
@@ -315,21 +336,25 @@
                 
                 if (lp.width == LayoutParams.MATCH_PARENT) {
                     childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(getMeasuredWidth() -
-                            mPaddingLeft - mPaddingRight - lp.leftMargin - lp.rightMargin,
+                            getPaddingLeftWithForeground() - getPaddingRightWithForeground() -
+                            lp.leftMargin - lp.rightMargin,
                             MeasureSpec.EXACTLY);
                 } else {
                     childWidthMeasureSpec = getChildMeasureSpec(widthMeasureSpec,
-                            mPaddingLeft + mPaddingRight + lp.leftMargin + lp.rightMargin,
+                            getPaddingLeftWithForeground() + getPaddingRightWithForeground() +
+                            lp.leftMargin + lp.rightMargin,
                             lp.width);
                 }
                 
                 if (lp.height == LayoutParams.MATCH_PARENT) {
                     childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(getMeasuredHeight() -
-                            mPaddingTop - mPaddingBottom - lp.topMargin - lp.bottomMargin,
+                            getPaddingTopWithForeground() - getPaddingBottomWithForeground() -
+                            lp.topMargin - lp.bottomMargin,
                             MeasureSpec.EXACTLY);
                 } else {
                     childHeightMeasureSpec = getChildMeasureSpec(heightMeasureSpec,
-                            mPaddingTop + mPaddingBottom + lp.topMargin + lp.bottomMargin,
+                            getPaddingTopWithForeground() + getPaddingBottomWithForeground() +
+                            lp.topMargin + lp.bottomMargin,
                             lp.height);
                 }
 
@@ -345,11 +370,11 @@
     protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
         final int count = getChildCount();
 
-        final int parentLeft = mPaddingLeft + mForegroundPaddingLeft;
-        final int parentRight = right - left - mPaddingRight - mForegroundPaddingRight;
+        final int parentLeft = getPaddingLeftWithForeground();
+        final int parentRight = right - left - getPaddingRightWithForeground();
 
-        final int parentTop = mPaddingTop + mForegroundPaddingTop;
-        final int parentBottom = bottom - top - mPaddingBottom - mForegroundPaddingBottom;
+        final int parentTop = getPaddingTopWithForeground();
+        final int parentBottom = bottom - top - getPaddingBottomWithForeground();
 
         mForegroundBoundsChanged = true;
         
diff --git a/core/java/android/widget/NumberPicker.java b/core/java/android/widget/NumberPicker.java
index 35e48f2..5345fa4 100644
--- a/core/java/android/widget/NumberPicker.java
+++ b/core/java/android/widget/NumberPicker.java
@@ -33,7 +33,6 @@
 import android.graphics.Rect;
 import android.graphics.Paint.Align;
 import android.graphics.drawable.Drawable;
-import android.os.SystemClock;
 import android.text.InputFilter;
 import android.text.InputType;
 import android.text.Spanned;
@@ -517,7 +516,10 @@
         mInputText = (EditText) findViewById(R.id.numberpicker_input);
         mInputText.setOnFocusChangeListener(new OnFocusChangeListener() {
             public void onFocusChange(View v, boolean hasFocus) {
-                if (!hasFocus) {
+                if (hasFocus) {
+                    mInputText.selectAll();
+                } else {
+                    mInputText.setSelection(0, 0);
                     validateInputTextView(v);
                 }
             }
@@ -687,7 +689,6 @@
                     InputMethodManager imm = (InputMethodManager) getContext().getSystemService(
                             Context.INPUT_METHOD_SERVICE);
                     imm.showSoftInput(mInputText, 0);
-                    mInputText.setSelection(0, mInputText.getText().length());
                     return true;
                 }
                 VelocityTracker velocityTracker = mVelocityTracker;
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index c61aad1..b948114 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -3726,19 +3726,19 @@
             // instead turning this into the normal enter key codes that an
             // app may be expecting.
             if (actionCode == EditorInfo.IME_ACTION_NEXT) {
-                View v = focusSearch(FOCUS_DOWN);
+                View v = focusSearch(FOCUS_FORWARD);
                 if (v != null) {
-                    if (!v.requestFocus(FOCUS_DOWN)) {
+                    if (!v.requestFocus(FOCUS_FORWARD)) {
                         throw new IllegalStateException("focus search returned a view " +
                                 "that wasn't able to take focus!");
                     }
                 }
                 return;
-                
+
             } else if (actionCode == EditorInfo.IME_ACTION_PREVIOUS) {
-                View v = focusSearch(FOCUS_UP);
+                View v = focusSearch(FOCUS_BACKWARD);
                 if (v != null) {
-                    if (!v.requestFocus(FOCUS_UP)) {
+                    if (!v.requestFocus(FOCUS_BACKWARD)) {
                         throw new IllegalStateException("focus search returned a view " +
                                 "that wasn't able to take focus!");
                     }
@@ -3750,10 +3750,11 @@
                 if (imm != null && imm.isActive(this)) {
                     imm.hideSoftInputFromWindow(getWindowToken(), 0);
                 }
+                clearFocus();
                 return;
             }
         }
-        
+
         Handler h = getHandler();
         if (h != null) {
             long eventTime = SystemClock.uptimeMillis();
@@ -4050,16 +4051,9 @@
         int wid = tv.getPaddingLeft() + tv.getPaddingRight();
         int ht = tv.getPaddingTop() + tv.getPaddingBottom();
 
-        /*
-         * Figure out how big the text would be if we laid it out to the
-         * full width of this view minus the border.
-         */
-        int cap = getWidth() - wid;
-        if (cap < 0) {
-            cap = 200; // We must not be measured yet -- setFrame() will fix it.
-        }
-
-        Layout l = new StaticLayout(text, tv.getPaint(), cap,
+        int defaultWidthInPixels = getResources().getDimensionPixelSize(
+                com.android.internal.R.dimen.textview_error_popup_default_width);
+        Layout l = new StaticLayout(text, tv.getPaint(), defaultWidthInPixels,
                                     Layout.Alignment.ALIGN_NORMAL, 1, 0, true);
         float max = 0;
         for (int i = 0; i < l.getLineCount(); i++) {
@@ -4067,7 +4061,8 @@
         }
 
         /*
-         * Now set the popup size to be big enough for the text plus the border.
+         * Now set the popup size to be big enough for the text plus the border capped
+         * to DEFAULT_MAX_POPUP_WIDTH
          */
         pop.setWidth(wid + (int) Math.ceil(max));
         pop.setHeight(ht + l.getHeight());
@@ -9564,8 +9559,8 @@
 
                 TextView.this.getPositionListener().removeSubscriber(SuggestionsPopupWindow.this);
 
-                if ((mText instanceof Editable) && mSuggestionRangeSpan != null) {
-                    ((Editable) mText).removeSpan(mSuggestionRangeSpan);
+                if ((mText instanceof Spannable)) {
+                    ((Spannable) mText).removeSpan(mSuggestionRangeSpan);
                 }
 
                 setCursorVisible(mCursorWasVisibleBeforeSuggestions);
@@ -9749,7 +9744,7 @@
         }
 
         private boolean updateSuggestions() {
-            Spannable spannable = (Spannable)TextView.this.mText;
+            Spannable spannable = (Spannable) TextView.this.mText;
             SuggestionSpan[] suggestionSpans = getSuggestionSpans();
 
             final int nbSpans = suggestionSpans.length;
@@ -9759,6 +9754,7 @@
             int spanUnionEnd = 0;
 
             SuggestionSpan misspelledSpan = null;
+            int underlineColor = 0;
 
             for (int spanIndex = 0; spanIndex < nbSpans; spanIndex++) {
                 SuggestionSpan suggestionSpan = suggestionSpans[spanIndex];
@@ -9771,6 +9767,9 @@
                     misspelledSpan = suggestionSpan;
                 }
 
+                // The first span dictates the background color of the highlighted text
+                if (spanIndex == 0) underlineColor = suggestionSpan.getUnderlineColor();
+
                 String[] suggestions = suggestionSpan.getSuggestions();
                 int nbSuggestions = suggestions.length;
                 for (int suggestionIndex = 0; suggestionIndex < nbSuggestions; suggestionIndex++) {
@@ -9813,9 +9812,17 @@
 
             if (mNumberOfSuggestions == 0) return false;
 
-            if (mSuggestionRangeSpan == null) mSuggestionRangeSpan =
-                    new SuggestionRangeSpan(mHighlightColor);
-            ((Editable) mText).setSpan(mSuggestionRangeSpan, spanUnionStart, spanUnionEnd,
+            if (mSuggestionRangeSpan == null) mSuggestionRangeSpan = new SuggestionRangeSpan();
+            if (underlineColor == 0) {
+                // Fallback on the default highlight color when the first span does not provide one
+                mSuggestionRangeSpan.setBackgroundColor(mHighlightColor);
+            } else {
+                final float BACKGROUND_TRANSPARENCY = 0.3f;
+                final int newAlpha = (int) (Color.alpha(underlineColor) * BACKGROUND_TRANSPARENCY);
+                mSuggestionRangeSpan.setBackgroundColor(
+                        (underlineColor & 0x00FFFFFF) + (newAlpha << 24));
+            }
+            spannable.setSpan(mSuggestionRangeSpan, spanUnionStart, spanUnionEnd,
                     Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
 
             mSuggestionsAdapter.notifyDataSetChanged();
@@ -9907,6 +9914,9 @@
                                     suggestionSpansFlags[i]);
                         }
                     }
+                    
+                    // Move cursor at the end of the replacement word
+                    Selection.setSelection(editable, spanEnd + lengthDifference);
                 }
             }
             hide();
diff --git a/core/java/android/widget/TimePicker.java b/core/java/android/widget/TimePicker.java
index 2350229..7865d50 100644
--- a/core/java/android/widget/TimePicker.java
+++ b/core/java/android/widget/TimePicker.java
@@ -16,8 +16,6 @@
 
 package android.widget;
 
-import com.android.internal.R;
-
 import android.annotation.Widget;
 import android.content.Context;
 import android.content.res.Configuration;
@@ -30,8 +28,11 @@
 import android.view.View;
 import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.AccessibilityManager;
+import android.view.inputmethod.EditorInfo;
 import android.widget.NumberPicker.OnValueChangeListener;
 
+import com.android.internal.R;
+
 import java.text.DateFormatSymbols;
 import java.util.Calendar;
 import java.util.Locale;
@@ -149,6 +150,8 @@
                 onTimeChanged();
             }
         });
+        EditText hourInput = (EditText) mHourSpinner.findViewById(R.id.numberpicker_input);
+        hourInput.setImeOptions(EditorInfo.IME_ACTION_NEXT);
 
         // divider (only for the new widget style)
         mDivider = (TextView) findViewById(R.id.divider);
@@ -184,6 +187,8 @@
                 onTimeChanged();
             }
         });
+        EditText minuteInput = (EditText) mMinuteSpinner.findViewById(R.id.numberpicker_input);
+        minuteInput.setImeOptions(EditorInfo.IME_ACTION_NEXT);
 
         /* Get the localized am/pm strings and use them in the spinner */
         mAmPmStrings = new DateFormatSymbols().getAmPmStrings();
@@ -214,6 +219,8 @@
                 }
             });
         }
+        EditText amPmInput = (EditText) mAmPmSpinner.findViewById(R.id.numberpicker_input);
+        amPmInput.setImeOptions(EditorInfo.IME_ACTION_DONE);
 
         // update controls to initial state
         updateHourControl();
diff --git a/core/java/com/android/internal/policy/IFaceLockCallback.aidl b/core/java/com/android/internal/policy/IFaceLockCallback.aidl
new file mode 100644
index 0000000..1eadc41
--- /dev/null
+++ b/core/java/com/android/internal/policy/IFaceLockCallback.aidl
@@ -0,0 +1,25 @@
+/*
+ * 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.internal.policy;
+
+import android.os.IBinder;
+
+/** {@hide} */
+oneway interface IFaceLockCallback {
+    void unlock();
+    void cancel();
+    void sleepDevice();
+}
diff --git a/core/java/com/android/internal/policy/IFaceLockInterface.aidl b/core/java/com/android/internal/policy/IFaceLockInterface.aidl
new file mode 100644
index 0000000..921b8c7
--- /dev/null
+++ b/core/java/com/android/internal/policy/IFaceLockInterface.aidl
@@ -0,0 +1,26 @@
+/*
+ * 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.internal.policy;
+
+import android.os.IBinder;
+import com.android.internal.policy.IFaceLockCallback;
+
+/** {@hide} */
+interface IFaceLockInterface {
+    void startUi(IBinder containingWindowToken, int x, int y, int width, int height);
+    void stopUi();
+    void registerCallback(IFaceLockCallback cb);
+}
diff --git a/core/java/com/android/internal/widget/AbsActionBarView.java b/core/java/com/android/internal/widget/AbsActionBarView.java
index df2f717..6c11288 100644
--- a/core/java/com/android/internal/widget/AbsActionBarView.java
+++ b/core/java/com/android/internal/widget/AbsActionBarView.java
@@ -15,6 +15,7 @@
  */
 package com.android.internal.widget;
 
+import com.android.internal.R;
 import com.android.internal.view.menu.ActionMenuPresenter;
 import com.android.internal.view.menu.ActionMenuView;
 
@@ -23,6 +24,8 @@
 import android.animation.ObjectAnimator;
 import android.animation.TimeInterpolator;
 import android.content.Context;
+import android.content.res.Configuration;
+import android.content.res.TypedArray;
 import android.util.AttributeSet;
 import android.view.View;
 import android.view.ViewGroup;
@@ -32,6 +35,7 @@
     protected ActionMenuView mMenuView;
     protected ActionMenuPresenter mActionMenuPresenter;
     protected ActionBarContainer mSplitView;
+    protected int mContentHeight;
 
     protected Animator mVisibilityAnim;
     protected final VisibilityAnimListener mVisAnimListener = new VisibilityAnimListener();
@@ -52,6 +56,30 @@
         super(context, attrs, defStyle);
     }
 
+    @Override
+    protected void onConfigurationChanged(Configuration newConfig) {
+        super.onConfigurationChanged(newConfig);
+
+        // Action bar can change size on configuration changes.
+        // Reread the desired height from the theme-specified style.
+        TypedArray a = getContext().obtainStyledAttributes(null, R.styleable.ActionBar,
+                com.android.internal.R.attr.actionBarStyle, 0);
+        setContentHeight(a.getLayoutDimension(R.styleable.ActionBar_height, 0));
+        a.recycle();
+        if (mActionMenuPresenter != null) {
+            mActionMenuPresenter.onConfigurationChanged(newConfig);
+        }
+    }
+
+    public void setContentHeight(int height) {
+        mContentHeight = height;
+        requestLayout();
+    }
+
+    public int getContentHeight() {
+        return mContentHeight;
+    }
+
     public void setSplitView(ActionBarContainer splitView) {
         mSplitView = splitView;
     }
diff --git a/core/java/com/android/internal/widget/ActionBarContextView.java b/core/java/com/android/internal/widget/ActionBarContextView.java
index 4fccc32..a631380 100644
--- a/core/java/com/android/internal/widget/ActionBarContextView.java
+++ b/core/java/com/android/internal/widget/ActionBarContextView.java
@@ -44,8 +44,6 @@
 public class ActionBarContextView extends AbsActionBarView implements AnimatorListener {
     private static final String TAG = "ActionBarContextView";
 
-    private int mContentHeight;
-    
     private CharSequence mTitle;
     private CharSequence mSubtitle;
 
@@ -94,15 +92,7 @@
         a.recycle();
     }
 
-    @Override
-    public void onConfigurationChanged(Configuration newConfig) {
-        super.onConfigurationChanged(newConfig);
-        if (mActionMenuPresenter != null) {
-            mActionMenuPresenter.onConfigurationChanged(newConfig);
-        }
-    }
-
-    public void setHeight(int height) {
+    public void setContentHeight(int height) {
         mContentHeight = height;
     }
 
diff --git a/core/java/com/android/internal/widget/ActionBarView.java b/core/java/com/android/internal/widget/ActionBarView.java
index 63b0274..7434df3a 100644
--- a/core/java/com/android/internal/widget/ActionBarView.java
+++ b/core/java/com/android/internal/widget/ActionBarView.java
@@ -84,8 +84,6 @@
 
     private static final int DEFAULT_CUSTOM_GRAVITY = Gravity.LEFT | Gravity.CENTER_VERTICAL;
     
-    private int mContentHeight;
-
     private int mNavigationMode;
     private int mDisplayOptions = -1;
     private CharSequence mTitle;
@@ -257,16 +255,6 @@
     protected void onConfigurationChanged(Configuration newConfig) {
         super.onConfigurationChanged(newConfig);
 
-        // Action bar can change size on configuration changes.
-        // Reread the desired height from the theme-specified style.
-        TypedArray a = getContext().obtainStyledAttributes(null, R.styleable.ActionBar,
-                com.android.internal.R.attr.actionBarStyle, 0);
-        setContentHeight(a.getLayoutDimension(R.styleable.ActionBar_height, 0));
-        a.recycle();
-        if (mActionMenuPresenter != null) {
-            mActionMenuPresenter.onConfigurationChanged(newConfig);
-        }
-
         mTitleView = null;
         mSubtitleView = null;
         mTitleUpView = null;
@@ -277,6 +265,13 @@
         if ((mDisplayOptions & ActionBar.DISPLAY_SHOW_TITLE) != 0) {
             initTitle();
         }
+
+        if (mTabScrollView != null && mIncludeTabs) {
+            ViewGroup.LayoutParams lp = mTabScrollView.getLayoutParams();
+            lp.width = LayoutParams.WRAP_CONTENT;
+            lp.height = LayoutParams.MATCH_PARENT;
+            mTabScrollView.setAllowCollapse(true);
+        }
     }
 
     @Override
@@ -304,15 +299,6 @@
         addView(mIndeterminateProgressView);
     }
 
-    public void setContentHeight(int height) {
-        mContentHeight = height;
-        requestLayout();
-    }
-
-    public int getContentHeight() {
-        return mContentHeight;
-    }
-
     public void setSplitActionBar(boolean splitActionBar) {
         if (mSplitActionBar != splitActionBar) {
             if (mMenuView != null) {
@@ -957,7 +943,7 @@
         }
 
         if (mContextView != null) {
-            mContextView.setHeight(getMeasuredHeight());
+            mContextView.setContentHeight(getMeasuredHeight());
         }
 
         if (mProgressView != null && mProgressView.getVisibility() != GONE) {
diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java
index 804f28a..4d828c4 100644
--- a/core/java/com/android/internal/widget/LockPatternUtils.java
+++ b/core/java/com/android/internal/widget/LockPatternUtils.java
@@ -106,8 +106,11 @@
     private final static String LOCKOUT_ATTEMPT_DEADLINE = "lockscreen.lockoutattemptdeadline";
     private final static String PATTERN_EVER_CHOSEN_KEY = "lockscreen.patterneverchosen";
     public final static String PASSWORD_TYPE_KEY = "lockscreen.password_type";
+    public static final String PASSWORD_TYPE_ALTERNATE_KEY = "lockscreen.password_type_alternate";
     private final static String LOCK_PASSWORD_SALT_KEY = "lockscreen.password_salt";
     private final static String DISABLE_LOCKSCREEN_KEY = "lockscreen.disabled";
+    public final static String LOCKSCREEN_BIOMETRIC_WEAK_FALLBACK
+            = "lockscreen.biometric_weak_fallback";
 
     private final static String PASSWORD_HISTORY_KEY = "lockscreen.passwordhistory";
 
@@ -373,6 +376,7 @@
         setLockPatternEnabled(false);
         saveLockPattern(null);
         setLong(PASSWORD_TYPE_KEY, DevicePolicyManager.PASSWORD_QUALITY_SOMETHING);
+        setLong(PASSWORD_TYPE_ALTERNATE_KEY, DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED);
     }
 
     /**
@@ -400,6 +404,15 @@
      * @param pattern The new pattern to save.
      */
     public void saveLockPattern(List<LockPatternView.Cell> pattern) {
+        this.saveLockPattern(pattern, false);
+    }
+
+    /**
+     * Save a lock pattern.
+     * @param pattern The new pattern to save.
+     * @param isFallback Specifies if this is a fallback to biometric weak
+     */
+    public void saveLockPattern(List<LockPatternView.Cell> pattern, boolean isFallback) {
         // Compute the hash
         final byte[] hash = LockPatternUtils.patternToHash(pattern);
         try {
@@ -417,7 +430,13 @@
             if (pattern != null) {
                 keyStore.password(patternToString(pattern));
                 setBoolean(PATTERN_EVER_CHOSEN_KEY, true);
-                setLong(PASSWORD_TYPE_KEY, DevicePolicyManager.PASSWORD_QUALITY_SOMETHING);
+                if (!isFallback) {
+                    setLong(PASSWORD_TYPE_KEY, DevicePolicyManager.PASSWORD_QUALITY_SOMETHING);
+                } else {
+                    setLong(PASSWORD_TYPE_KEY, DevicePolicyManager.PASSWORD_QUALITY_BIOMETRIC_WEAK);
+                    setLong(PASSWORD_TYPE_ALTERNATE_KEY,
+                            DevicePolicyManager.PASSWORD_QUALITY_SOMETHING);
+                }
                 dpm.setActivePasswordState(DevicePolicyManager.PASSWORD_QUALITY_SOMETHING, pattern
                         .size(), 0, 0, 0, 0, 0, 0);
             } else {
@@ -493,6 +512,18 @@
      * @param quality {@see DevicePolicyManager#getPasswordQuality(android.content.ComponentName)}
      */
     public void saveLockPassword(String password, int quality) {
+        this.saveLockPassword(password, quality, false);
+    }
+
+    /**
+     * Save a lock password.  Does not ensure that the password is as good
+     * as the requested mode, but will adjust the mode to be as good as the
+     * pattern.
+     * @param password The password to save
+     * @param quality {@see DevicePolicyManager#getPasswordQuality(android.content.ComponentName)}
+     * @param isFallback Specifies if this is a fallback to biometric weak
+     */
+    public void saveLockPassword(String password, int quality, boolean isFallback) {
         // Compute the hash
         final byte[] hash = passwordToHash(password);
         try {
@@ -515,7 +546,12 @@
                 keyStore.password(password);
 
                 int computedQuality = computePasswordQuality(password);
-                setLong(PASSWORD_TYPE_KEY, Math.max(quality, computedQuality));
+                if (!isFallback) {
+                    setLong(PASSWORD_TYPE_KEY, Math.max(quality, computedQuality));
+                } else {
+                    setLong(PASSWORD_TYPE_KEY, DevicePolicyManager.PASSWORD_QUALITY_BIOMETRIC_WEAK);
+                    setLong(PASSWORD_TYPE_ALTERNATE_KEY, Math.max(quality, computedQuality));
+                }
                 if (computedQuality != DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED) {
                     int letters = 0;
                     int uppercase = 0;
@@ -590,7 +626,22 @@
      * @return stored password quality
      */
     public int getKeyguardStoredPasswordQuality() {
-        return (int) getLong(PASSWORD_TYPE_KEY, DevicePolicyManager.PASSWORD_QUALITY_SOMETHING);
+        int quality =
+                (int) getLong(PASSWORD_TYPE_KEY, DevicePolicyManager.PASSWORD_QUALITY_SOMETHING);
+        // If the user has chosen to use weak biometric sensor, then return the backup locking
+        // method and treat biometric as a special case.
+        if (quality == DevicePolicyManager.PASSWORD_QUALITY_BIOMETRIC_WEAK) {
+            quality =
+                (int) getLong(PASSWORD_TYPE_ALTERNATE_KEY,
+                        DevicePolicyManager.PASSWORD_QUALITY_SOMETHING);
+        }
+        return quality;
+    }
+
+    public boolean usingBiometricWeak() {
+        int quality =
+                (int) getLong(PASSWORD_TYPE_KEY, DevicePolicyManager.PASSWORD_QUALITY_SOMETHING);
+        return quality == DevicePolicyManager.PASSWORD_QUALITY_BIOMETRIC_WEAK;
     }
 
     /**
@@ -726,6 +777,15 @@
     }
 
     /**
+     * @return Whether biometric weak lock is enabled.
+     */
+    public boolean isBiometricEnabled() {
+        // TODO: check if it's installed
+        return getLong(PASSWORD_TYPE_KEY, DevicePolicyManager.PASSWORD_QUALITY_SOMETHING)
+                == DevicePolicyManager.PASSWORD_QUALITY_BIOMETRIC_WEAK;
+    }
+
+    /**
      * Set whether the lock pattern is enabled.
      */
     public void setLockPatternEnabled(boolean enabled) {
@@ -863,7 +923,8 @@
                 || mode == DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC
                 || mode == DevicePolicyManager.PASSWORD_QUALITY_COMPLEX;
         final boolean secure = isPattern && isLockPatternEnabled() && savedPatternExists()
-                || isPassword && savedPasswordExists();
+                || isPassword && savedPasswordExists()
+                || usingBiometricWeak() && isBiometricEnabled();
         return secure;
     }
 
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_bluetooth_common.h b/core/jni/android_bluetooth_common.h
index 2f5fd5a..1f4da3a 100644
--- a/core/jni/android_bluetooth_common.h
+++ b/core/jni/android_bluetooth_common.h
@@ -202,6 +202,13 @@
 #define INPUT_OPERATION_GENERIC_FAILURE        5003
 #define INPUT_OPERATION_SUCCESS                5004
 
+#define HEALTH_OPERATION_SUCCESS               6000
+#define HEALTH_OPERATION_ERROR                 6001
+#define HEALTH_OPERATION_INVALID_ARGS          6002
+#define HEALTH_OPERATION_GENERIC_FAILURE       6003
+#define HEALTH_OPERATION_NOT_FOUND             6004
+#define HEALTH_OPERATION_NOT_ALLOWED           6005
+
 #endif
 } /* namespace android */
 
diff --git a/core/jni/android_server_BluetoothEventLoop.cpp b/core/jni/android_server_BluetoothEventLoop.cpp
index eee256a..0335ce7 100644
--- a/core/jni/android_server_BluetoothEventLoop.cpp
+++ b/core/jni/android_server_BluetoothEventLoop.cpp
@@ -74,6 +74,7 @@
 static jmethodID method_onPanDeviceConnectionResult;
 static jmethodID method_onHealthDevicePropertyChanged;
 static jmethodID method_onHealthDeviceChannelChanged;
+static jmethodID method_onHealthDeviceConnectionResult;
 
 typedef event_loop_native_data_t native_data_t;
 
@@ -141,6 +142,9 @@
                                                "(Ljava/lang/String;[Ljava/lang/String;)V");
     method_onPanDeviceConnectionResult = env->GetMethodID(clazz, "onPanDeviceConnectionResult",
                                                "(Ljava/lang/String;I)V");
+    method_onHealthDeviceConnectionResult = env->GetMethodID(clazz,
+                                                             "onHealthDeviceConnectionResult",
+                                                             "(II)V");
     method_onHealthDevicePropertyChanged = env->GetMethodID(clazz, "onHealthDevicePropertyChanged",
                                                "(Ljava/lang/String;[Ljava/lang/String;)V");
     method_onHealthDeviceChannelChanged = env->GetMethodID(clazz, "onHealthDeviceChannelChanged",
@@ -1533,6 +1537,39 @@
     free(user);
 }
 
+void onHealthDeviceConnectionResult(DBusMessage *msg, void *user, void *n) {
+    LOGV("%s", __FUNCTION__);
+
+    native_data_t *nat = (native_data_t *)n;
+    DBusError err;
+    dbus_error_init(&err);
+    JNIEnv *env;
+    nat->vm->GetEnv((void**)&env, nat->envVer);
+
+    jint result = HEALTH_OPERATION_SUCCESS;
+    if (dbus_set_error_from_message(&err, msg)) {
+        if (!strcmp(err.name, BLUEZ_ERROR_IFC ".InvalidArgs")) {
+            result = HEALTH_OPERATION_INVALID_ARGS;
+        } else if (!strcmp(err.name, BLUEZ_ERROR_IFC ".HealthError")) {
+            result = HEALTH_OPERATION_ERROR;
+        } else if (!strcmp(err.name, BLUEZ_ERROR_IFC ".NotFound")) {
+            result = HEALTH_OPERATION_NOT_FOUND;
+        } else if (!strcmp(err.name, BLUEZ_ERROR_IFC ".NotAllowed")) {
+            result = HEALTH_OPERATION_NOT_ALLOWED;
+        } else {
+            result = HEALTH_OPERATION_GENERIC_FAILURE;
+        }
+        LOG_AND_FREE_DBUS_ERROR(&err);
+    }
+
+    LOGV("... Health Device Code = %d, result = %d", code, result);
+    jint code = *(int *) user;
+    env->CallVoidMethod(nat->me,
+                        method_onHealthDeviceConnectionResult,
+                        code,
+                        result);
+    free(user);
+}
 #endif
 
 static JNINativeMethod sMethods[] = {
diff --git a/core/jni/android_server_BluetoothService.cpp b/core/jni/android_server_BluetoothService.cpp
index 819449a..a49c918 100644
--- a/core/jni/android_server_BluetoothService.cpp
+++ b/core/jni/android_server_BluetoothService.cpp
@@ -78,8 +78,8 @@
 void onDiscoverServicesResult(DBusMessage *msg, void *user, void *nat);
 void onCreateDeviceResult(DBusMessage *msg, void *user, void *nat);
 void onInputDeviceConnectionResult(DBusMessage *msg, void *user, void *nat);
-void onConnectPanResult(DBusMessage *msg, void *user, void *n);
 void onPanDeviceConnectionResult(DBusMessage *msg, void *user, void *nat);
+void onHealthDeviceConnectionResult(DBusMessage *msg, void *user, void *nat);
 
 
 /** Get native data stored in the opaque (Java code maintained) pointer mNativeData
@@ -1450,79 +1450,70 @@
 }
 
 static jboolean createChannelNative(JNIEnv *env, jobject object,
-                                       jstring devicePath, jstring appPath, jstring config) {
+                                       jstring devicePath, jstring appPath, jstring config,
+                                       jint code) {
     LOGV("%s", __FUNCTION__);
-    jboolean result = JNI_FALSE;
 #ifdef HAVE_BLUETOOTH
     native_data_t *nat = get_native_data(env, object);
+    jobject eventLoop = env->GetObjectField(object, field_mEventLoop);
+    struct event_loop_native_data_t *eventLoopNat =
+            get_EventLoop_native_data(env, eventLoop);
 
-    if (nat) {
-        DBusError err;
-        dbus_error_init(&err);
-
+    if (nat && eventLoopNat) {
         const char *c_device_path = env->GetStringUTFChars(devicePath, NULL);
         const char *c_app_path = env->GetStringUTFChars(appPath, NULL);
         const char *c_config = env->GetStringUTFChars(config, NULL);
+        int *data = (int *) malloc(sizeof(int));
+        if (data == NULL) return JNI_FALSE;
 
-        DBusMessage *reply  = dbus_func_args(env, nat->conn,
-                                             c_device_path,
-                                             DBUS_HEALTH_DEVICE_IFACE,
-                                             "CreateChannel",
-                                             DBUS_TYPE_OBJECT_PATH, &c_app_path,
-                                             DBUS_TYPE_STRING, &c_config,
-                                             DBUS_TYPE_INVALID);
+        *data = code;
+        bool ret = dbus_func_args_async(env, nat->conn, -1, onHealthDeviceConnectionResult,
+                                        data, eventLoopNat, c_device_path,
+                                        DBUS_HEALTH_DEVICE_IFACE, "CreateChannel",
+                                        DBUS_TYPE_OBJECT_PATH, &c_app_path,
+                                        DBUS_TYPE_STRING, &c_config,
+                                        DBUS_TYPE_INVALID);
 
 
         env->ReleaseStringUTFChars(devicePath, c_device_path);
         env->ReleaseStringUTFChars(appPath, c_app_path);
         env->ReleaseStringUTFChars(config, c_config);
 
-        if (!reply) {
-            if (dbus_error_is_set(&err)) {
-                LOG_AND_FREE_DBUS_ERROR(&err);
-            }
-        } else {
-            result = JNI_TRUE;
-        }
+        return ret ? JNI_TRUE : JNI_FALSE;
     }
 #endif
-    return result;
+    return JNI_FALSE;
 }
 
 static jboolean destroyChannelNative(JNIEnv *env, jobject object, jstring devicePath,
-                                     jstring channelPath) {
+                                     jstring channelPath, jint code) {
     LOGE("%s", __FUNCTION__);
-    jboolean result = JNI_FALSE;
 #ifdef HAVE_BLUETOOTH
     native_data_t *nat = get_native_data(env, object);
+    jobject eventLoop = env->GetObjectField(object, field_mEventLoop);
+    struct event_loop_native_data_t *eventLoopNat =
+            get_EventLoop_native_data(env, eventLoop);
 
-    if (nat) {
-        DBusError err;
-        dbus_error_init(&err);
-
+    if (nat && eventLoopNat) {
         const char *c_device_path = env->GetStringUTFChars(devicePath, NULL);
         const char *c_channel_path = env->GetStringUTFChars(channelPath, NULL);
+        int *data = (int *) malloc(sizeof(int));
+        if (data == NULL) return JNI_FALSE;
 
-        DBusMessage *reply = dbus_func_args(env, nat->conn,
-                                            c_device_path,
-                                            DBUS_HEALTH_DEVICE_IFACE,
-                                            "DestroyChannel",
-                                            DBUS_TYPE_OBJECT_PATH, &c_channel_path,
-                                            DBUS_TYPE_INVALID);
+        *data = code;
+        bool ret = dbus_func_args_async(env, nat->conn, -1, onHealthDeviceConnectionResult,
+                                        data, eventLoopNat, c_device_path,
+                                        DBUS_HEALTH_DEVICE_IFACE, "DestroyChannel",
+                                        DBUS_TYPE_OBJECT_PATH, &c_channel_path,
+                                        DBUS_TYPE_INVALID);
 
         env->ReleaseStringUTFChars(devicePath, c_device_path);
         env->ReleaseStringUTFChars(channelPath, c_channel_path);
 
-        if (!reply) {
-            if (dbus_error_is_set(&err)) {
-                LOG_AND_FREE_DBUS_ERROR(&err);
-            }
-        } else {
-            result = JNI_TRUE;
-        }
+        return ret ? JNI_TRUE : JNI_FALSE;
     }
 #endif
-    return result;
+    return JNI_FALSE;
 }
 
 static jstring getMainChannelNative(JNIEnv *env, jobject object, jstring devicePath) {
@@ -1659,6 +1650,7 @@
         if (fileDesc == NULL) {
             // FileDescriptor constructor has thrown an exception
             releaseChannelFdNative(env, object, channelPath);
+            close(fd);
             return NULL;
         }
 
@@ -1667,7 +1659,7 @@
         if (parcelFileDesc == NULL) {
             // ParcelFileDescriptor constructor has thrown an exception
             releaseChannelFdNative(env, object, channelPath);
-            LOGE("---Parcel File Desc is null");
+            close(fd);
             return NULL;
         }
 
@@ -1754,9 +1746,10 @@
 
     {"unregisterHealthApplicationNative", "(Ljava/lang/String;)Z",
               (void *)unregisterHealthApplicationNative},
-    {"createChannelNative", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Z",
+    {"createChannelNative", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;I)Z",
               (void *)createChannelNative},
-    {"destroyChannelNative", "(Ljava/lang/String;Ljava/lang/String;)Z", (void *)destroyChannelNative},
+    {"destroyChannelNative", "(Ljava/lang/String;Ljava/lang/String;I)Z",
+              (void *)destroyChannelNative},
     {"getMainChannelNative", "(Ljava/lang/String;)Ljava/lang/String;", (void *)getMainChannelNative},
     {"getChannelApplicationNative", "(Ljava/lang/String;)Ljava/lang/String;",
               (void *)getChannelApplicationNative},
diff --git a/core/res/res/drawable-hdpi/ab_share_pack_holo_dark.9.png b/core/res/res/drawable-hdpi/ab_share_pack_holo_dark.9.png
new file mode 100644
index 0000000..6c14157
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ab_share_pack_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ab_share_pack_holo_light.9.png b/core/res/res/drawable-hdpi/ab_share_pack_holo_light.9.png
new file mode 100644
index 0000000..f4ff16b
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ab_share_pack_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_cab_done_default_holo_dark.9.png b/core/res/res/drawable-hdpi/btn_cab_done_default_holo_dark.9.png
index 0d165bb..b0dc31f 100644
--- a/core/res/res/drawable-hdpi/btn_cab_done_default_holo_dark.9.png
+++ b/core/res/res/drawable-hdpi/btn_cab_done_default_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_cab_done_default_holo_light.9.png b/core/res/res/drawable-hdpi/btn_cab_done_default_holo_light.9.png
index 73c7e25..4bc2683 100644
--- a/core/res/res/drawable-hdpi/btn_cab_done_default_holo_light.9.png
+++ b/core/res/res/drawable-hdpi/btn_cab_done_default_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_cab_done_focused_holo_dark.9.png b/core/res/res/drawable-hdpi/btn_cab_done_focused_holo_dark.9.png
index 1459eee..4af38fb 100644
--- a/core/res/res/drawable-hdpi/btn_cab_done_focused_holo_dark.9.png
+++ b/core/res/res/drawable-hdpi/btn_cab_done_focused_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_cab_done_focused_holo_light.9.png b/core/res/res/drawable-hdpi/btn_cab_done_focused_holo_light.9.png
index 04de530..d32f74c 100644
--- a/core/res/res/drawable-hdpi/btn_cab_done_focused_holo_light.9.png
+++ b/core/res/res/drawable-hdpi/btn_cab_done_focused_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_cab_done_pressed_holo_dark.9.png b/core/res/res/drawable-hdpi/btn_cab_done_pressed_holo_dark.9.png
index bab70fa..66adffe 100644
--- a/core/res/res/drawable-hdpi/btn_cab_done_pressed_holo_dark.9.png
+++ b/core/res/res/drawable-hdpi/btn_cab_done_pressed_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_cab_done_pressed_holo_light.9.png b/core/res/res/drawable-hdpi/btn_cab_done_pressed_holo_light.9.png
index b46adfa..caeff9c 100644
--- a/core/res/res/drawable-hdpi/btn_cab_done_pressed_holo_light.9.png
+++ b/core/res/res/drawable-hdpi/btn_cab_done_pressed_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_menu_share_holo_dark.png b/core/res/res/drawable-hdpi/ic_menu_share_holo_dark.png
index db011be..6f747c8 100644
--- a/core/res/res/drawable-hdpi/ic_menu_share_holo_dark.png
+++ b/core/res/res/drawable-hdpi/ic_menu_share_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_menu_share_holo_light.png b/core/res/res/drawable-hdpi/ic_menu_share_holo_light.png
index d9a9a73..682b2fd 100644
--- a/core/res/res/drawable-hdpi/ic_menu_share_holo_light.png
+++ b/core/res/res/drawable-hdpi/ic_menu_share_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/list_divider_holo_dark.9.png b/core/res/res/drawable-hdpi/list_divider_holo_dark.9.png
new file mode 100644
index 0000000..986ab0b
--- /dev/null
+++ b/core/res/res/drawable-hdpi/list_divider_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/list_divider_holo_light.9.png b/core/res/res/drawable-hdpi/list_divider_holo_light.9.png
new file mode 100644
index 0000000..0279e17
--- /dev/null
+++ b/core/res/res/drawable-hdpi/list_divider_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ab_share_pack_holo_dark.9.png b/core/res/res/drawable-mdpi/ab_share_pack_holo_dark.9.png
new file mode 100644
index 0000000..ed4ba34
--- /dev/null
+++ b/core/res/res/drawable-mdpi/ab_share_pack_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ab_share_pack_holo_light.9.png b/core/res/res/drawable-mdpi/ab_share_pack_holo_light.9.png
new file mode 100644
index 0000000..1983c68
--- /dev/null
+++ b/core/res/res/drawable-mdpi/ab_share_pack_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_cab_done_default_holo_dark.9.png b/core/res/res/drawable-mdpi/btn_cab_done_default_holo_dark.9.png
index 9e936b3..5461b9c 100644
--- a/core/res/res/drawable-mdpi/btn_cab_done_default_holo_dark.9.png
+++ b/core/res/res/drawable-mdpi/btn_cab_done_default_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_cab_done_default_holo_light.9.png b/core/res/res/drawable-mdpi/btn_cab_done_default_holo_light.9.png
index 0360104..5dc6f80 100644
--- a/core/res/res/drawable-mdpi/btn_cab_done_default_holo_light.9.png
+++ b/core/res/res/drawable-mdpi/btn_cab_done_default_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_cab_done_focused_holo_dark.9.png b/core/res/res/drawable-mdpi/btn_cab_done_focused_holo_dark.9.png
index dd947d2..a70b53c 100644
--- a/core/res/res/drawable-mdpi/btn_cab_done_focused_holo_dark.9.png
+++ b/core/res/res/drawable-mdpi/btn_cab_done_focused_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_cab_done_focused_holo_light.9.png b/core/res/res/drawable-mdpi/btn_cab_done_focused_holo_light.9.png
index 51cfca2..c7a9896 100644
--- a/core/res/res/drawable-mdpi/btn_cab_done_focused_holo_light.9.png
+++ b/core/res/res/drawable-mdpi/btn_cab_done_focused_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_cab_done_pressed_holo_dark.9.png b/core/res/res/drawable-mdpi/btn_cab_done_pressed_holo_dark.9.png
index fd6e6c7..85d7aad 100644
--- a/core/res/res/drawable-mdpi/btn_cab_done_pressed_holo_dark.9.png
+++ b/core/res/res/drawable-mdpi/btn_cab_done_pressed_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_cab_done_pressed_holo_light.9.png b/core/res/res/drawable-mdpi/btn_cab_done_pressed_holo_light.9.png
index 5db212c..f7b01e0 100644
--- a/core/res/res/drawable-mdpi/btn_cab_done_pressed_holo_light.9.png
+++ b/core/res/res/drawable-mdpi/btn_cab_done_pressed_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_menu_share_holo_dark.png b/core/res/res/drawable-mdpi/ic_menu_share_holo_dark.png
index 306cac8..6bf21e3 100644
--- a/core/res/res/drawable-mdpi/ic_menu_share_holo_dark.png
+++ b/core/res/res/drawable-mdpi/ic_menu_share_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_menu_share_holo_light.png b/core/res/res/drawable-mdpi/ic_menu_share_holo_light.png
index cc081ad..70fe31a 100644
--- a/core/res/res/drawable-mdpi/ic_menu_share_holo_light.png
+++ b/core/res/res/drawable-mdpi/ic_menu_share_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/list_divider_holo_dark.9.png b/core/res/res/drawable-mdpi/list_divider_holo_dark.9.png
new file mode 100644
index 0000000..986ab0b
--- /dev/null
+++ b/core/res/res/drawable-mdpi/list_divider_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/list_divider_holo_light.9.png b/core/res/res/drawable-mdpi/list_divider_holo_light.9.png
new file mode 100644
index 0000000..0279e17
--- /dev/null
+++ b/core/res/res/drawable-mdpi/list_divider_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-nodpi/list_divider_holo_dark.9.png b/core/res/res/drawable-nodpi/list_divider_holo_dark.9.png
deleted file mode 100644
index 2e7951f..0000000
--- a/core/res/res/drawable-nodpi/list_divider_holo_dark.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-nodpi/list_divider_holo_light.9.png b/core/res/res/drawable-nodpi/list_divider_holo_light.9.png
deleted file mode 100644
index 17d8a54..0000000
--- a/core/res/res/drawable-nodpi/list_divider_holo_light.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ab_share_pack_holo_dark.9.png b/core/res/res/drawable-xhdpi/ab_share_pack_holo_dark.9.png
new file mode 100644
index 0000000..55099d49
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/ab_share_pack_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ab_share_pack_holo_light.9.png b/core/res/res/drawable-xhdpi/ab_share_pack_holo_light.9.png
new file mode 100644
index 0000000..3c4701f
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/ab_share_pack_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_cab_done_default_holo_dark.9.png b/core/res/res/drawable-xhdpi/btn_cab_done_default_holo_dark.9.png
index 01efef4..7ef2db7 100644
--- a/core/res/res/drawable-xhdpi/btn_cab_done_default_holo_dark.9.png
+++ b/core/res/res/drawable-xhdpi/btn_cab_done_default_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_cab_done_default_holo_light.9.png b/core/res/res/drawable-xhdpi/btn_cab_done_default_holo_light.9.png
index c287605..2283b4c 100644
--- a/core/res/res/drawable-xhdpi/btn_cab_done_default_holo_light.9.png
+++ b/core/res/res/drawable-xhdpi/btn_cab_done_default_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_cab_done_focused_holo_dark.9.png b/core/res/res/drawable-xhdpi/btn_cab_done_focused_holo_dark.9.png
index 9a496e8..6d2039e 100644
--- a/core/res/res/drawable-xhdpi/btn_cab_done_focused_holo_dark.9.png
+++ b/core/res/res/drawable-xhdpi/btn_cab_done_focused_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_cab_done_focused_holo_light.9.png b/core/res/res/drawable-xhdpi/btn_cab_done_focused_holo_light.9.png
index e2a38b4..3c909b5 100644
--- a/core/res/res/drawable-xhdpi/btn_cab_done_focused_holo_light.9.png
+++ b/core/res/res/drawable-xhdpi/btn_cab_done_focused_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_cab_done_pressed_holo_dark.9.png b/core/res/res/drawable-xhdpi/btn_cab_done_pressed_holo_dark.9.png
index 911722f..131d103 100644
--- a/core/res/res/drawable-xhdpi/btn_cab_done_pressed_holo_dark.9.png
+++ b/core/res/res/drawable-xhdpi/btn_cab_done_pressed_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_cab_done_pressed_holo_light.9.png b/core/res/res/drawable-xhdpi/btn_cab_done_pressed_holo_light.9.png
index da169bf..3e7dcdf 100644
--- a/core/res/res/drawable-xhdpi/btn_cab_done_pressed_holo_light.9.png
+++ b/core/res/res/drawable-xhdpi/btn_cab_done_pressed_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_menu_share_holo_dark.png b/core/res/res/drawable-xhdpi/ic_menu_share_holo_dark.png
index af72732..45a0f1d 100644
--- a/core/res/res/drawable-xhdpi/ic_menu_share_holo_dark.png
+++ b/core/res/res/drawable-xhdpi/ic_menu_share_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_menu_share_holo_light.png b/core/res/res/drawable-xhdpi/ic_menu_share_holo_light.png
index 79c162f..528e554 100644
--- a/core/res/res/drawable-xhdpi/ic_menu_share_holo_light.png
+++ b/core/res/res/drawable-xhdpi/ic_menu_share_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/list_divider_holo_dark.9.png b/core/res/res/drawable-xhdpi/list_divider_holo_dark.9.png
new file mode 100644
index 0000000..e62f011
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/list_divider_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/list_divider_holo_light.9.png b/core/res/res/drawable-xhdpi/list_divider_holo_light.9.png
new file mode 100644
index 0000000..65061c0
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/list_divider_holo_light.9.png
Binary files differ
diff --git a/core/res/res/layout/activity_chooser_view.xml b/core/res/res/layout/activity_chooser_view.xml
index 82e1f83..4057441 100644
--- a/core/res/res/layout/activity_chooser_view.xml
+++ b/core/res/res/layout/activity_chooser_view.xml
@@ -19,33 +19,9 @@
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
     android:id="@+id/activity_chooser_view_content"
     android:layout_width="wrap_content"
-    android:layout_height="wrap_content"
+    android:layout_height="match_parent"
     android:layout_gravity="center"
-    android:gravity="center"
-    style="?android:attr/actionButtonStyle"
-    android:padding="0dip">
-
-    <FrameLayout
-        android:id="@+id/default_activity_button"
-        android:layout_width="wrap_content"
-        android:layout_height="match_parent"
-        android:layout_gravity="center"
-        android:focusable="true"
-        android:addStatesFromChildren="true"
-        android:background="?android:attr/actionBarItemBackground">
-
-        <ImageView android:id="@+id/image"
-            android:layout_width="32dip"
-            android:layout_height="32dip"
-            android:layout_gravity="center"
-            android:layout_marginTop="4dip"
-            android:layout_marginBottom="4dip"
-            android:layout_marginLeft="8dip"
-            android:layout_marginRight="8dip"
-            android:scaleType="fitCenter"
-            android:adjustViewBounds="true" />
-
-    </FrameLayout>
+    style="?android:attr/activityChooserViewStyle">
 
     <FrameLayout
         android:id="@+id/expand_activities_button"
@@ -60,10 +36,32 @@
             android:layout_width="32dip"
             android:layout_height="32dip"
             android:layout_gravity="center"
-            android:layout_marginTop="4dip"
-            android:layout_marginBottom="4dip"
-            android:layout_marginLeft="8dip"
-            android:layout_marginRight="8dip"
+            android:layout_marginTop="2dip"
+            android:layout_marginBottom="2dip"
+            android:layout_marginLeft="12dip"
+            android:layout_marginRight="12dip"
+            android:scaleType="fitCenter"
+            android:adjustViewBounds="true" />
+
+    </FrameLayout>
+
+    <FrameLayout
+        android:id="@+id/default_activity_button"
+        android:layout_width="wrap_content"
+        android:layout_height="match_parent"
+        android:layout_gravity="center"
+        android:focusable="true"
+        android:addStatesFromChildren="true"
+        android:background="?android:attr/actionBarItemBackground">
+
+        <ImageView android:id="@+id/image"
+            android:layout_width="32dip"
+            android:layout_height="32dip"
+            android:layout_gravity="center"
+            android:layout_marginTop="2dip"
+            android:layout_marginBottom="2dip"
+            android:layout_marginLeft="12dip"
+            android:layout_marginRight="12dip"
             android:scaleType="fitCenter"
             android:adjustViewBounds="true" />
 
diff --git a/core/res/res/layout/activity_list_item.xml b/core/res/res/layout/activity_list_item.xml
index 7022fe1..572caf0 100644
--- a/core/res/res/layout/activity_list_item.xml
+++ b/core/res/res/layout/activity_list_item.xml
@@ -33,6 +33,6 @@
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         android:layout_gravity="center_horizontal"
-        android:paddingLeft="6dip" />
+        android:paddingLeft="?android:attr/listPreferredItemPaddingLeft" />
 </LinearLayout>
 
diff --git a/core/res/res/layout/activity_list_item_2.xml b/core/res/res/layout/activity_list_item_2.xml
index 3b84c733..a58ebfc 100644
--- a/core/res/res/layout/activity_list_item_2.xml
+++ b/core/res/res/layout/activity_list_item_2.xml
@@ -18,7 +18,7 @@
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
     android:minHeight="?android:attr/listPreferredItemHeight"
-    android:textAppearance="?android:attr/textAppearanceMedium"
+    android:textAppearance="?android:attr/textAppearanceListItemSmall"
     android:gravity="center_vertical"
     android:drawablePadding="14dip"
     android:paddingLeft="16dip"
diff --git a/core/res/res/layout/alert_dialog_progress_holo.xml b/core/res/res/layout/alert_dialog_progress_holo.xml
new file mode 100644
index 0000000..94dbb2b
--- /dev/null
+++ b/core/res/res/layout/alert_dialog_progress_holo.xml
@@ -0,0 +1,48 @@
+<?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.
+-->
+
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="wrap_content" android:layout_height="match_parent">
+        <ProgressBar android:id="@+id/progress"
+            style="?android:attr/progressBarStyleHorizontal"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_marginTop="16dip"
+            android:layout_marginBottom="1dip"
+            android:layout_marginLeft="16dip"
+            android:layout_marginRight="16dip"
+            android:layout_centerHorizontal="true" />
+        <TextView
+            android:id="@+id/progress_percent"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:paddingBottom="16dip"
+            android:layout_marginLeft="16dip"
+            android:layout_marginRight="16dip"
+            android:layout_alignParentLeft="true"
+            android:layout_below="@id/progress"
+        />
+        <TextView
+            android:id="@+id/progress_number"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:paddingBottom="16dip"
+            android:layout_marginLeft="16dip"
+            android:layout_marginRight="16dip"
+            android:layout_alignParentRight="true"
+            android:layout_below="@id/progress"
+        />
+</RelativeLayout>
diff --git a/core/res/res/layout/progress_dialog_holo.xml b/core/res/res/layout/progress_dialog_holo.xml
new file mode 100644
index 0000000..9631efd
--- /dev/null
+++ b/core/res/res/layout/progress_dialog_holo.xml
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 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.
+*/
+-->
+
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content">
+
+    <LinearLayout android:id="@+id/body"
+        android:orientation="horizontal"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:baselineAligned="false"
+        android:padding="16dip">
+
+        <ProgressBar android:id="@android:id/progress"
+            style="?android:attr/progressBarStyle"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:max="10000"
+            android:layout_marginRight="16dip" />
+
+        <TextView android:id="@+id/message"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_gravity="center_vertical" />
+    </LinearLayout>
+</FrameLayout>
diff --git a/core/res/res/layout/resolve_list_item.xml b/core/res/res/layout/resolve_list_item.xml
index 66e3b8a..c0404be 100644
--- a/core/res/res/layout/resolve_list_item.xml
+++ b/core/res/res/layout/resolve_list_item.xml
@@ -23,8 +23,8 @@
     android:minHeight="?android:attr/listPreferredItemHeight"
     android:layout_height="wrap_content"
     android:layout_width="match_parent"
-    android:paddingLeft="10dip"
-    android:paddingRight="15dip">
+    android:paddingLeft="16dip"
+    android:paddingRight="16dip">
 
     <!-- Activity icon when presenting dialog -->
     <ImageView android:id="@+id/icon"
@@ -39,18 +39,18 @@
         android:layout_height="wrap_content" >
         <!-- Activity name -->
         <TextView android:id="@android:id/text1"
-            android:textAppearance="?android:attr/textAppearanceLarge"
+            android:textAppearance="?android:attr/textAppearanceListItemSmall"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:maxLines="2"
-            android:paddingLeft="10dip" />
+            android:paddingLeft="16dip" />
         <!-- Extended activity info to distinguish between duplicate activity names -->
         <TextView android:id="@android:id/text2"
-            android:textAppearance="?android:attr/textAppearanceMedium"
+            android:textAppearance="?android:attr/textAppearanceSmall"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:maxLines="2"
-            android:paddingLeft="10dip" />
+            android:paddingLeft="16dip" />
     </LinearLayout>
 </LinearLayout>
 
diff --git a/core/res/res/layout/simple_list_item_1.xml b/core/res/res/layout/simple_list_item_1.xml
index 252e006..c5e3efc 100644
--- a/core/res/res/layout/simple_list_item_1.xml
+++ b/core/res/res/layout/simple_list_item_1.xml
@@ -18,9 +18,9 @@
     android:id="@android:id/text1"
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
-    android:textAppearance="?android:attr/textAppearanceListItem"
+    android:textAppearance="?android:attr/textAppearanceListItemSmall"
     android:gravity="center_vertical"
-    android:paddingLeft="8dip"
-    android:paddingRight="8dip"
-    android:minHeight="?android:attr/listPreferredItemHeight"
+    android:paddingLeft="?android:attr/listPreferredItemPaddingLeft"
+    android:paddingRight="?android:attr/listPreferredItemPaddingRight"
+    android:minHeight="?android:attr/listPreferredItemHeightSmall"
 />
diff --git a/core/res/res/layout/simple_list_item_2.xml b/core/res/res/layout/simple_list_item_2.xml
index 9b6c62a..9369876 100644
--- a/core/res/res/layout/simple_list_item_2.xml
+++ b/core/res/res/layout/simple_list_item_2.xml
@@ -24,8 +24,8 @@
 	<TextView android:id="@android:id/text1"
 		android:layout_width="match_parent"
 		android:layout_height="wrap_content"
-        android:layout_marginLeft="8dip"
-        android:layout_marginTop="8dip"
+    android:layout_marginLeft="?android:attr/listPreferredItemPaddingLeft"
+    android:layout_marginTop="8dip"
 		android:textAppearance="?android:attr/textAppearanceListItem"
 	/>
 		
@@ -33,7 +33,7 @@
 		android:layout_width="match_parent"
 		android:layout_height="wrap_content"
 		android:layout_below="@android:id/text1"
-        android:layout_alignLeft="@android:id/text1"
+    android:layout_alignLeft="@android:id/text1"
 		android:textAppearance="?android:attr/textAppearanceSmall"
 	/>
 
diff --git a/core/res/res/layout/simple_list_item_activated_1.xml b/core/res/res/layout/simple_list_item_activated_1.xml
index d60f93b..a5fb5d1 100644
--- a/core/res/res/layout/simple_list_item_activated_1.xml
+++ b/core/res/res/layout/simple_list_item_activated_1.xml
@@ -18,8 +18,10 @@
     android:id="@android:id/text1"
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
-    android:textAppearance="?android:attr/textAppearanceListItem"
+    android:textAppearance="?android:attr/textAppearanceListItemSmall"
     android:gravity="center_vertical"
+    android:paddingLeft="?android:attr/listPreferredItemPaddingLeft"
+    android:paddingRight="?android:attr/listPreferredItemPaddingRight"
     android:background="?android:attr/activatedBackgroundIndicator"
-    android:minHeight="?android:attr/listPreferredItemHeight"
+    android:minHeight="?android:attr/listPreferredItemHeightSmall"
 />
diff --git a/core/res/res/layout/simple_list_item_activated_2.xml b/core/res/res/layout/simple_list_item_activated_2.xml
index 5be5c92..8746f6f 100644
--- a/core/res/res/layout/simple_list_item_activated_2.xml
+++ b/core/res/res/layout/simple_list_item_activated_2.xml
@@ -27,9 +27,9 @@
     <TextView android:id="@android:id/text1"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
-        android:layout_marginLeft="8dip"
-        android:layout_marginTop="8dip"
-        android:textAppearance="?android:attr/textAppearanceLarge"
+        android:layout_marginLeft="?android:attr/listPreferredItemPaddingLeft"
+        android:layout_marginTop="6dip"
+        android:textAppearance="?android:attr/textAppearanceListItem"
     />
 
     <TextView android:id="@android:id/text2"
diff --git a/core/res/res/layout/simple_list_item_checked.xml b/core/res/res/layout/simple_list_item_checked.xml
index 79d3a18..c9153f8 100644
--- a/core/res/res/layout/simple_list_item_checked.xml
+++ b/core/res/res/layout/simple_list_item_checked.xml
@@ -17,10 +17,10 @@
 <CheckedTextView xmlns:android="http://schemas.android.com/apk/res/android"
     android:id="@android:id/text1"
     android:layout_width="match_parent"
-    android:layout_height="?android:attr/listPreferredItemHeight"
-    android:textAppearance="?android:attr/textAppearanceListItem"
+    android:layout_height="?android:attr/listPreferredItemHeightSmall"
+    android:textAppearance="?android:attr/textAppearanceListItemSmall"
     android:gravity="center_vertical"
     android:checkMark="?android:attr/textCheckMark"
-    android:paddingLeft="8dip"
-    android:paddingRight="8dip"
+    android:paddingLeft="?android:attr/listPreferredItemPaddingLeft"
+    android:paddingRight="?android:attr/listPreferredItemPaddingRight"
 />
diff --git a/core/res/res/layout/simple_list_item_single_choice.xml b/core/res/res/layout/simple_list_item_single_choice.xml
index ac4a4a8..4a6cefa 100644
--- a/core/res/res/layout/simple_list_item_single_choice.xml
+++ b/core/res/res/layout/simple_list_item_single_choice.xml
@@ -17,10 +17,10 @@
 <CheckedTextView xmlns:android="http://schemas.android.com/apk/res/android"
     android:id="@android:id/text1"
     android:layout_width="match_parent"
-    android:layout_height="?android:attr/listPreferredItemHeight"
-    android:textAppearance="?android:attr/textAppearanceListItem"
+    android:layout_height="?android:attr/listPreferredItemHeightSmall"
+    android:textAppearance="?android:attr/textAppearanceListItemSmall"
     android:gravity="center_vertical"
     android:checkMark="?android:attr/listChoiceIndicatorSingle"
-    android:paddingLeft="8dip"
-    android:paddingRight="8dip"
+    android:paddingLeft="?android:attr/listPreferredItemPaddingLeft"
+    android:paddingRight="?android:attr/listPreferredItemPaddingRight"
 />
diff --git a/core/res/res/layout/simple_spinner_item.xml b/core/res/res/layout/simple_spinner_item.xml
index 77929ee..61dc025 100644
--- a/core/res/res/layout/simple_spinner_item.xml
+++ b/core/res/res/layout/simple_spinner_item.xml
@@ -19,7 +19,7 @@
 -->
 <TextView xmlns:android="http://schemas.android.com/apk/res/android" 
     android:id="@android:id/text1"
-	style="?android:attr/spinnerItemStyle"
+    style="?android:attr/spinnerItemStyle"
     android:singleLine="true"
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 0bf5b0a..f90d67b 100755
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -235,6 +235,11 @@
         <!-- The list item height for search results. @hide -->
         <attr name="searchResultListItemHeight" format="dimension" />
 
+        <!-- The preferred padding along the left edge of list items. -->
+        <attr name="listPreferredItemPaddingLeft" format="dimension" />
+        <!-- The preferred padding along the right edge of list items. -->
+        <attr name="listPreferredItemPaddingRight" format="dimension" />
+
         <!-- The preferred TextAppearance for the primary text of list items. -->
         <attr name="textAppearanceListItem" format="reference" />
         <!-- The preferred TextAppearance for the primary text of small list items. -->
@@ -597,6 +602,9 @@
         <!-- The DatePicker style. -->
         <attr name="datePickerStyle" format="reference" />
 
+        <!-- Default ActivityChooserView style. -->
+        <attr name="activityChooserViewStyle" format="reference" />
+
         <!-- Fast scroller styles -->
         <eat-comment />
 
@@ -1543,6 +1551,8 @@
         <attr name="multiChoiceItemLayout" format="reference" />
         <attr name="singleChoiceItemLayout" format="reference" />
         <attr name="listItemLayout" format="reference" />
+        <attr name="progressLayout" format="reference" />
+        <attr name="horizontalProgressLayout" format="reference" />
     </declare-styleable>
 
     <!-- Fragment animation class attributes. -->
@@ -1796,7 +1806,13 @@
         <!-- Defines whether the vertical scrollbar track should always be drawn. -->
         <attr name="scrollbarAlwaysDrawVerticalTrack" format="boolean" />
 
-        <!-- Defines which edges should be fadeded on scrolling. -->
+        <!-- {@deprecated This attribute is deprecated and will be ignored as of
+             API level {@link android.os.Build.VERSION_CODES#ICE_CREAM_SANDWICH}.
+             Using fading edges may introduce noticeable performance
+             degradations and should be used only when required by the application's
+             visual design. To request fading edges with API level
+             {@link android.os.Build.VERSION_CODES#ICE_CREAM_SANDWICH} and above,
+             use the <code>requiresFadingEdge</code> attribute instead.} -->
         <attr name="fadingEdge">
             <!-- No edge is faded. -->
             <flag name="none" value="0x00000000" />
@@ -1805,6 +1821,15 @@
             <!-- Fades vertical edges only. -->
             <flag name="vertical" value="0x00002000" />
         </attr>
+        <!-- Defines which edges should be faded on scrolling. -->
+        <attr name="requiresFadingEdge">
+            <!-- No edge is faded. -->
+            <flag name="none" value="0x00000000" />
+            <!-- Fades horizontal edges only. -->
+            <flag name="horizontal" value="0x00001000" />
+            <!-- Fades vertical edges only. -->
+            <flag name="vertical" value="0x00002000" />
+        </attr>
         <!-- Defines the length of the fading edges. -->
         <attr name="fadingEdgeLength" format="dimension" />
 
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index 2753eab..4f162f2 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -175,4 +175,7 @@
     <!-- Width of the icon in a dropdown list -->
     <dimen name="dropdownitem_icon_width">32dip</dimen>
 
+    <!-- Default width for a textview error popup -->
+    <dimen name="textview_error_popup_default_width">240dip</dimen>
+
 </resources>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index bc2b907..9327a0b 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -1798,6 +1798,16 @@
   <public type="attr" name="textAppearanceListItem" />
   <public type="attr" name="textAppearanceListItemSmall" />
 
+  <public type="attr" name="targetDescriptions" />
+  <public type="attr" name="directionDescriptions" />
+
+  <public type="attr" name="overridesImplicitlyEnabledSubtype" />
+
+  <public type="attr" name="listPreferredItemPaddingLeft" />
+  <public type="attr" name="listPreferredItemPaddingRight" />
+
+  <public type="attr" name="requiresFadingEdge" />
+
   <public type="style" name="TextAppearance.SuggestionHighlight" />
 
   <public type="style" name="Theme.Holo.Light.DarkActionBar" />
@@ -2007,8 +2017,4 @@
   <public type="color" name="holo_purple" />
   <public type="color" name="holo_blue_bright" />
 
-  <public type="attr" name="targetDescriptions" />
-  <public type="attr" name="directionDescriptions" />
-
-  <public type="attr" name="overridesImplicitlyEnabledSubtype" />
 </resources>
diff --git a/core/res/res/values/styles.xml b/core/res/res/values/styles.xml
index 1a6a523..356a2ad 100644
--- a/core/res/res/values/styles.xml
+++ b/core/res/res/values/styles.xml
@@ -61,6 +61,8 @@
         <item name="bottomBright">@android:drawable/popup_bottom_bright</item>
         <item name="bottomMedium">@android:drawable/popup_bottom_medium</item>
         <item name="centerMedium">@android:drawable/popup_center_medium</item>
+        <item name="progressLayout">@android:layout/progress_dialog</item>
+        <item name="horizontalProgressLayout">@android:layout/alert_dialog_progress</item>
     </style>
 
     <style name="Widget.PreferenceFrameLayout">
@@ -890,6 +892,14 @@
         <item name="android:textSize">30sp</item>
     </style>
 
+    <style name="Widget.ActivityChooserView">
+        <item name="android:gravity">center</item>
+        <item name="android:background">@android:drawable/ab_share_pack_holo_dark</item>
+        <item name="android:divider">?android:attr/dividerVertical</item>
+        <item name="android:showDividers">middle</item>
+        <item name="android:dividerPadding">6dip</item>
+    </style>
+
      <style name="TextAppearance.SuggestionHighlight">
          <item name="android:textSize">18sp</item>
          <item name="android:textColor">@android:color/suggestion_highlight_text</item>
@@ -1651,6 +1661,9 @@
         <item name="android:background">@null</item>
     </style>
 
+    <style name="Widget.Holo.ActivityChooserView" parent="Widget.ActivityChooserView">
+    </style>
+
     <style name="Widget.Holo.ImageWell" parent="Widget.ImageWell">
     </style>
 
@@ -2071,6 +2084,10 @@
     <style name="Widget.Holo.Light.EditText.NumberPickerInputText" parent="Widget.Holo.EditText.NumberPickerInputText">
     </style>
 
+    <style name="Widget.Holo.Light.ActivityChooserView" parent="Widget.Holo.ActivityChooserView">
+        <item name="android:background">@android:drawable/ab_share_pack_holo_light</item>
+    </style>
+
     <style name="Widget.Holo.Light.ImageWell" parent="Widget.ImageWell">
     </style>
 
@@ -2335,6 +2352,8 @@
         <item name="centerMedium">@android:drawable/dialog_middle_holo_dark</item>
         <item name="layout">@android:layout/alert_dialog_holo</item>
         <item name="listLayout">@android:layout/select_dialog_holo</item>
+        <item name="progressLayout">@android:layout/progress_dialog_holo</item>
+        <item name="horizontalProgressLayout">@android:layout/alert_dialog_progress_holo</item>
         <item name="listItemLayout">@android:layout/select_dialog_item_holo</item>
         <item name="multiChoiceItemLayout">@android:layout/select_dialog_multichoice_holo</item>
         <item name="singleChoiceItemLayout">@android:layout/select_dialog_singlechoice_holo</item>
diff --git a/core/res/res/values/themes.xml b/core/res/res/values/themes.xml
index 6f98e02..d19c97f 100644
--- a/core/res/res/values/themes.xml
+++ b/core/res/res/values/themes.xml
@@ -124,6 +124,8 @@
         <item name="dropdownListPreferredItemHeight">?android:attr/listPreferredItemHeight</item>
         <item name="textAppearanceListItem">?android:attr/textAppearanceLarge</item>
         <item name="textAppearanceListItemSmall">?android:attr/textAppearanceLarge</item>
+        <item name="listPreferredItemPaddingLeft">6dip</item>
+        <item name="listPreferredItemPaddingRight">6dip</item>
 
         <!-- @hide -->
         <item name="searchResultListItemHeight">58dip</item>
@@ -269,7 +271,8 @@
         <item name="quickContactBadgeStyleSmallWindowLarge">@android:style/Widget.QuickContactBadgeSmall.WindowLarge</item>
         <item name="listPopupWindowStyle">@android:style/Widget.ListPopupWindow</item>
         <item name="popupMenuStyle">@android:style/Widget.PopupMenu</item>
-        
+        <item name="activityChooserViewStyle">@android:style/Widget.ActivityChooserView</item>
+
         <!-- Preference styles -->
         <item name="preferenceScreenStyle">@android:style/Preference.PreferenceScreen</item>
         <item name="preferenceCategoryStyle">@android:style/Preference.Category</item>
@@ -923,6 +926,8 @@
         <item name="listPreferredItemHeightLarge">80dip</item>
         <item name="dropdownListPreferredItemHeight">?android:attr/listPreferredItemHeightSmall</item>
         <item name="textAppearanceListItemSmall">?android:attr/textAppearanceMedium</item>
+        <item name="listPreferredItemPaddingLeft">8dip</item>
+        <item name="listPreferredItemPaddingRight">8dip</item>
 
         <!-- @hide -->
         <item name="searchResultListItemHeight">58dip</item>
@@ -1062,6 +1067,7 @@
         <item name="listPopupWindowStyle">@android:style/Widget.Holo.ListPopupWindow</item>
         <item name="popupMenuStyle">@android:style/Widget.Holo.PopupMenu</item>
         <item name="stackViewStyle">@android:style/Widget.Holo.StackView</item>
+        <item name="activityChooserViewStyle">@android:style/Widget.Holo.ActivityChooserView</item>
 
         <!-- Preference styles -->
         <item name="preferenceScreenStyle">@android:style/Preference.Holo.PreferenceScreen</item>
@@ -1227,6 +1233,8 @@
         <item name="listPreferredItemHeightLarge">80dip</item>
         <item name="dropdownListPreferredItemHeight">?android:attr/listPreferredItemHeightSmall</item>
         <item name="textAppearanceListItemSmall">?android:attr/textAppearanceMedium</item>
+        <item name="listPreferredItemPaddingLeft">8dip</item>
+        <item name="listPreferredItemPaddingRight">8dip</item>
 
         <!-- @hide -->
         <item name="searchResultListItemHeight">58dip</item>
@@ -1366,6 +1374,7 @@
         <item name="listPopupWindowStyle">@android:style/Widget.Holo.Light.ListPopupWindow</item>
         <item name="popupMenuStyle">@android:style/Widget.Holo.Light.PopupMenu</item>
         <item name="stackViewStyle">@android:style/Widget.Holo.StackView</item>
+        <item name="activityChooserViewStyle">@android:style/Widget.Holo.Light.ActivityChooserView</item>
 
         <!-- Preference styles -->
         <item name="preferenceScreenStyle">@android:style/Preference.Holo.PreferenceScreen</item>
@@ -1531,6 +1540,9 @@
         
         <item name="textAppearance">@android:style/TextAppearance.Holo</item>
         <item name="textAppearanceInverse">@android:style/TextAppearance.Holo.Inverse</item>
+
+        <item name="listPreferredItemPaddingLeft">16dip</item>
+        <item name="listPreferredItemPaddingRight">16dip</item>
     </style>
 
     <!-- Variation of Theme.Holo.Dialog that has a nice minumum width for
@@ -1620,6 +1632,9 @@
 
         <item name="textAppearance">@android:style/TextAppearance.Holo.Light</item>
         <item name="textAppearanceInverse">@android:style/TextAppearance.Holo.Light.Inverse</item>
+
+        <item name="listPreferredItemPaddingLeft">16dip</item>
+        <item name="listPreferredItemPaddingRight">16dip</item>
     </style>
 
     <!-- Variation of Theme.Holo.Light.Dialog that has a nice minumum width for
diff --git a/data/videos/AndroidInSpace.240p.mp4 b/data/videos/AndroidInSpace.240p.mp4
new file mode 100644
index 0000000..e1445e4
--- /dev/null
+++ b/data/videos/AndroidInSpace.240p.mp4
Binary files differ
diff --git a/data/videos/Sunset.240p.mp4 b/data/videos/Sunset.240p.mp4
new file mode 100644
index 0000000..f5c533f
--- /dev/null
+++ b/data/videos/Sunset.240p.mp4
Binary files differ
diff --git a/data/videos/VideoPackage1.mk b/data/videos/VideoPackage1.mk
new file mode 100644
index 0000000..daff26f
--- /dev/null
+++ b/data/videos/VideoPackage1.mk
@@ -0,0 +1,23 @@
+#
+# 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  := frameworks/base/data/videos
+TARGET_PATH := system/media/video
+
+PRODUCT_COPY_FILES += \
+	$(LOCAL_PATH)/AndroidInSpace.240p.mp4:$(TARGET_PATH)/AndroidInSpace.240p.mp4 \
+	$(LOCAL_PATH)/Sunset.240p.mp4:$(TARGET_PATH)/Sunset.240p.mp4
+
diff --git a/graphics/java/android/graphics/Matrix.java b/graphics/java/android/graphics/Matrix.java
index 66ed104..a837294 100644
--- a/graphics/java/android/graphics/Matrix.java
+++ b/graphics/java/android/graphics/Matrix.java
@@ -37,6 +37,188 @@
     public static final int MPERSP_1 = 7;   //!< use with getValues/setValues
     public static final int MPERSP_2 = 8;   //!< use with getValues/setValues
 
+    /** @hide */
+    public static Matrix IDENTITY_MATRIX = new Matrix() {
+        void oops() {
+            throw new IllegalStateException("Matrix can not be modified");
+        }
+
+        @Override
+        public void set(Matrix src) {
+            oops();
+        }
+
+        @Override
+        public void reset() {
+            oops();
+        }
+
+        @Override
+        public void setTranslate(float dx, float dy) {
+            oops();
+        }
+
+        @Override
+        public void setScale(float sx, float sy, float px, float py) {
+            oops();
+        }
+
+        @Override
+        public void setScale(float sx, float sy) {
+            oops();
+        }
+
+        @Override
+        public void setRotate(float degrees, float px, float py) {
+            oops();
+        }
+
+        @Override
+        public void setRotate(float degrees) {
+            oops();
+        }
+
+        @Override
+        public void setSinCos(float sinValue, float cosValue, float px, float py) {
+            oops();
+        }
+
+        @Override
+        public void setSinCos(float sinValue, float cosValue) {
+            oops();
+        }
+
+        @Override
+        public void setSkew(float kx, float ky, float px, float py) {
+            oops();
+        }
+
+        @Override
+        public void setSkew(float kx, float ky) {
+            oops();
+        }
+
+        @Override
+        public boolean setConcat(Matrix a, Matrix b) {
+            oops();
+            return false;
+        }
+
+        @Override
+        public boolean preTranslate(float dx, float dy) {
+            oops();
+            return false;
+        }
+
+        @Override
+        public boolean preScale(float sx, float sy, float px, float py) {
+            oops();
+            return false;
+        }
+
+        @Override
+        public boolean preScale(float sx, float sy) {
+            oops();
+            return false;
+        }
+
+        @Override
+        public boolean preRotate(float degrees, float px, float py) {
+            oops();
+            return false;
+        }
+
+        @Override
+        public boolean preRotate(float degrees) {
+            oops();
+            return false;
+        }
+
+        @Override
+        public boolean preSkew(float kx, float ky, float px, float py) {
+            oops();
+            return false;
+        }
+
+        @Override
+        public boolean preSkew(float kx, float ky) {
+            oops();
+            return false;
+        }
+
+        @Override
+        public boolean preConcat(Matrix other) {
+            oops();
+            return false;
+        }
+
+        @Override
+        public boolean postTranslate(float dx, float dy) {
+            oops();
+            return false;
+        }
+
+        @Override
+        public boolean postScale(float sx, float sy, float px, float py) {
+            oops();
+            return false;
+        }
+
+        @Override
+        public boolean postScale(float sx, float sy) {
+            oops();
+            return false;
+        }
+
+        @Override
+        public boolean postRotate(float degrees, float px, float py) {
+            oops();
+            return false;
+        }
+
+        @Override
+        public boolean postRotate(float degrees) {
+            oops();
+            return false;
+        }
+
+        @Override
+        public boolean postSkew(float kx, float ky, float px, float py) {
+            oops();
+            return false;
+        }
+
+        @Override
+        public boolean postSkew(float kx, float ky) {
+            oops();
+            return false;
+        }
+
+        @Override
+        public boolean postConcat(Matrix other) {
+            oops();
+            return false;
+        }
+
+        @Override
+        public boolean setRectToRect(RectF src, RectF dst, ScaleToFit stf) {
+            oops();
+            return false;
+        }
+
+        @Override
+        public boolean setPolyToPoly(float[] src, int srcIndex, float[] dst, int dstIndex,
+                int pointCount) {
+            oops();
+            return false;
+        }
+
+        @Override
+        public void setValues(float[] values) {
+            oops();
+        }
+    };
+
     /**
      * @hide
      */
diff --git a/include/media/mediascanner.h b/include/media/mediascanner.h
index 803bffb..a73403b 100644
--- a/include/media/mediascanner.h
+++ b/include/media/mediascanner.h
@@ -62,12 +62,17 @@
 private:
     // current locale (like "ja_JP"), created/destroyed with strdup()/free()
     char *mLocale;
+    char *mSkipList;
+    int *mSkipIndex;
 
     MediaScanResult doProcessDirectory(
             char *path, int pathRemaining, MediaScannerClient &client, bool noMedia);
     MediaScanResult doProcessDirectoryEntry(
             char *path, int pathRemaining, MediaScannerClient &client, bool noMedia,
             struct dirent* entry, char* fileSpot);
+    void loadSkipList();
+    bool shouldSkipDirectory(char *path);
+
 
     MediaScanner(const MediaScanner &);
     MediaScanner &operator=(const MediaScanner &);
@@ -103,4 +108,3 @@
 }; // namespace android
 
 #endif // MEDIASCANNER_H
-
diff --git a/include/ui/Input.h b/include/ui/Input.h
index f1385a0..af899ef 100644
--- a/include/ui/Input.h
+++ b/include/ui/Input.h
@@ -660,15 +660,19 @@
     static const uint32_t HISTORY_SIZE = 10;
 
     // Oldest sample to consider when calculating the velocity.
-    static const nsecs_t MAX_AGE = 200 * 1000000; // 200 ms
+    static const nsecs_t MAX_AGE = 100 * 1000000; // 100 ms
 
     // The minimum duration between samples when estimating velocity.
-    static const nsecs_t MIN_DURATION = 10 * 1000000; // 10 ms
+    static const nsecs_t MIN_DURATION = 5 * 1000000; // 5 ms
 
     struct Movement {
         nsecs_t eventTime;
         BitSet32 idBits;
         Position positions[MAX_POINTERS];
+
+        inline const Position& getPosition(uint32_t id) const {
+            return positions[idBits.getIndexOfBit(id)];
+        }
     };
 
     uint32_t mIndex;
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index 24784af..32595e4 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -63,36 +63,42 @@
 // In this array, the index of each Blender equals the value of the first
 // entry. For instance, gBlends[1] == gBlends[SkXfermode::kSrc_Mode]
 static const Blender gBlends[] = {
-    { SkXfermode::kClear_Mode,   GL_ZERO,                 GL_ONE_MINUS_SRC_ALPHA },
-    { SkXfermode::kSrc_Mode,     GL_ONE,                  GL_ZERO },
-    { SkXfermode::kDst_Mode,     GL_ZERO,                 GL_ONE },
-    { SkXfermode::kSrcOver_Mode, GL_ONE,                  GL_ONE_MINUS_SRC_ALPHA },
-    { SkXfermode::kDstOver_Mode, GL_ONE_MINUS_DST_ALPHA,  GL_ONE },
-    { SkXfermode::kSrcIn_Mode,   GL_DST_ALPHA,            GL_ZERO },
-    { SkXfermode::kDstIn_Mode,   GL_ZERO,                 GL_SRC_ALPHA },
-    { SkXfermode::kSrcOut_Mode,  GL_ONE_MINUS_DST_ALPHA,  GL_ZERO },
-    { SkXfermode::kDstOut_Mode,  GL_ZERO,                 GL_ONE_MINUS_SRC_ALPHA },
-    { SkXfermode::kSrcATop_Mode, GL_DST_ALPHA,            GL_ONE_MINUS_SRC_ALPHA },
-    { SkXfermode::kDstATop_Mode, GL_ONE_MINUS_DST_ALPHA,  GL_SRC_ALPHA },
-    { SkXfermode::kXor_Mode,     GL_ONE_MINUS_DST_ALPHA,  GL_ONE_MINUS_SRC_ALPHA }
+    { SkXfermode::kClear_Mode,    GL_ZERO,                GL_ONE_MINUS_SRC_ALPHA },
+    { SkXfermode::kSrc_Mode,      GL_ONE,                 GL_ZERO },
+    { SkXfermode::kDst_Mode,      GL_ZERO,                GL_ONE },
+    { SkXfermode::kSrcOver_Mode,  GL_ONE,                 GL_ONE_MINUS_SRC_ALPHA },
+    { SkXfermode::kDstOver_Mode,  GL_ONE_MINUS_DST_ALPHA, GL_ONE },
+    { SkXfermode::kSrcIn_Mode,    GL_DST_ALPHA,           GL_ZERO },
+    { SkXfermode::kDstIn_Mode,    GL_ZERO,                GL_SRC_ALPHA },
+    { SkXfermode::kSrcOut_Mode,   GL_ONE_MINUS_DST_ALPHA, GL_ZERO },
+    { SkXfermode::kDstOut_Mode,   GL_ZERO,                GL_ONE_MINUS_SRC_ALPHA },
+    { SkXfermode::kSrcATop_Mode,  GL_DST_ALPHA,           GL_ONE_MINUS_SRC_ALPHA },
+    { SkXfermode::kDstATop_Mode,  GL_ONE_MINUS_DST_ALPHA, GL_SRC_ALPHA },
+    { SkXfermode::kXor_Mode,      GL_ONE_MINUS_DST_ALPHA, GL_ONE_MINUS_SRC_ALPHA },
+    { SkXfermode::kPlus_Mode,     GL_ONE,                 GL_ONE },
+    { SkXfermode::kMultiply_Mode, GL_ZERO,                GL_SRC_COLOR },
+    { SkXfermode::kScreen_Mode,   GL_ONE,                 GL_ONE_MINUS_SRC_COLOR }
 };
 
 // This array contains the swapped version of each SkXfermode. For instance
 // this array's SrcOver blending mode is actually DstOver. You can refer to
 // createLayer() for more information on the purpose of this array.
 static const Blender gBlendsSwap[] = {
-    { SkXfermode::kClear_Mode,   GL_ONE_MINUS_DST_ALPHA,  GL_ZERO },
-    { SkXfermode::kSrc_Mode,     GL_ZERO,                 GL_ONE },
-    { SkXfermode::kDst_Mode,     GL_ONE,                  GL_ZERO },
-    { SkXfermode::kSrcOver_Mode, GL_ONE_MINUS_DST_ALPHA,  GL_ONE },
-    { SkXfermode::kDstOver_Mode, GL_ONE,                  GL_ONE_MINUS_SRC_ALPHA },
-    { SkXfermode::kSrcIn_Mode,   GL_ZERO,                 GL_SRC_ALPHA },
-    { SkXfermode::kDstIn_Mode,   GL_DST_ALPHA,            GL_ZERO },
-    { SkXfermode::kSrcOut_Mode,  GL_ZERO,                 GL_ONE_MINUS_SRC_ALPHA },
-    { SkXfermode::kDstOut_Mode,  GL_ONE_MINUS_DST_ALPHA,  GL_ZERO },
-    { SkXfermode::kSrcATop_Mode, GL_ONE_MINUS_DST_ALPHA,  GL_SRC_ALPHA },
-    { SkXfermode::kDstATop_Mode, GL_DST_ALPHA,            GL_ONE_MINUS_SRC_ALPHA },
-    { SkXfermode::kXor_Mode,     GL_ONE_MINUS_DST_ALPHA,  GL_ONE_MINUS_SRC_ALPHA }
+    { SkXfermode::kClear_Mode,    GL_ONE_MINUS_DST_ALPHA, GL_ZERO },
+    { SkXfermode::kSrc_Mode,      GL_ZERO,                GL_ONE },
+    { SkXfermode::kDst_Mode,      GL_ONE,                 GL_ZERO },
+    { SkXfermode::kSrcOver_Mode,  GL_ONE_MINUS_DST_ALPHA, GL_ONE },
+    { SkXfermode::kDstOver_Mode,  GL_ONE,                 GL_ONE_MINUS_SRC_ALPHA },
+    { SkXfermode::kSrcIn_Mode,    GL_ZERO,                GL_SRC_ALPHA },
+    { SkXfermode::kDstIn_Mode,    GL_DST_ALPHA,           GL_ZERO },
+    { SkXfermode::kSrcOut_Mode,   GL_ZERO,                GL_ONE_MINUS_SRC_ALPHA },
+    { SkXfermode::kDstOut_Mode,   GL_ONE_MINUS_DST_ALPHA, GL_ZERO },
+    { SkXfermode::kSrcATop_Mode,  GL_ONE_MINUS_DST_ALPHA, GL_SRC_ALPHA },
+    { SkXfermode::kDstATop_Mode,  GL_DST_ALPHA,           GL_ONE_MINUS_SRC_ALPHA },
+    { SkXfermode::kXor_Mode,      GL_ONE_MINUS_DST_ALPHA, GL_ONE_MINUS_SRC_ALPHA },
+    { SkXfermode::kPlus_Mode,     GL_ONE,                 GL_ONE },
+    { SkXfermode::kMultiply_Mode, GL_DST_COLOR,           GL_ZERO },
+    { SkXfermode::kScreen_Mode,   GL_ONE_MINUS_DST_COLOR, GL_ONE }
 };
 
 static const GLenum gTextureUnits[] = {
@@ -2489,7 +2495,7 @@
         ProgramDescription& description, bool swapSrcDst) {
     blend = blend || mode != SkXfermode::kSrcOver_Mode;
     if (blend) {
-        if (mode < SkXfermode::kPlus_Mode) {
+        if (mode <= SkXfermode::kScreen_Mode) {
             if (!mCaches.blend) {
                 glEnable(GL_BLEND);
             }
@@ -2542,15 +2548,7 @@
 
 void OpenGLRenderer::getAlphaAndMode(SkPaint* paint, int* alpha, SkXfermode::Mode* mode) {
     if (paint) {
-        if (!mCaches.extensions.hasFramebufferFetch()) {
-            const bool isMode = SkXfermode::IsMode(paint->getXfermode(), mode);
-            if (!isMode) {
-                // Assume SRC_OVER
-                *mode = SkXfermode::kSrcOver_Mode;
-            }
-        } else {
-            *mode = getXfermode(paint->getXfermode());
-        }
+        *mode = getXfermode(paint->getXfermode());
 
         // Skia draws using the color's alpha channel if < 255
         // Otherwise, it uses the paint's alpha
diff --git a/libs/ui/Input.cpp b/libs/ui/Input.cpp
index 688b998..0d25823 100644
--- a/libs/ui/Input.cpp
+++ b/libs/ui/Input.cpp
@@ -752,6 +752,7 @@
 
     switch (actionMasked) {
     case AMOTION_EVENT_ACTION_DOWN:
+    case AMOTION_EVENT_ACTION_HOVER_ENTER:
         // Clear all pointers on down before adding the new movement.
         clear();
         break;
@@ -764,12 +765,11 @@
         clearPointers(downIdBits);
         break;
     }
-    case AMOTION_EVENT_ACTION_OUTSIDE:
-    case AMOTION_EVENT_ACTION_CANCEL:
-    case AMOTION_EVENT_ACTION_SCROLL:
-    case AMOTION_EVENT_ACTION_UP:
-    case AMOTION_EVENT_ACTION_POINTER_UP:
-        // Ignore these actions because they do not convey any new information about
+    case AMOTION_EVENT_ACTION_MOVE:
+    case AMOTION_EVENT_ACTION_HOVER_MOVE:
+        break;
+    default:
+        // Ignore all other actions because they do not convey any new information about
         // pointer movement.  We also want to preserve the last known velocity of the pointers.
         // Note that ACTION_UP and ACTION_POINTER_UP always report the last known position
         // of the pointers that went up.  ACTION_POINTER_UP does include the new position of
@@ -814,68 +814,36 @@
 bool VelocityTracker::getVelocity(uint32_t id, float* outVx, float* outVy) const {
     const Movement& newestMovement = mMovements[mIndex];
     if (newestMovement.idBits.hasBit(id)) {
-        // Find the oldest sample that contains the pointer and that is not older than MAX_AGE.
-        nsecs_t minTime = newestMovement.eventTime - MAX_AGE;
-        uint32_t oldestIndex = mIndex;
-        uint32_t numTouches = 1;
-        do {
-            uint32_t nextOldestIndex = (oldestIndex == 0 ? HISTORY_SIZE : oldestIndex) - 1;
-            const Movement& nextOldestMovement = mMovements[nextOldestIndex];
-            if (!nextOldestMovement.idBits.hasBit(id)
-                    || nextOldestMovement.eventTime < minTime) {
-                break;
-            }
-            oldestIndex = nextOldestIndex;
-        } while (++numTouches < HISTORY_SIZE);
-
-        // Calculate an exponentially weighted moving average of the velocity estimate
-        // at different points in time measured relative to the oldest sample.
-        // This is essentially an IIR filter.  Newer samples are weighted more heavily
-        // than older samples.  Samples at equal time points are weighted more or less
-        // equally.
-        //
-        // One tricky problem is that the sample data may be poorly conditioned.
-        // Sometimes samples arrive very close together in time which can cause us to
-        // overestimate the velocity at that time point.  Most samples might be measured
-        // 16ms apart but some consecutive samples could be only 0.5sm apart because
-        // the hardware or driver reports them irregularly or in bursts.
+        const Position& newestPosition = newestMovement.getPosition(id);
         float accumVx = 0;
         float accumVy = 0;
-        uint32_t index = oldestIndex;
-        uint32_t samplesUsed = 0;
-        const Movement& oldestMovement = mMovements[oldestIndex];
-        const Position& oldestPosition =
-                oldestMovement.positions[oldestMovement.idBits.getIndexOfBit(id)];
-        nsecs_t lastDuration = 0;
+        float duration = 0;
 
-        while (numTouches-- > 1) {
-            if (++index == HISTORY_SIZE) {
-                index = 0;
-            }
+        // Iterate over movement samples in reverse time order and accumulate velocity.
+        uint32_t index = mIndex;
+        do {
+            index = (index == 0 ? HISTORY_SIZE : index) - 1;
             const Movement& movement = mMovements[index];
-            nsecs_t duration = movement.eventTime - oldestMovement.eventTime;
-
-            // If the duration between samples is small, we may significantly overestimate
-            // the velocity.  Consequently, we impose a minimum duration constraint on the
-            // samples that we include in the calculation.
-            if (duration >= MIN_DURATION) {
-                const Position& position = movement.positions[movement.idBits.getIndexOfBit(id)];
-                float scale = 1000000000.0f / duration; // one over time delta in seconds
-                float vx = (position.x - oldestPosition.x) * scale;
-                float vy = (position.y - oldestPosition.y) * scale;
-
-                accumVx = (accumVx * lastDuration + vx * duration) / (duration + lastDuration);
-                accumVy = (accumVy * lastDuration + vy * duration) / (duration + lastDuration);
-
-                lastDuration = duration;
-                samplesUsed += 1;
+            if (!movement.idBits.hasBit(id)) {
+                break;
             }
-        }
+
+            nsecs_t age = newestMovement.eventTime - movement.eventTime;
+            if (age > MAX_AGE) {
+                break;
+            }
+
+            const Position& position = movement.getPosition(id);
+            accumVx += newestPosition.x - position.x;
+            accumVy += newestPosition.y - position.y;
+            duration += age;
+        } while (index != mIndex);
 
         // Make sure we used at least one sample.
-        if (samplesUsed != 0) {
-            *outVx = accumVx;
-            *outVy = accumVy;
+        if (duration >= MIN_DURATION) {
+            float scale = 1000000000.0f / duration; // one over time delta in seconds
+            *outVx = accumVx * scale;
+            *outVy = accumVy * scale;
             return true;
         }
     }
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index 25c4200..cd8bb1d 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -1717,12 +1717,11 @@
 
 
     /**
-     * @hide
-     * CANDIDATE FOR SDK
      * Registers the remote control client for providing information to display on the remote
      * controls.
-     * @param rcClient the remote control client associated responsible
-     *      for providing the information to display on the remote control.
+     * @param rcClient The remote control client from which remote controls will receive
+     *      information to display.
+     * @see RemoteControlClient
      */
     public void registerRemoteControlClient(RemoteControlClient rcClient) {
         if ((rcClient == null) || (rcClient.getRcEventReceiver() == null)) {
@@ -1741,11 +1740,9 @@
     }
 
     /**
-     * @hide
-     * CANDIDATE FOR SDK
      * Unregisters the remote control client that was providing information to display on the
-     * remotes.
-     * @param rcClient the remote control client to unregister
+     * remote controls.
+     * @param rcClient The remote control client to unregister.
      * @see #registerRemoteControlClient(RemoteControlClient)
      */
     public void unregisterRemoteControlClient(RemoteControlClient rcClient) {
diff --git a/media/java/android/media/AudioService.java b/media/java/android/media/AudioService.java
index 9d9b6ea..f5e1416 100644
--- a/media/java/android/media/AudioService.java
+++ b/media/java/android/media/AudioService.java
@@ -343,9 +343,8 @@
         readPersistedSettings();
         mSettingsObserver = new SettingsObserver();
         createStreamStates();
-        // Call setMode() to initialize mSetModeDeathHandlers
-        mMode = AudioSystem.MODE_INVALID;
-        setMode(AudioSystem.MODE_NORMAL, null);
+
+        mMode = AudioSystem.MODE_NORMAL;
         mMediaServerOk = true;
 
         // Call setRingerModeInt() to apply correct mute
@@ -768,37 +767,27 @@
         private int mPid;
         private int mMode = AudioSystem.MODE_NORMAL; // Current mode set by this client
 
-        SetModeDeathHandler(IBinder cb) {
+        SetModeDeathHandler(IBinder cb, int pid) {
             mCb = cb;
-            mPid = Binder.getCallingPid();
+            mPid = pid;
         }
 
         public void binderDied() {
+            IBinder newModeOwner = null;
             synchronized(mSetModeDeathHandlers) {
                 Log.w(TAG, "setMode() client died");
                 int index = mSetModeDeathHandlers.indexOf(this);
                 if (index < 0) {
                     Log.w(TAG, "unregistered setMode() client died");
                 } else {
-                    mSetModeDeathHandlers.remove(this);
-                    // If dead client was a the top of client list,
-                    // apply next mode in the stack
-                    if (index == 0) {
-                        // mSetModeDeathHandlers is never empty as the initial entry
-                        // created when AudioService starts is never removed
-                        SetModeDeathHandler hdlr = mSetModeDeathHandlers.get(0);
-                        int mode = hdlr.getMode();
-                        if (AudioService.this.mMode != mode) {
-                            if (AudioSystem.setPhoneState(mode) == AudioSystem.AUDIO_STATUS_OK) {
-                                AudioService.this.mMode = mode;
-                                if (mode != AudioSystem.MODE_NORMAL) {
-                                    disconnectBluetoothSco(mCb);
-                                }
-                            }
-                        }
-                    }
+                    newModeOwner = setModeInt(AudioSystem.MODE_NORMAL, mCb, mPid);
                 }
             }
+            // when entering RINGTONE, IN_CALL or IN_COMMUNICATION mode, clear all
+            // SCO connections not started by the application changing the mode
+            if (newModeOwner != null) {
+                 disconnectBluetoothSco(newModeOwner);
+            }
         }
 
         public int getPid() {
@@ -828,60 +817,97 @@
             return;
         }
 
-        synchronized (mSettingsLock) {
+        IBinder newModeOwner = null;
+        synchronized(mSetModeDeathHandlers) {
             if (mode == AudioSystem.MODE_CURRENT) {
                 mode = mMode;
             }
-            if (mode != mMode) {
+            newModeOwner = setModeInt(mode, cb, Binder.getCallingPid());
+        }
+        // when entering RINGTONE, IN_CALL or IN_COMMUNICATION mode, clear all
+        // SCO connections not started by the application changing the mode
+        if (newModeOwner != null) {
+             disconnectBluetoothSco(newModeOwner);
+        }
+    }
 
-                // automatically handle audio focus for mode changes
-                handleFocusForCalls(mMode, mode, cb);
+    // must be called synchronized on mSetModeDeathHandlers
+    // setModeInt() returns a non null IBInder if the audio mode was successfully set to
+    // any mode other than NORMAL.
+    IBinder setModeInt(int mode, IBinder cb, int pid) {
+        IBinder newModeOwner = null;
+        if (cb == null) {
+            Log.e(TAG, "setModeInt() called with null binder");
+            return newModeOwner;
+        }
 
-                if (AudioSystem.setPhoneState(mode) == AudioSystem.AUDIO_STATUS_OK) {
-                    mMode = mode;
-
-                    synchronized(mSetModeDeathHandlers) {
-                        SetModeDeathHandler hdlr = null;
-                        Iterator iter = mSetModeDeathHandlers.iterator();
-                        while (iter.hasNext()) {
-                            SetModeDeathHandler h = (SetModeDeathHandler)iter.next();
-                            if (h.getBinder() == cb) {
-                                hdlr = h;
-                                // Remove from client list so that it is re-inserted at top of list
-                                iter.remove();
-                                break;
-                            }
-                        }
-                        if (hdlr == null) {
-                            hdlr = new SetModeDeathHandler(cb);
-                            // cb is null when setMode() is called by AudioService constructor
-                            if (cb != null) {
-                                // Register for client death notification
-                                try {
-                                    cb.linkToDeath(hdlr, 0);
-                                } catch (RemoteException e) {
-                                    // Client has died!
-                                    Log.w(TAG, "setMode() could not link to "+cb+" binder death");
-                                }
-                            }
-                        }
-                        // Last client to call setMode() is always at top of client list
-                        // as required by SetModeDeathHandler.binderDied()
-                        mSetModeDeathHandlers.add(0, hdlr);
-                        hdlr.setMode(mode);
-                    }
-
-                    // when entering RINGTONE, IN_CALL or IN_COMMUNICATION mode, clear all
-                    // SCO connections not started by the application changing the mode
-                    if (mode != AudioSystem.MODE_NORMAL) {
-                        disconnectBluetoothSco(cb);
-                    }
+        SetModeDeathHandler hdlr = null;
+        Iterator iter = mSetModeDeathHandlers.iterator();
+        while (iter.hasNext()) {
+            SetModeDeathHandler h = (SetModeDeathHandler)iter.next();
+            if (h.getPid() == pid) {
+                hdlr = h;
+                // Remove from client list so that it is re-inserted at top of list
+                iter.remove();
+                hdlr.getBinder().unlinkToDeath(hdlr, 0);
+                break;
+            }
+        }
+        int status = AudioSystem.AUDIO_STATUS_OK;
+        do {
+            if (mode == AudioSystem.MODE_NORMAL) {
+                // get new mode from client at top the list if any
+                if (!mSetModeDeathHandlers.isEmpty()) {
+                    hdlr = mSetModeDeathHandlers.get(0);
+                    cb = hdlr.getBinder();
+                    mode = hdlr.getMode();
                 }
+            } else {
+                if (hdlr == null) {
+                    hdlr = new SetModeDeathHandler(cb, pid);
+                }
+                // Register for client death notification
+                try {
+                    cb.linkToDeath(hdlr, 0);
+                } catch (RemoteException e) {
+                    // Client has died!
+                    Log.w(TAG, "setMode() could not link to "+cb+" binder death");
+                }
+
+                // Last client to call setMode() is always at top of client list
+                // as required by SetModeDeathHandler.binderDied()
+                mSetModeDeathHandlers.add(0, hdlr);
+                hdlr.setMode(mode);
+            }
+
+            if (mode != mMode) {
+                status = AudioSystem.setPhoneState(mode);
+                if (status == AudioSystem.AUDIO_STATUS_OK) {
+                    // automatically handle audio focus for mode changes
+                    handleFocusForCalls(mMode, mode, cb);
+                    mMode = mode;
+                } else {
+                    if (hdlr != null) {
+                        mSetModeDeathHandlers.remove(hdlr);
+                        cb.unlinkToDeath(hdlr, 0);
+                    }
+                    // force reading new top of mSetModeDeathHandlers stack
+                    mode = AudioSystem.MODE_NORMAL;
+                }
+            } else {
+                status = AudioSystem.AUDIO_STATUS_OK;
+            }
+        } while (status != AudioSystem.AUDIO_STATUS_OK && !mSetModeDeathHandlers.isEmpty());
+
+        if (status == AudioSystem.AUDIO_STATUS_OK) {
+            if (mode != AudioSystem.MODE_NORMAL) {
+                newModeOwner = cb;
             }
             int streamType = getActiveStreamType(AudioManager.USE_DEFAULT_STREAM_TYPE);
             int index = mStreamStates[STREAM_VOLUME_ALIAS[streamType]].mIndex;
             setStreamVolumeInt(STREAM_VOLUME_ALIAS[streamType], index, true, false);
         }
+        return newModeOwner;
     }
 
     /** pre-condition: oldMode != newMode */
@@ -1345,28 +1371,30 @@
                     broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_CONNECTING);
                     // Accept SCO audio activation only in NORMAL audio mode or if the mode is
                     // currently controlled by the same client process.
-                    if ((AudioService.this.mMode == AudioSystem.MODE_NORMAL ||
-                            mSetModeDeathHandlers.get(0).getPid() == mCreatorPid) &&
-                            (mScoAudioState == SCO_STATE_INACTIVE ||
-                             mScoAudioState == SCO_STATE_DEACTIVATE_REQ)) {
-                        if (mScoAudioState == SCO_STATE_INACTIVE) {
-                            if (mBluetoothHeadset != null && mBluetoothHeadsetDevice != null) {
-                                if (mBluetoothHeadset.startScoUsingVirtualVoiceCall(
-                                        mBluetoothHeadsetDevice)) {
-                                    mScoAudioState = SCO_STATE_ACTIVE_INTERNAL;
-                                } else {
-                                    broadcastScoConnectionState(
-                                            AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
+                    synchronized(mSetModeDeathHandlers) {
+                        if ((mSetModeDeathHandlers.isEmpty() ||
+                                mSetModeDeathHandlers.get(0).getPid() == mCreatorPid) &&
+                                (mScoAudioState == SCO_STATE_INACTIVE ||
+                                 mScoAudioState == SCO_STATE_DEACTIVATE_REQ)) {
+                            if (mScoAudioState == SCO_STATE_INACTIVE) {
+                                if (mBluetoothHeadset != null && mBluetoothHeadsetDevice != null) {
+                                    if (mBluetoothHeadset.startScoUsingVirtualVoiceCall(
+                                            mBluetoothHeadsetDevice)) {
+                                        mScoAudioState = SCO_STATE_ACTIVE_INTERNAL;
+                                    } else {
+                                        broadcastScoConnectionState(
+                                                AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
+                                    }
+                                } else if (getBluetoothHeadset()) {
+                                    mScoAudioState = SCO_STATE_ACTIVATE_REQ;
                                 }
-                            } else if (getBluetoothHeadset()) {
-                                mScoAudioState = SCO_STATE_ACTIVATE_REQ;
+                            } else {
+                                mScoAudioState = SCO_STATE_ACTIVE_INTERNAL;
+                                broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_CONNECTED);
                             }
                         } else {
-                            mScoAudioState = SCO_STATE_ACTIVE_INTERNAL;
-                            broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_CONNECTED);
+                            broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
                         }
-                    } else {
-                        broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
                     }
                 } else if (state == BluetoothHeadset.STATE_AUDIO_DISCONNECTED &&
                               (mScoAudioState == SCO_STATE_ACTIVE_INTERNAL ||
diff --git a/media/java/android/media/RemoteControlClient.java b/media/java/android/media/RemoteControlClient.java
index d7b85e4..daa25e0 100644
--- a/media/java/android/media/RemoteControlClient.java
+++ b/media/java/android/media/RemoteControlClient.java
@@ -17,7 +17,6 @@
 package android.media;
 
 import android.content.ComponentName;
-import android.content.SharedPreferences.Editor;
 import android.graphics.Bitmap;
 import android.graphics.Canvas;
 import android.graphics.Paint;
@@ -31,15 +30,14 @@
 import android.util.Log;
 
 import java.lang.IllegalArgumentException;
-import java.util.HashMap;
 
 /**
- * @hide
- * CANDIDATE FOR SDK
  * RemoteControlClient enables exposing information meant to be consumed by remote controls
- * capable of displaying metadata, album art and media transport control buttons.
- * A remote control client object is associated with a media button event receiver
- * when registered through
+ * capable of displaying metadata, artwork and media transport control buttons.
+ * A remote control client object is associated with a media button event receiver. This
+ * event receiver must have been previously registered with
+ * {@link AudioManager#registerMediaButtonEventReceiver(ComponentName)} before the
+ * RemoteControlClient can be registered through
  * {@link AudioManager#registerRemoteControlClient(RemoteControlClient)}.
  */
 public class RemoteControlClient
@@ -110,7 +108,8 @@
     public final static int PLAYSTATE_ERROR              = 9;
     /**
      * @hide
-     * The value of a playback state when none has been declared
+     * The value of a playback state when none has been declared.
+     * Intentionally hidden as an application shouldn't set such a playback state value.
      */
     public final static int PLAYSTATE_NONE               = 0;
 
@@ -122,7 +121,7 @@
      */
     public final static int FLAG_KEY_MEDIA_PREVIOUS = 1 << 0;
     /**
-     * Flag indicating a RemoteControlClient makes use of the "rewing" media key.
+     * Flag indicating a RemoteControlClient makes use of the "rewind" media key.
      *
      * @see #setTransportControlFlags(int)
      * @see android.view.KeyEvent#KEYCODE_MEDIA_REWIND
@@ -173,7 +172,9 @@
 
     /**
      * @hide
-     * The flags for when no media keys are declared supported
+     * The flags for when no media keys are declared supported.
+     * Intentionally hidden as an application shouldn't set the transport control flags
+     *     to this value.
      */
     public final static int FLAGS_KEY_MEDIA_NONE = 0;
 
@@ -184,29 +185,29 @@
     public final static int FLAG_INFORMATION_REQUEST_METADATA = 1 << 0;
     /**
      * @hide
-     * FIXME doc not valid
      * Flag used to signal that the transport control buttons supported by the
-     * RemoteControlClient have changed.
+     *     RemoteControlClient are requested.
      * This can for instance happen when playback is at the end of a playlist, and the "next"
      * operation is not supported anymore.
      */
     public final static int FLAG_INFORMATION_REQUEST_KEY_MEDIA = 1 << 1;
     /**
      * @hide
-     * FIXME doc not valid
-     * Flag used to signal that the playback state of the RemoteControlClient has changed.
+     * Flag used to signal that the playback state of the RemoteControlClient is requested.
      */
     public final static int FLAG_INFORMATION_REQUEST_PLAYSTATE = 1 << 2;
     /**
      * @hide
-     * FIXME doc not valid
-     * Flag used to signal that the album art for the RemoteControlClient has changed.
+     * Flag used to signal that the album art for the RemoteControlClient is requested.
      */
     public final static int FLAG_INFORMATION_REQUEST_ALBUM_ART = 1 << 3;
 
     /**
      * Class constructor.
-     * @param mediaButtonEventReceiver the receiver for the media button events.
+     * @param mediaButtonEventReceiver The receiver for the media button events. It needs to have
+     *     been registered with {@link AudioManager#registerMediaButtonEventReceiver(ComponentName)}
+     *     before this new RemoteControlClient can itself be registered with
+     *     {@link AudioManager#registerRemoteControlClient(RemoteControlClient)}.
      * @see AudioManager#registerMediaButtonEventReceiver(ComponentName)
      * @see AudioManager#registerRemoteControlClient(RemoteControlClient)
      */
@@ -227,8 +228,11 @@
     /**
      * Class constructor for a remote control client whose internal event handling
      * happens on a user-provided Looper.
-     * @param mediaButtonEventReceiver the receiver for the media button events.
-     * @param looper the Looper running the event loop.
+     * @param mediaButtonEventReceiver The receiver for the media button events. It needs to have
+     *     been registered with {@link AudioManager#registerMediaButtonEventReceiver(ComponentName)}
+     *     before this new RemoteControlClient can itself be registered with
+     *     {@link AudioManager#registerRemoteControlClient(RemoteControlClient)}.
+     * @param looper The Looper running the event loop.
      * @see AudioManager#registerMediaButtonEventReceiver(ComponentName)
      * @see AudioManager#registerRemoteControlClient(RemoteControlClient)
      */
@@ -257,11 +261,28 @@
 
     /**
      * Class used to modify metadata in a {@link RemoteControlClient} object.
+     * Use {@link RemoteControlClient#editMetadata(boolean)} to create an instance of an editor,
+     * on which you set the metadata for the RemoteControlClient instance. Once all the information
+     * has been set, use {@link #apply()} to make it the new metadata that should be displayed
+     * for the associated client. Once the metadata has been "applied", you cannot reuse this
+     * instance of the MetadataEditor.
      */
     public class MetadataEditor {
+        /**
+         * @hide
+         */
         protected boolean mMetadataChanged;
+        /**
+         * @hide
+         */
         protected boolean mArtworkChanged;
+        /**
+         * @hide
+         */
         protected Bitmap mEditorArtwork;
+        /**
+         * @hide
+         */
         protected Bundle mEditorMetadata;
         private boolean mApplied = false;
 
@@ -277,13 +298,18 @@
         /**
          * The metadata key for the content artwork / album art.
          */
-        public final static int METADATA_KEY_ARTWORK = 100;
+        public final static int BITMAP_KEY_ARTWORK = 100;
+        /**
+         * @hide
+         * TODO(jmtrivi) have lockscreen and music move to the new key name
+         */
+        public final static int METADATA_KEY_ARTWORK = BITMAP_KEY_ARTWORK;
 
         /**
          * Adds textual information to be displayed.
          * Note that none of the information added after {@link #apply()} has been called,
          * will be displayed.
-         * @param key the identifier of a the metadata field to set. Valid values are
+         * @param key The identifier of a the metadata field to set. Valid values are
          *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_ALBUM},
          *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_ALBUMARTIST},
          *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_TITLE},
@@ -294,11 +320,11 @@
          *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_DATE},
          *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_GENRE},
          *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_TITLE},
-         *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_WRITER},
-         *      .
-         * @param value the text for the given key, or {@code null} to signify there is no valid
+         *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_WRITER}.
+         * @param value The text for the given key, or {@code null} to signify there is no valid
          *      information for the field.
-         * @return      FIXME description
+         * @return Returns a reference to the same MetadataEditor object, so you can chain put
+         *      calls together.
          */
         public synchronized MetadataEditor putString(int key, String value)
                 throws IllegalArgumentException {
@@ -315,15 +341,18 @@
         }
 
         /**
-         * FIXME javadoc
+         * Adds numerical information to be displayed.
+         * Note that none of the information added after {@link #apply()} has been called,
+         * will be displayed.
          * @param key the identifier of a the metadata field to set. Valid values are
          *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_CD_TRACK_NUMBER},
          *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_DISC_NUMBER},
          *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_DURATION} (with a value
          *      expressed in milliseconds),
          *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_YEAR}.
-         * @param value FIXME javadoc
-         * @return FIXME javadoc
+         * @param value The long value for the given key
+         * @return Returns a reference to the same MetadataEditor object, so you can chain put
+         *      calls together.
          * @throws IllegalArgumentException
          */
         public synchronized MetadataEditor putLong(int key, long value)
@@ -342,9 +371,11 @@
 
         /**
          * Sets the album / artwork picture to be displayed on the remote control.
-         * @param key FIXME description
-         * @param bitmap the bitmap for the artwork, or null if there isn't any.
-         * @return FIXME description
+         * @param key the identifier of the bitmap to set. The only valid value is
+         *      {@link #BITMAP_KEY_ARTWORK}
+         * @param bitmap The bitmap for the artwork, or null if there isn't any.
+         * @return Returns a reference to the same MetadataEditor object, so you can chain put
+         *      calls together.
          * @throws IllegalArgumentException
          * @see android.graphics.Bitmap
          */
@@ -354,7 +385,7 @@
                 Log.e(TAG, "Can't edit a previously applied MetadataEditor");
                 return this;
             }
-            if (key != METADATA_KEY_ARTWORK) {
+            if (key != BITMAP_KEY_ARTWORK) {
                 throw(new IllegalArgumentException("Invalid type 'Bitmap' for key "+ key));
             }
             if ((mArtworkExpectedWidth > 0) && (mArtworkExpectedHeight > 0)) {
@@ -369,7 +400,8 @@
         }
 
         /**
-         * FIXME description
+         * Clears all the metadata that has been set since the MetadataEditor instance was
+         *     created with {@link RemoteControlClient#editMetadata(boolean)}.
          */
         public synchronized void clear() {
             if (mApplied) {
@@ -381,7 +413,10 @@
         }
 
         /**
-         * FIXME description
+         * Associates all the metadata that has been set since the MetadataEditor instance was
+         *     created with {@link RemoteControlClient#editMetadata(boolean)}, or since
+         *     {@link #clear()} was called, with the RemoteControlClient. Once "applied",
+         *     this MetadataEditor cannot be reused to edit the RemoteControlClient's metadata.
          */
         public synchronized void apply() {
             if (mApplied) {
@@ -408,9 +443,10 @@
     }
 
     /**
-     * FIXME description
-     * @param startEmpty
-     * @return
+     * Creates a {@link MetadataEditor}.
+     * @param startEmpty Set to false if you want the MetadataEditor to contain the metadata that
+     *     was previously applied to the RemoteControlClient, or true if it is to be created empty.
+     * @return a new MetadataEditor instance.
      */
     public MetadataEditor editMetadata(boolean startEmpty) {
         MetadataEditor editor = new MetadataEditor();
@@ -430,7 +466,7 @@
 
     /**
      * Sets the current playback state.
-     * @param state the current playback state, one of the following values:
+     * @param state The current playback state, one of the following values:
      *       {@link #PLAYSTATE_STOPPED},
      *       {@link #PLAYSTATE_PAUSED},
      *       {@link #PLAYSTATE_PLAYING},
@@ -453,7 +489,7 @@
 
     /**
      * Sets the flags for the media transport control buttons that this client supports.
-     * @param a combination of the following flags:
+     * @param transportControlFlags A combination of the following flags:
      *      {@link #FLAG_KEY_MEDIA_PREVIOUS},
      *      {@link #FLAG_KEY_MEDIA_REWIND},
      *      {@link #FLAG_KEY_MEDIA_PLAY},
diff --git a/media/jni/mediaeditor/VideoEditorMain.cpp b/media/jni/mediaeditor/VideoEditorMain.cpp
index 4e954fc..ed4e92e 100755
--- a/media/jni/mediaeditor/VideoEditorMain.cpp
+++ b/media/jni/mediaeditor/VideoEditorMain.cpp
@@ -2328,6 +2328,10 @@
             break;
         }
         env->CallVoidMethod(callback, mid, (jint)k);
+        if (env->ExceptionCheck()) {
+            err = M4ERR_ALLOC;
+            break;
+        }
     }
 
     env->ReleaseIntArrayElements(pixelArray, m_dst32, 0);
@@ -2338,7 +2342,7 @@
         env->ReleaseStringUTFChars(path, pString);
     }
 
-    if (err != M4NO_ERROR) {
+    if (err != M4NO_ERROR && !env->ExceptionCheck()) {
         jniThrowException(env, "java/lang/RuntimeException",\
                 "ThumbnailGetPixels32 failed");
     }
diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp
index 7509239..c2c6715 100644
--- a/media/libmedia/AudioTrack.cpp
+++ b/media/libmedia/AudioTrack.cpp
@@ -1078,6 +1078,11 @@
         frames = mRemainingFrames;
     }
 
+    int32_t waitCount = -1;
+    if (mUpdatePeriod || (!mMarkerReached && mMarkerPosition) || mLoopCount) {
+        waitCount = 1;
+    }
+
     do {
 
         audioBuffer.frameCount = frames;
@@ -1085,7 +1090,7 @@
         // Calling obtainBuffer() with a wait count of 1
         // limits wait time to WAIT_PERIOD_MS. This prevents from being
         // stuck here not being able to handle timed events (position, markers, loops).
-        status_t err = obtainBuffer(&audioBuffer, 1);
+        status_t err = obtainBuffer(&audioBuffer, waitCount);
         if (err < NO_ERROR) {
             if (err != TIMED_OUT) {
                 LOGE_IF(err != status_t(NO_MORE_BUFFERS), "Error obtaining an audio buffer, giving up.");
diff --git a/media/libmedia/MediaScanner.cpp b/media/libmedia/MediaScanner.cpp
index 41f8593..19dedfc 100644
--- a/media/libmedia/MediaScanner.cpp
+++ b/media/libmedia/MediaScanner.cpp
@@ -16,6 +16,7 @@
 
 //#define LOG_NDEBUG 0
 #define LOG_TAG "MediaScanner"
+#include <cutils/properties.h>
 #include <utils/Log.h>
 
 #include <media/mediascanner.h>
@@ -26,11 +27,14 @@
 namespace android {
 
 MediaScanner::MediaScanner()
-    : mLocale(NULL) {
+    : mLocale(NULL), mSkipList(NULL), mSkipIndex(NULL) {
+    loadSkipList();
 }
 
 MediaScanner::~MediaScanner() {
     setLocale(NULL);
+    free(mSkipList);
+    free(mSkipIndex);
 }
 
 void MediaScanner::setLocale(const char *locale) {
@@ -47,6 +51,33 @@
     return mLocale;
 }
 
+void MediaScanner::loadSkipList() {
+    mSkipList = (char *)malloc(PROPERTY_VALUE_MAX * sizeof(char));
+    if (mSkipList) {
+      property_get("testing.mediascanner.skiplist", mSkipList, "");
+    }
+    if (!mSkipList || (strlen(mSkipList) == 0)) {
+        free(mSkipList);
+        mSkipList = NULL;
+        return;
+    }
+    mSkipIndex = (int *)malloc(PROPERTY_VALUE_MAX * sizeof(int));
+    if (mSkipIndex) {
+        // dup it because strtok will modify the string
+        char *skipList = strdup(mSkipList);
+        if (skipList) {
+            char * path = strtok(skipList, ",");
+            int i = 0;
+            while (path) {
+                mSkipIndex[i++] = strlen(path);
+                path = strtok(NULL, ",");
+            }
+            mSkipIndex[i] = -1;
+            free(skipList);
+        }
+    }
+}
+
 MediaScanResult MediaScanner::processDirectory(
         const char *path, MediaScannerClient &client) {
     int pathLength = strlen(path);
@@ -75,12 +106,39 @@
     return result;
 }
 
+bool MediaScanner::shouldSkipDirectory(char *path) {
+    if (path && mSkipList && mSkipIndex) {
+        int len = strlen(path);
+        int idx = 0;
+        // track the start position of next path in the comma
+        // separated list obtained from getprop
+        int startPos = 0;
+        while (mSkipIndex[idx] != -1) {
+            // no point to match path name if strlen mismatch
+            if ((len == mSkipIndex[idx])
+                // pick out the path segment from comma separated list
+                // to compare against current path parameter
+                && (strncmp(path, &mSkipList[startPos], len) == 0)) {
+                return true;
+            }
+            startPos += mSkipIndex[idx] + 1; // extra char for the delimiter
+            idx++;
+        }
+    }
+    return false;
+}
+
 MediaScanResult MediaScanner::doProcessDirectory(
         char *path, int pathRemaining, MediaScannerClient &client, bool noMedia) {
     // place to copy file or directory name
     char* fileSpot = path + strlen(path);
     struct dirent* entry;
 
+    if (shouldSkipDirectory(path)) {
+      LOGD("Skipping: %s", path);
+      return MEDIA_SCAN_RESULT_OK;
+    }
+
     // Treat all files as non-media in directories that contain a  ".nomedia" file
     if (pathRemaining >= 8 /* strlen(".nomedia") */ ) {
         strcpy(fileSpot, ".nomedia");
diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp
index fb49d7b..9ab470b 100755
--- a/media/libstagefright/OMXCodec.cpp
+++ b/media/libstagefright/OMXCodec.cpp
@@ -50,7 +50,7 @@
 
 // Treat time out as an error if we have not received any output
 // buffers after 3 seconds.
-const static int64_t kBufferFilledEventTimeOutUs = 3000000000LL;
+const static int64_t kBufferFilledEventTimeOutNs = 3000000000LL;
 
 struct CodecInfo {
     const char *mime;
@@ -2325,9 +2325,14 @@
         {
             CODEC_LOGV("OMX_EventPortSettingsChanged(port=%ld, data2=0x%08lx)",
                        data1, data2);
-            CHECK(mFilledBuffers.empty());
 
             if (data2 == 0 || data2 == OMX_IndexParamPortDefinition) {
+                // There is no need to check whether mFilledBuffers is empty or not
+                // when the OMX_EventPortSettingsChanged is not meant for reallocating
+                // the output buffers.
+                if (data1 == kPortIndexOutput) {
+                    CHECK(mFilledBuffers.empty());
+                }
                 onPortSettingsChanged(data1);
             } else if (data1 == kPortIndexOutput &&
                         (data2 == OMX_IndexConfigCommonOutputCrop ||
@@ -3220,7 +3225,7 @@
         // for video encoding.
         return mBufferFilled.wait(mLock);
     }
-    status_t err = mBufferFilled.waitRelative(mLock, kBufferFilledEventTimeOutUs);
+    status_t err = mBufferFilled.waitRelative(mLock, kBufferFilledEventTimeOutNs);
     if (err != OK) {
         CODEC_LOGE("Timed out waiting for output buffers: %d/%d",
             countBuffersWeOwn(mPortBuffers[kPortIndexInput]),
diff --git a/media/libstagefright/SurfaceMediaSource.cpp b/media/libstagefright/SurfaceMediaSource.cpp
index 50dd804..306f1f6 100644
--- a/media/libstagefright/SurfaceMediaSource.cpp
+++ b/media/libstagefright/SurfaceMediaSource.cpp
@@ -13,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-// #define LOG_NDEBUG 0
+//#define LOG_NDEBUG 0
 #define LOG_TAG "SurfaceMediaSource"
 
 #include <media/stagefright/SurfaceMediaSource.h>
@@ -458,6 +458,10 @@
     LOGV("queueBuffer");
 
     Mutex::Autolock lock(mMutex);
+    *outWidth = mDefaultWidth;
+    *outHeight = mDefaultHeight;
+    *outTransform = 0;
+
     if (bufIndex < 0 || bufIndex >= mBufferCount) {
         LOGE("queueBuffer: slot index out of range [0, %d]: %d",
                 mBufferCount, bufIndex);
@@ -518,9 +522,6 @@
     // buffer is available
     onFrameReceivedLocked();
 
-    *outWidth = mDefaultWidth;
-    *outHeight = mDefaultHeight;
-    *outTransform = 0;
 
     return OK;
 }
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaProfileReader.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaProfileReader.java
index b1ad315..b1d049e 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaProfileReader.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaProfileReader.java
@@ -95,6 +95,25 @@
         return audioEncoderMap.get(audioEncoder);
     }
 
+    public static int getMinFrameRateForCodec(int codec) {
+        return getMinOrMaxFrameRateForCodec(codec, false);
+    }
+
+    public static int getMaxFrameRateForCodec(int codec) {
+        return getMinOrMaxFrameRateForCodec(codec, true);
+    }
+
+    private static int getMinOrMaxFrameRateForCodec(int codec, boolean max) {
+        for (VideoEncoderCap cap: videoEncoders) {
+            if (cap.mCodec == codec) {
+                if (max) return cap.mMaxFrameRate;
+                else return cap.mMinFrameRate;
+            }
+        }
+        // Should never reach here
+        throw new IllegalArgumentException("Unsupported video codec " + codec);
+    }
+
     private MediaProfileReader() {} // Don't call me
 
     private static void initVideoEncoderMap() {
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaItemThumbnailTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaItemThumbnailTest.java
index 154f691..d5b67aa 100755
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaItemThumbnailTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaItemThumbnailTest.java
@@ -657,7 +657,7 @@
     public void testThumbnailListForH264WVGAWithCount() throws Exception {
         final String videoItemFilename = INPUT_FILE_PATH +
             "H264_BP_800x480_15fps_512kbps_AACLC_24KHz_38Kbps_s_1_17.mp4";
-        final int tnCount = 100;
+        final int tnCount = 70;
         final int renderingMode = MediaItem.RENDERING_MODE_BLACK_BORDER;
         final MediaVideoItem mediaVideoItem =
             mVideoEditorHelper.createMediaItem(mVideoEditor, "m1",
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaRecorderTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaRecorderTest.java
index 82df6690..796b52c 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaRecorderTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaRecorderTest.java
@@ -247,7 +247,9 @@
             mCamera.unlock();
             mRecorder.setCamera(mCamera);
             Thread.sleep(1000);
-            recordVideo(15, 352, 288, MediaRecorder.VideoEncoder.H263,
+            int codec = MediaRecorder.VideoEncoder.H263;
+            int frameRate = MediaProfileReader.getMaxFrameRateForCodec(codec);
+            recordVideo(frameRate, 352, 288, codec,
                     MediaRecorder.OutputFormat.THREE_GPP, 
                     MediaNames.RECORDED_PORTRAIT_H263, true);
             mCamera.lock();
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/performance/MediaPlayerPerformance.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/performance/MediaPlayerPerformance.java
index 0f79515..0b887b9 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/performance/MediaPlayerPerformance.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/performance/MediaPlayerPerformance.java
@@ -365,16 +365,6 @@
         assertTrue("H264 playback memory test", memoryResult);
     }
 
-    private int getMaxFrameRateForVideoEncoder(int codec) {
-        int frameRate = -1;
-        for (VideoEncoderCap cap: videoEncoders) {
-            if (cap.mCodec == MediaRecorder.VideoEncoder.H263) {
-                frameRate = cap.mMaxFrameRate;
-            }
-        }
-        return frameRate;
-    }
-
     // Test case 4: Capture the memory usage after every 20 video only recorded
     @LargeTest
     public void testH263RecordVideoOnlyMemoryUsage() throws Exception {
@@ -384,7 +374,7 @@
         File videoH263RecordOnlyMemoryOut = new File(MEDIA_MEMORY_OUTPUT);
         Writer output = new BufferedWriter(new FileWriter(videoH263RecordOnlyMemoryOut, true));
         output.write("H263 video record only\n");
-        int frameRate = getMaxFrameRateForVideoEncoder(MediaRecorder.VideoEncoder.H263);
+        int frameRate = MediaProfileReader.getMaxFrameRateForCodec(MediaRecorder.VideoEncoder.H263);
         assertTrue("H263 video recording frame rate", frameRate != -1);
         for (int i = 0; i < NUM_STRESS_LOOP; i++) {
             assertTrue(stressVideoRecord(frameRate, 352, 288, MediaRecorder.VideoEncoder.H263,
@@ -406,7 +396,7 @@
         File videoMp4RecordOnlyMemoryOut = new File(MEDIA_MEMORY_OUTPUT);
         Writer output = new BufferedWriter(new FileWriter(videoMp4RecordOnlyMemoryOut, true));
         output.write("MPEG4 video record only\n");
-        int frameRate = getMaxFrameRateForVideoEncoder(MediaRecorder.VideoEncoder.MPEG_4_SP);
+        int frameRate = MediaProfileReader.getMaxFrameRateForCodec(MediaRecorder.VideoEncoder.MPEG_4_SP);
         assertTrue("MPEG4 video recording frame rate", frameRate != -1);
         for (int i = 0; i < NUM_STRESS_LOOP; i++) {
             assertTrue(stressVideoRecord(frameRate, 352, 288, MediaRecorder.VideoEncoder.MPEG_4_SP,
@@ -428,7 +418,7 @@
 
         File videoRecordAudioMemoryOut = new File(MEDIA_MEMORY_OUTPUT);
         Writer output = new BufferedWriter(new FileWriter(videoRecordAudioMemoryOut, true));
-        int frameRate = getMaxFrameRateForVideoEncoder(MediaRecorder.VideoEncoder.H263);
+        int frameRate = MediaProfileReader.getMaxFrameRateForCodec(MediaRecorder.VideoEncoder.H263);
         assertTrue("H263 video recording frame rate", frameRate != -1);
         output.write("Audio and h263 video record\n");
         for (int i = 0; i < NUM_STRESS_LOOP; i++) {
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/stress/MediaRecorderStressTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/stress/MediaRecorderStressTest.java
index ae0589c..e6177ba 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/stress/MediaRecorderStressTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/stress/MediaRecorderStressTest.java
@@ -205,7 +205,7 @@
                 mRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
                 mRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
                 mRecorder.setOutputFile(filename);
-                mRecorder.setVideoFrameRate(20);
+                mRecorder.setVideoFrameRate(MediaRecorderStressTestRunner.mFrameRate);
                 mRecorder.setVideoSize(176,144);
                 Log.v(TAG, "setEncoder");
                 mRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H263);
@@ -269,7 +269,7 @@
                 mRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
                 mRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
                 mRecorder.setOutputFile(filename);
-                mRecorder.setVideoFrameRate(20);
+                mRecorder.setVideoFrameRate(MediaRecorderStressTestRunner.mFrameRate);
                 mRecorder.setVideoSize(176,144);
                 Log.v(TAG, "Media recorder setEncoder");
                 mRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H263);
diff --git a/packages/SystemUI/res/drawable-hdpi/recents_thumbnail_bg_dragging.9.png b/packages/SystemUI/res/drawable-hdpi/recents_thumbnail_bg_dragging.9.png
index 1ad16f7..652f66f 100644
--- a/packages/SystemUI/res/drawable-hdpi/recents_thumbnail_bg_dragging.9.png
+++ b/packages/SystemUI/res/drawable-hdpi/recents_thumbnail_bg_dragging.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/recents_thumbnail_bg_press.9.png b/packages/SystemUI/res/drawable-hdpi/recents_thumbnail_bg_press.9.png
index 6e806ee..288d818 100644
--- a/packages/SystemUI/res/drawable-hdpi/recents_thumbnail_bg_press.9.png
+++ b/packages/SystemUI/res/drawable-hdpi/recents_thumbnail_bg_press.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/status_bar_close_on.9.png b/packages/SystemUI/res/drawable-hdpi/status_bar_close_on.9.png
index 35d0a06..0f0cbf1 100644
--- a/packages/SystemUI/res/drawable-hdpi/status_bar_close_on.9.png
+++ b/packages/SystemUI/res/drawable-hdpi/status_bar_close_on.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/recents_thumbnail_bg_dragging.9.png b/packages/SystemUI/res/drawable-mdpi/recents_thumbnail_bg_dragging.9.png
index 0352aca..6f4d658 100644
--- a/packages/SystemUI/res/drawable-mdpi/recents_thumbnail_bg_dragging.9.png
+++ b/packages/SystemUI/res/drawable-mdpi/recents_thumbnail_bg_dragging.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/recents_thumbnail_bg_press.9.png b/packages/SystemUI/res/drawable-mdpi/recents_thumbnail_bg_press.9.png
index 7376085..10e4fd2 100644
--- a/packages/SystemUI/res/drawable-mdpi/recents_thumbnail_bg_press.9.png
+++ b/packages/SystemUI/res/drawable-mdpi/recents_thumbnail_bg_press.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/status_bar_close_on.9.png b/packages/SystemUI/res/drawable-mdpi/status_bar_close_on.9.png
index 79da092..5e8a116 100644
--- a/packages/SystemUI/res/drawable-mdpi/status_bar_close_on.9.png
+++ b/packages/SystemUI/res/drawable-mdpi/status_bar_close_on.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/recents_thumbnail_bg_dragging.9.png b/packages/SystemUI/res/drawable-xhdpi/recents_thumbnail_bg_dragging.9.png
new file mode 100644
index 0000000..1d097c5
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/recents_thumbnail_bg_dragging.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/recents_thumbnail_bg_press.9.png b/packages/SystemUI/res/drawable-xhdpi/recents_thumbnail_bg_press.9.png
index 507ee22..5bae56d 100644
--- a/packages/SystemUI/res/drawable-xhdpi/recents_thumbnail_bg_press.9.png
+++ b/packages/SystemUI/res/drawable-xhdpi/recents_thumbnail_bg_press.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/status_bar_close_on.9.png b/packages/SystemUI/res/drawable-xhdpi/status_bar_close_on.9.png
new file mode 100644
index 0000000..efac368
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/status_bar_close_on.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable/recents_thumbnail_fg.xml b/packages/SystemUI/res/drawable/recents_thumbnail_fg.xml
new file mode 100644
index 0000000..d683af9
--- /dev/null
+++ b/packages/SystemUI/res/drawable/recents_thumbnail_fg.xml
@@ -0,0 +1,20 @@
+<?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.
+-->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:drawable="@drawable/recents_thumbnail_bg_press" android:state_selected="true" />
+    <item android:drawable="@drawable/recents_thumbnail_bg_press" android:state_pressed="true" />
+    <item android:drawable="@*android:color/transparent"/>
+</selector>
diff --git a/packages/SystemUI/res/layout-land/status_bar_recent_item.xml b/packages/SystemUI/res/layout-land/status_bar_recent_item.xml
index 4b2468a..eae3e52 100644
--- a/packages/SystemUI/res/layout-land/status_bar_recent_item.xml
+++ b/packages/SystemUI/res/layout-land/status_bar_recent_item.xml
@@ -21,7 +21,9 @@
 <FrameLayout
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_height="match_parent"
-    android:layout_width="wrap_content">
+    android:layout_width="wrap_content"
+    android:paddingLeft="@dimen/status_bar_recents_item_padding"
+    android:paddingRight="@dimen/status_bar_recents_item_padding">
 
     <RelativeLayout android:id="@+id/recent_item"
         android:layout_gravity="bottom"
@@ -35,12 +37,11 @@
             android:layout_alignParentLeft="true"
             android:layout_alignParentTop="true"
             android:layout_marginLeft="@dimen/status_bar_recents_thumbnail_left_margin"
-            android:scaleType="center"
-            android:background="@drawable/recents_thumbnail_bg">
+            android:background="@drawable/recents_thumbnail_bg"
+            android:foreground="@drawable/recents_thumbnail_fg">
             <ImageView android:id="@+id/app_thumbnail_image"
-                android:layout_width="match_parent"
-                android:layout_height="match_parent"
-                android:visibility="invisible"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
             />
         </FrameLayout>
 
diff --git a/packages/SystemUI/res/layout-port/status_bar_recent_item.xml b/packages/SystemUI/res/layout-port/status_bar_recent_item.xml
index a327d42..b14ef595 100644
--- a/packages/SystemUI/res/layout-port/status_bar_recent_item.xml
+++ b/packages/SystemUI/res/layout-port/status_bar_recent_item.xml
@@ -21,7 +21,9 @@
 <FrameLayout
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_height="wrap_content"
-    android:layout_width="match_parent">
+    android:layout_width="match_parent"
+    android:paddingTop="@dimen/status_bar_recents_item_padding"
+    android:paddingBottom="@dimen/status_bar_recents_item_padding">
 
     <RelativeLayout android:id="@+id/recent_item"
         android:layout_height="wrap_content"
@@ -33,12 +35,11 @@
             android:layout_alignParentLeft="true"
             android:layout_alignParentTop="true"
             android:layout_marginLeft="@dimen/status_bar_recents_thumbnail_left_margin"
-            android:scaleType="center"
-            android:background="@drawable/recents_thumbnail_bg">
+            android:background="@drawable/recents_thumbnail_bg"
+            android:foreground="@drawable/recents_thumbnail_fg">
             <ImageView android:id="@+id/app_thumbnail_image"
-                android:layout_width="match_parent"
-                android:layout_height="match_parent"
-                android:visibility="invisible"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
             />
         </FrameLayout>
 
diff --git a/packages/SystemUI/res/layout-sw600dp/status_bar_recent_item.xml b/packages/SystemUI/res/layout-sw600dp/status_bar_recent_item.xml
index 0f45bcd..f4be651 100644
--- a/packages/SystemUI/res/layout-sw600dp/status_bar_recent_item.xml
+++ b/packages/SystemUI/res/layout-sw600dp/status_bar_recent_item.xml
@@ -30,11 +30,11 @@
         android:layout_alignParentTop="true"
         android:layout_marginLeft="@dimen/status_bar_recents_thumbnail_left_margin"
         android:scaleType="center"
-        android:background="@drawable/recents_thumbnail_bg">
+        android:background="@drawable/recents_thumbnail_bg"
+        android:foreground="@drawable/recents_thumbnail_fg">
         <ImageView android:id="@+id/app_thumbnail_image"
-            android:layout_width="match_parent"
-            android:layout_height="match_parent"
-            android:visibility="invisible"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
         />
     </FrameLayout>
 
diff --git a/packages/SystemUI/res/values-hdpi/dimens.xml b/packages/SystemUI/res/values-hdpi/dimens.xml
index 277626e..6b6fd4d 100644
--- a/packages/SystemUI/res/values-hdpi/dimens.xml
+++ b/packages/SystemUI/res/values-hdpi/dimens.xml
@@ -16,10 +16,6 @@
 */
 -->
 <resources>
-    <!-- padding of pressed drawable for recents thumbnails (should be the same on left, right,
-         top, and bottom -->
-    <dimen name="recents_thumbnail_bg_press_padding">3px</dimen>
-
     <!-- thickness (height) of each notification row, including any separators or padding -->
     <!-- Note: this is 64dip + 1px divider = 97px. -->
     <dimen name="notification_height">97px</dimen>
diff --git a/packages/SystemUI/res/values-land/dimens.xml b/packages/SystemUI/res/values-land/dimens.xml
index ca74b8b..32ebc80 100644
--- a/packages/SystemUI/res/values-land/dimens.xml
+++ b/packages/SystemUI/res/values-land/dimens.xml
@@ -21,7 +21,7 @@
 
     <!-- Recent Applications parameters -->
     <!-- How far the thumbnail for a recent app appears from left edge -->
-    <dimen name="status_bar_recents_thumbnail_left_margin">8dp</dimen>
+    <dimen name="status_bar_recents_thumbnail_left_margin">0dp</dimen>
     <!-- How far the thumbnail for a recent app appears from top edge -->
     <dimen name="status_bar_recents_thumbnail_top_margin">12dp</dimen>
     <!-- Padding for text descriptions -->
@@ -32,4 +32,6 @@
     <dimen name="status_bar_recents_app_label_left_margin">16dip</dimen>
     <!-- Margin between recents container and glow on the right -->
     <dimen name="status_bar_recents_right_glow_margin">0dip</dimen>
+    <!-- Padding between recents items -->
+    <dimen name="status_bar_recents_item_padding">2dip</dimen>
 </resources>
diff --git a/packages/SystemUI/res/values-mdpi/dimens.xml b/packages/SystemUI/res/values-mdpi/dimens.xml
deleted file mode 100644
index d16d549b..0000000
--- a/packages/SystemUI/res/values-mdpi/dimens.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<?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.
-*/
--->
-<resources>
-    <!-- padding of pressed drawable for recents thumbnails (should be the same on left, right,
-         top, and bottom -->
-    <dimen name="recents_thumbnail_bg_press_padding">2px</dimen>
-</resources>
diff --git a/packages/SystemUI/res/values-port/dimens.xml b/packages/SystemUI/res/values-port/dimens.xml
index b89a610..2bafd30 100644
--- a/packages/SystemUI/res/values-port/dimens.xml
+++ b/packages/SystemUI/res/values-port/dimens.xml
@@ -22,9 +22,11 @@
     <!-- Padding for text descriptions -->
     <dimen name="status_bar_recents_text_description_padding">8dp</dimen>
     <!-- Width of application label text -->
-    <dimen name="status_bar_recents_app_label_width">97dip</dimen>
+    <dimen name="status_bar_recents_app_label_width">88dip</dimen>
     <!-- Left margin of application label text -->
-    <dimen name="status_bar_recents_app_label_left_margin">8dip</dimen>
+    <dimen name="status_bar_recents_app_label_left_margin">16dip</dimen>
     <!-- Margin between recents container and glow on the right -->
     <dimen name="status_bar_recents_right_glow_margin">100dip</dimen>
+    <!-- Padding between recents items -->
+    <dimen name="status_bar_recents_item_padding">0dip</dimen>
 </resources>
diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java b/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java
index 43905dd..f7afe3a 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java
@@ -85,7 +85,6 @@
     private View mRecentsGlowView;
     private ViewGroup mRecentsContainer;
     private Bitmap mDefaultThumbnailBackground;
-    private BitmapDrawable mPressedDrawable;
 
     private boolean mShowing;
     private Choreographer mChoreo;
@@ -96,11 +95,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 +109,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;
         }
@@ -184,12 +186,12 @@
                 holder.labelView = (TextView) convertView.findViewById(R.id.app_label);
                 holder.descriptionView = (TextView) convertView.findViewById(R.id.app_description);
 
-                StateListDrawable thumbnailForegroundDrawable = new StateListDrawable();
+		/*                StateListDrawable thumbnailForegroundDrawable = new StateListDrawable();
                 thumbnailForegroundDrawable.addState(new int[] { android.R.attr.state_pressed },
                         mPressedDrawable);
                 thumbnailForegroundDrawable.addState(new int[] { android.R.attr.state_selected },
                         mPressedDrawable);
-                ((FrameLayout)holder.thumbnailView).setForeground(thumbnailForegroundDrawable);
+			((FrameLayout)holder.thumbnailView).setForeground(thumbnailForegroundDrawable);*/
                 convertView.setTag(holder);
             } else {
                 holder = (ViewHolder) convertView.getTag();
@@ -352,18 +354,6 @@
         mDefaultThumbnailBackground = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
         Canvas c = new Canvas(mDefaultThumbnailBackground);
         c.drawColor(color);
-
-        // Render the pressed state (setting the 9 patch drawable directly causes padding issues)
-        int bgPadding = (int) res.getDimension(R.dimen.recents_thumbnail_bg_press_padding);
-        Bitmap pressedOverlay = Bitmap.createBitmap(
-                width + 2 * bgPadding, height + 2 * bgPadding, Bitmap.Config.ARGB_8888);
-        c.setBitmap(pressedOverlay);
-
-        Drawable pressedDrawable9Patch = res.getDrawable(R.drawable.recents_thumbnail_bg_press);
-        pressedDrawable9Patch.getCurrent().setBounds(
-                0, 0, pressedOverlay.getWidth(), pressedOverlay.getHeight());
-        pressedDrawable9Patch.draw(c);
-        mPressedDrawable = new BitmapDrawable(res, pressedOverlay);
     }
 
     @Override
@@ -496,17 +486,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 +717,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/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
index 6ec3443..ee9aa41 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -1174,7 +1174,6 @@
                 case MSG_OPEN_RECENTS_PANEL:
                     if (DEBUG) Slog.d(TAG, "opening recents panel");
                     if (mRecentsPanel != null) {
-                        disable(StatusBarManager.DISABLE_BACK);
                         mRecentsPanel.setVisibility(View.VISIBLE);
                         mRecentsPanel.show(true, true);
                     }
@@ -1182,7 +1181,6 @@
                 case MSG_CLOSE_RECENTS_PANEL:
                     if (DEBUG) Slog.d(TAG, "closing recents panel");
                     if (mRecentsPanel != null && mRecentsPanel.isShowing()) {
-                        disable(StatusBarManager.DISABLE_NONE);
                         mRecentsPanel.show(false, true);
                     }
                     break;
@@ -1797,30 +1795,34 @@
                 pw.println("    [" + i + "] icon=" + ic);
             }
             
-            pw.println("see the logcat for a dump of the views we have created.");
-            // must happen on ui thread
-            mHandler.post(new Runnable() {
-                    public void run() {
-                        mStatusBarView.getLocationOnScreen(mAbsPos);
-                        Slog.d(TAG, "mStatusBarView: ----- (" + mAbsPos[0] + "," + mAbsPos[1]
-                                + ") " + mStatusBarView.getWidth() + "x"
-                                + mStatusBarView.getHeight());
-                        mStatusBarView.debug();
+            if (false) {
+                pw.println("see the logcat for a dump of the views we have created.");
+                // must happen on ui thread
+                mHandler.post(new Runnable() {
+                        public void run() {
+                            mStatusBarView.getLocationOnScreen(mAbsPos);
+                            Slog.d(TAG, "mStatusBarView: ----- (" + mAbsPos[0] + "," + mAbsPos[1]
+                                    + ") " + mStatusBarView.getWidth() + "x"
+                                    + mStatusBarView.getHeight());
+                            mStatusBarView.debug();
 
-                        mExpandedView.getLocationOnScreen(mAbsPos);
-                        Slog.d(TAG, "mExpandedView: ----- (" + mAbsPos[0] + "," + mAbsPos[1]
-                                + ") " + mExpandedView.getWidth() + "x"
-                                + mExpandedView.getHeight());
-                        mExpandedView.debug();
+                            mExpandedView.getLocationOnScreen(mAbsPos);
+                            Slog.d(TAG, "mExpandedView: ----- (" + mAbsPos[0] + "," + mAbsPos[1]
+                                    + ") " + mExpandedView.getWidth() + "x"
+                                    + mExpandedView.getHeight());
+                            mExpandedView.debug();
 
-                        mTrackingView.getLocationOnScreen(mAbsPos);
-                        Slog.d(TAG, "mTrackingView: ----- (" + mAbsPos[0] + "," + mAbsPos[1]
-                                + ") " + mTrackingView.getWidth() + "x"
-                                + mTrackingView.getHeight());
-                        mTrackingView.debug();
-                    }
-                });
+                            mTrackingView.getLocationOnScreen(mAbsPos);
+                            Slog.d(TAG, "mTrackingView: ----- (" + mAbsPos[0] + "," + mAbsPos[1]
+                                    + ") " + mTrackingView.getWidth() + "x"
+                                    + mTrackingView.getHeight());
+                            mTrackingView.debug();
+                        }
+                    });
+            }
         }
+
+        mNetworkController.dump(fd, pw, args);
     }
 
     void onBarViewAttached() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DateView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DateView.java
index d3f9525..c19550b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DateView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DateView.java
@@ -22,11 +22,9 @@
 import android.content.IntentFilter;
 import android.text.format.DateFormat;
 import android.util.AttributeSet;
-import android.util.Slog;
-import android.widget.TextView;
-import android.view.MotionEvent;
 import android.view.View;
 import android.view.ViewParent;
+import android.widget.TextView;
 
 import com.android.systemui.R;
 
@@ -42,9 +40,10 @@
     private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
         @Override
         public void onReceive(Context context, Intent intent) {
-            String action = intent.getAction();
-            if (action.equals(Intent.ACTION_TIME_TICK)
-                    || action.equals(Intent.ACTION_TIMEZONE_CHANGED)) {
+            final String action = intent.getAction();
+            if (Intent.ACTION_TIME_TICK.equals(action)
+                    || Intent.ACTION_TIME_CHANGED.equals(action)
+                    || Intent.ACTION_TIMEZONE_CHANGED.equals(action)) {
                 updateClock();
             }
         }
@@ -118,6 +117,7 @@
                 // Register for Intent broadcasts for the clock and battery
                 IntentFilter filter = new IntentFilter();
                 filter.addAction(Intent.ACTION_TIME_TICK);
+                filter.addAction(Intent.ACTION_TIME_CHANGED);
                 filter.addAction(Intent.ACTION_TIMEZONE_CHANGED);
                 mContext.registerReceiver(mIntentReceiver, filter, null, null);
                 updateClock();
@@ -127,4 +127,3 @@
         }
     }
 }
-
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java
index 3c85814..b50ebcd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java
@@ -296,6 +296,7 @@
             }
             mServiceState = state;
             updateTelephonySignalStrength();
+            updateDataNetType();
             updateDataIcon();
             refreshViews();
         }
@@ -831,7 +832,12 @@
                 mHasMobileDataFeature ? mDataSignalIconId : mWifiIconId;
             mContentDescriptionCombinedSignal = mHasMobileDataFeature
                 ? mContentDescriptionDataType : mContentDescriptionWifi;
-            mDataTypeIconId = 0;
+
+            if ((isCdma() && isCdmaEri()) || mPhone.isNetworkRoaming()) {
+                mDataTypeIconId = R.drawable.stat_sys_data_connected_roam;
+            } else {
+                mDataTypeIconId = 0;
+            }
         }
 
         if (DEBUG) {
@@ -969,6 +975,7 @@
     }
 
     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+        pw.println("Network Controller state:");
         pw.println("  - telephony ------");
         pw.print("  mHspaDataDistinguishable=");
         pw.println(mHspaDataDistinguishable);
@@ -982,6 +989,10 @@
         pw.println(mDataState);
         pw.print("  mDataActivity=");
         pw.println(mDataActivity);
+        pw.print("  mDataNetType=");
+        pw.print(mDataNetType);
+        pw.print("/");
+        pw.println(TelephonyManager.getNetworkTypeName(mDataNetType));
         pw.print("  mServiceState=");
         pw.println(mServiceState);
         pw.print("  mNetworkName=");
@@ -989,7 +1000,7 @@
         pw.print("  mNetworkNameDefault=");
         pw.println(mNetworkNameDefault);
         pw.print("  mNetworkNameSeparator=");
-        pw.println(mNetworkNameSeparator);
+        pw.println(mNetworkNameSeparator.replace("\n","\\n"));
         pw.print("  mPhoneSignalIconId=0x");
         pw.print(Integer.toHexString(mPhoneSignalIconId));
         pw.print("/");
@@ -1060,7 +1071,7 @@
     }
 
     private String getResourceName(int resId) {
-        if (resId == 0) {
+        if (resId != 0) {
             final Resources res = mContext.getResources();
             try {
                 return res.getResourceName(resId);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/InputMethodsPanel.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/InputMethodsPanel.java
index 5911378..e406a0c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/InputMethodsPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/InputMethodsPanel.java
@@ -218,15 +218,16 @@
 
     private View createInputMethodItem(
             final InputMethodInfo imi, final InputMethodSubtype subtype) {
-        CharSequence subtypeName = getSubtypeName(imi, subtype);
-        CharSequence imiName = getIMIName(imi);
-        Drawable icon = getSubtypeIcon(imi, subtype);
-        View view = View.inflate(mContext, R.layout.status_bar_input_methods_item, null);
-        ImageView subtypeIcon = (ImageView)view.findViewById(R.id.item_icon);
-        TextView itemTitle = (TextView)view.findViewById(R.id.item_title);
-        TextView itemSubtitle = (TextView)view.findViewById(R.id.item_subtitle);
-        ImageView settingsIcon = (ImageView)view.findViewById(R.id.item_settings_icon);
-        View subtypeView = view.findViewById(R.id.item_subtype);
+        final CharSequence subtypeName = subtype.overridesImplicitlyEnabledSubtype()
+                ? null : getSubtypeName(imi, subtype);
+        final CharSequence imiName = getIMIName(imi);
+        final Drawable icon = getSubtypeIcon(imi, subtype);
+        final View view = View.inflate(mContext, R.layout.status_bar_input_methods_item, null);
+        final ImageView subtypeIcon = (ImageView)view.findViewById(R.id.item_icon);
+        final TextView itemTitle = (TextView)view.findViewById(R.id.item_title);
+        final TextView itemSubtitle = (TextView)view.findViewById(R.id.item_subtitle);
+        final ImageView settingsIcon = (ImageView)view.findViewById(R.id.item_settings_icon);
+        final View subtypeView = view.findViewById(R.id.item_subtype);
         if (subtypeName == null) {
             itemTitle.setText(imiName);
             itemSubtitle.setVisibility(View.GONE);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java
index b4c480b..39011d3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java
@@ -301,6 +301,7 @@
         mRecentsPanel = (RecentsPanelView) View.inflate(context,
                 R.layout.status_bar_recent_panel, null);
         mRecentsPanel.setVisibility(View.GONE);
+        mRecentsPanel.setSystemUiVisibility(View.STATUS_BAR_DISABLE_BACK);
         mRecentsPanel.setOnTouchListener(new TouchOutsideListener(MSG_CLOSE_RECENTS_PANEL,
                 mRecentsPanel));
         mStatusBarView.setIgnoreChildren(2, mRecentButton, mRecentsPanel);
@@ -436,6 +437,13 @@
 
         sb.setHandler(mHandler);
 
+        // Sanity-check that someone hasn't set up the config wrong and asked for a navigation bar
+        // on a tablet that has only the system bar
+        if (mContext.getResources().getBoolean(
+                com.android.internal.R.bool.config_showNavigationBar)) {
+            throw new RuntimeException("Tablet device cannot show navigation bar and system bar");
+        }
+
         mBarContents = (ViewGroup) sb.findViewById(R.id.bar_contents);
         // layout transitions for the status bar's contents
         mBarContentsLayoutTransition = new LayoutTransition();
@@ -705,7 +713,6 @@
                 case MSG_OPEN_RECENTS_PANEL:
                     if (DEBUG) Slog.d(TAG, "opening recents panel");
                     if (mRecentsPanel != null) {
-                        disable(StatusBarManager.DISABLE_BACK);
                         mRecentsPanel.setVisibility(View.VISIBLE);
                         mRecentsPanel.show(true, true);
                     }
@@ -713,7 +720,6 @@
                 case MSG_CLOSE_RECENTS_PANEL:
                     if (DEBUG) Slog.d(TAG, "closing recents panel");
                     if (mRecentsPanel != null && mRecentsPanel.isShowing()) {
-                        disable(StatusBarManager.DISABLE_NONE);
                         mRecentsPanel.show(false, true);
                     }
                     break;
diff --git a/policy/src/com/android/internal/policy/impl/KeyguardViewBase.java b/policy/src/com/android/internal/policy/impl/KeyguardViewBase.java
index 74dde9c..2fcf1dc3 100644
--- a/policy/src/com/android/internal/policy/impl/KeyguardViewBase.java
+++ b/policy/src/com/android/internal/policy/impl/KeyguardViewBase.java
@@ -127,6 +127,15 @@
      */
     abstract public void cleanUp();
 
+    /**
+     * These were added to support FaceLock because the KeyguardViewManager needs to tell the 
+     * LockPatternKeyguardView when to bind and and unbind with FaceLock service.  Although
+     * implemented in LockPatternKeyguardView, these are not implemented in anything else
+     * derived from KeyguardViewBase
+     */
+    abstract public void bindToFaceLock();
+    abstract public void stopAndUnbindFromFaceLock();
+
     @Override
     public boolean dispatchKeyEvent(KeyEvent event) {
         if (shouldEventKeepScreenOnWhileKeyguardShowing(event)) {
diff --git a/policy/src/com/android/internal/policy/impl/KeyguardViewManager.java b/policy/src/com/android/internal/policy/impl/KeyguardViewManager.java
index c1f1151..cbf1c90 100644
--- a/policy/src/com/android/internal/policy/impl/KeyguardViewManager.java
+++ b/policy/src/com/android/internal/policy/impl/KeyguardViewManager.java
@@ -24,6 +24,7 @@
 import android.content.res.Resources;
 import android.graphics.PixelFormat;
 import android.graphics.Canvas;
+import android.os.SystemProperties;
 import android.util.Log;
 import android.view.View;
 import android.view.ViewGroup;
@@ -31,6 +32,8 @@
 import android.view.WindowManager;
 import android.widget.FrameLayout;
 
+import android.graphics.Color;
+
 /**
  * Manages creating, showing, hiding and resetting the keyguard.  Calls back
  * via {@link com.android.internal.policy.impl.KeyguardViewCallback} to poke
@@ -98,7 +101,9 @@
         if (DEBUG) Log.d(TAG, "show(); mKeyguardView==" + mKeyguardView);
 
         Resources res = mContext.getResources();
-        boolean enableScreenRotation = res.getBoolean(R.bool.config_enableLockScreenRotation);
+        boolean enableScreenRotation =
+                SystemProperties.getBoolean("lockscreen.rot_override",false)
+                || res.getBoolean(R.bool.config_enableLockScreenRotation);
         if (mKeyguardHost == null) {
             if (DEBUG) Log.d(TAG, "keyguard host is null, creating it...");
 
@@ -160,6 +165,7 @@
                 mKeyguardView.onScreenTurnedOn();
             }
         }
+
         mViewManager.updateViewLayout(mKeyguardHost, mWindowLayoutParams);
         mKeyguardHost.setVisibility(View.VISIBLE);
         mKeyguardView.requestFocus();
@@ -194,6 +200,9 @@
         mScreenOn = false;
         if (mKeyguardView != null) {
             mKeyguardView.onScreenTurnedOff();
+
+            // When screen is turned off, need to unbind from FaceLock service if using FaceLock
+            mKeyguardView.stopAndUnbindFromFaceLock();
         }
     }
 
@@ -202,6 +211,9 @@
         mScreenOn = true;
         if (mKeyguardView != null) {
             mKeyguardView.onScreenTurnedOn();
+
+            // When screen is turned on, need to bind to FaceLock service if we are using FaceLock
+            mKeyguardView.bindToFaceLock();
         }
     }
 
@@ -238,6 +250,13 @@
      */
     public synchronized void hide() {
         if (DEBUG) Log.d(TAG, "hide()");
+
+        if (mKeyguardView != null) {
+            // When view is hidden, need to unbind from FaceLock service if we are using FaceLock
+            // e.g., when device becomes unlocked
+            mKeyguardView.stopAndUnbindFromFaceLock();
+        }
+
         if (mKeyguardHost != null) {
             mKeyguardHost.setVisibility(View.GONE);
             // Don't do this right away, so we can let the view continue to animate
diff --git a/policy/src/com/android/internal/policy/impl/KeyguardViewMediator.java b/policy/src/com/android/internal/policy/impl/KeyguardViewMediator.java
index 2a34f18..64a9677 100644
--- a/policy/src/com/android/internal/policy/impl/KeyguardViewMediator.java
+++ b/policy/src/com/android/internal/policy/impl/KeyguardViewMediator.java
@@ -1202,12 +1202,15 @@
                     // showing secure lockscreen; disable expanding.
                     flags |= StatusBarManager.DISABLE_EXPAND;
                 }
+                if (isSecure()) {
+                    // showing secure lockscreen; disable ticker.
+                    flags |= StatusBarManager.DISABLE_NOTIFICATION_TICKER;
+                }
             }
 
             if (DEBUG) {
-                Log.d(TAG,
-                        "adjustStatusBarLocked: mShowing=" + mShowing + " mHidden=" + mHidden
-                                + " isSecure=" + isSecure() + " --> flags=" + flags);
+                Log.d(TAG, "adjustStatusBarLocked: mShowing=" + mShowing + " mHidden=" + mHidden
+                        + " isSecure=" + isSecure() + " --> flags=0x" + Integer.toHexString(flags));
             }
 
             mStatusBarManager.disable(flags);
diff --git a/policy/src/com/android/internal/policy/impl/LockPatternKeyguardView.java b/policy/src/com/android/internal/policy/impl/LockPatternKeyguardView.java
index 0de2de95..1d311d6 100644
--- a/policy/src/com/android/internal/policy/impl/LockPatternKeyguardView.java
+++ b/policy/src/com/android/internal/policy/impl/LockPatternKeyguardView.java
@@ -18,6 +18,8 @@
 
 import com.android.internal.R;
 import com.android.internal.policy.impl.LockPatternKeyguardView.UnlockMode;
+import com.android.internal.policy.IFaceLockCallback;
+import com.android.internal.policy.IFaceLockInterface;
 import com.android.internal.telephony.IccCard;
 import com.android.internal.widget.LockPatternUtils;
 import com.android.internal.widget.LockScreenWidgetCallback;
@@ -32,16 +34,20 @@
 import android.accounts.OperationCanceledException;
 import android.app.AlertDialog;
 import android.app.admin.DevicePolicyManager;
+import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
 import android.content.res.Configuration;
 import android.content.res.Resources;
+import android.content.ServiceConnection;
 import android.graphics.Bitmap;
 import android.graphics.Canvas;
 import android.graphics.ColorFilter;
 import android.graphics.PixelFormat;
 import android.graphics.drawable.Drawable;
 import android.os.Bundle;
+import android.os.IBinder;
+import android.os.RemoteException;
 import android.os.SystemClock;
 import android.os.SystemProperties;
 import android.telephony.TelephonyManager;
@@ -56,6 +62,7 @@
 
 import java.io.IOException;
 
+
 /**
  * The host view for all of the screens of the pattern unlock screen.  There are
  * two {@link Mode}s of operation, lock and unlock.  This will show the appropriate
@@ -93,6 +100,12 @@
 
     private boolean mShowLockBeforeUnlock = false;
 
+    // The following were added to support FaceLock
+    private IFaceLockInterface mFaceLockService;
+    private boolean mBoundToFaceLockService = false;
+    private boolean mFaceLockServiceRunning = false;
+    private View mFaceLockAreaView;
+
     /**
      * The current {@link KeyguardScreen} will use this to communicate back to us.
      */
@@ -580,6 +593,10 @@
     }
 
     private boolean isSecure() {
+        // TODO: make this work with SIM and Account cases below.
+        boolean usingBiometric = mLockPatternUtils.usingBiometricWeak();
+        if (usingBiometric && mLockPatternUtils.isBiometricEnabled())
+            return true;
         UnlockMode unlockMode = getUnlockMode();
         boolean secure = false;
         switch (unlockMode) {
@@ -687,6 +704,12 @@
                     mKeyguardScreenCallback,
                     mUpdateMonitor.getFailedAttempts());
             view.setEnableFallback(mEnableFallback);
+
+            // TODO(bcolonna): For pattern unlock, it can give us the view where the pattern is
+            // displayed and FaceLock can draw in that area.
+            // For other views it's not so simple and we should probably change how the FaceLock
+            // area is determined.
+            mFaceLockAreaView = view.getUnlockAreaView();
             unlockView = view;
         } else if (unlockMode == UnlockMode.SimPuk) {
             unlockView = new SimPukUnlockScreen(
@@ -912,5 +935,142 @@
             return mBitmap.getHeight();
         }
     }
-}
 
+    // Everything below pertains to FaceLock - might want to separate this out
+
+    // Binds to FaceLock service, but does not tell it to start
+    public void bindToFaceLock() {
+        if (mLockPatternUtils.usingBiometricWeak()) {
+            if (!mBoundToFaceLockService) {
+                if (DEBUG) Log.d(TAG, "before bind to FaceLock service");
+                mContext.bindService(new Intent(IFaceLockInterface.class.getName()),
+                        mFaceLockConnection,
+                        Context.BIND_AUTO_CREATE);
+                if (DEBUG) Log.d(TAG, "after bind to FaceLock service");
+                mBoundToFaceLockService = true;
+            } else {
+                // On startup I've seen onScreenTurnedOn() get called twice without
+                // onScreenTurnedOff() being called in between, which can cause this (bcolonna)
+                if (DEBUG) Log.w(TAG, "Attempt to bind to FaceLock when already bound");
+            }
+        }
+    }
+
+    // Tells FaceLock to stop and then unbinds from the FaceLock service
+    public void stopAndUnbindFromFaceLock() {
+        if (mLockPatternUtils.usingBiometricWeak()) {
+            stopFaceLock();
+
+            if (mBoundToFaceLockService) {
+                if (DEBUG) Log.d(TAG, "before unbind from FaceLock service");
+                mContext.unbindService(mFaceLockConnection);
+                if (DEBUG) Log.d(TAG, "after unbind from FaceLock service");
+                mBoundToFaceLockService = false;
+            } else {
+                // This could probably happen after the session when someone activates FaceLock
+                // because it wasn't active when the phone was turned on
+                if (DEBUG) Log.w(TAG, "Attempt to unbind from FaceLock when not bound");
+            }
+        }
+    }
+
+    private ServiceConnection mFaceLockConnection = new ServiceConnection() {
+        // Completes connection, registers callback and starts FaceLock when service is bound
+        @Override
+        public void onServiceConnected(ComponentName className, IBinder iservice) {
+            mFaceLockService = IFaceLockInterface.Stub.asInterface(iservice);
+            if (DEBUG) Log.d(TAG, "Connected to FaceLock service");
+            try {
+                mFaceLockService.registerCallback(mFaceLockCallback);
+            } catch (RemoteException e) {
+                throw new RuntimeException("Remote exception");
+            }
+
+            // TODO(bcolonna): Need to set location properly (only works for pattern view now)
+            if (mFaceLockAreaView != null) {
+                int[] unlockLocationOnScreen = new int[2];
+                mFaceLockAreaView.getLocationOnScreen(unlockLocationOnScreen);
+                int x = unlockLocationOnScreen[0];
+                int y = unlockLocationOnScreen[1];
+                int w = mFaceLockAreaView.getWidth();
+                int h = mFaceLockAreaView.getHeight();
+                if (DEBUG) Log.d(TAG, "(x,y) (wxh): (" + x + "," + y + ") (" + w + "x" + h + ")");
+                startFaceLock(mFaceLockAreaView.getWindowToken(), x, y, w, h);
+            }
+        }
+
+        // Cleans up if FaceLock service unexpectedly disconnects
+        @Override
+        public void onServiceDisconnected(ComponentName className) {
+            mFaceLockService = null;
+            if (DEBUG) Log.w(TAG, "Unexpected disconnect from FaceLock service");
+        }
+    };
+
+    // Tells the FaceLock service to start displaying its UI and perform recognition
+    public void startFaceLock(IBinder windowToken, int x, int y, int h, int w)
+    {
+        if (mLockPatternUtils.usingBiometricWeak()) {
+            if (!mFaceLockServiceRunning) {
+                if (DEBUG) Log.d(TAG, "Starting FaceLock");
+                try {
+                    mFaceLockService.startUi(windowToken, x, y, h, w);
+                } catch (RemoteException e) {
+                    throw new RuntimeException("Remote exception");
+                }
+                mFaceLockServiceRunning = true;
+            } else {
+                if (DEBUG) Log.w(TAG, "startFaceLock() attempted while running");
+            }
+        }
+    }
+
+    // Tells the FaceLock service to stop displaying its UI and stop recognition
+    public void stopFaceLock()
+    {
+        if (mLockPatternUtils.usingBiometricWeak()) {
+            // Note that attempting to stop FaceLock when it's not running is not an issue.
+            // FaceLock can return, which stops it and then we try to stop it when the
+            // screen is turned off.  That's why we check.
+            if (mFaceLockServiceRunning) {
+                try {
+                    if (DEBUG) Log.d(TAG, "Stopping FaceLock");
+                    mFaceLockService.stopUi();
+                } catch (RemoteException e) {
+                    throw new RuntimeException("Remote exception");
+                }
+                mFaceLockServiceRunning = false;
+            }
+        }
+    }
+
+    // Implements the FaceLock service callback interface defined in AIDL
+    private final IFaceLockCallback mFaceLockCallback = new IFaceLockCallback.Stub() {
+
+        // Stops the FaceLock UI and indicates that the phone should be unlocked
+        @Override
+        public void unlock() {
+            if (DEBUG) Log.d(TAG, "FaceLock unlock");
+            stopFaceLock();
+            mKeyguardScreenCallback.keyguardDone(true);
+            mKeyguardScreenCallback.reportSuccessfulUnlockAttempt();
+        }
+
+        // Stops the FaceLock UI and exposes the backup method without unlocking
+        @Override
+        public void cancel() {
+            // In this case, either the user has cancelled out, or FaceLock failed to recognize them
+            if (DEBUG) Log.d(TAG, "FaceLock cancel");
+            stopFaceLock();
+        }
+
+        // Stops the FaceLock UI and puts the phone to sleep
+        @Override
+        public void sleepDevice() {
+            // In this case, it appears the phone has been turned on accidentally
+            if (DEBUG) Log.d(TAG, "FaceLock accidental turn on");
+            stopFaceLock();
+            // TODO(bcolonna): how do we put the phone back to sleep (i.e., turn off the screen)
+        }
+    };
+}
diff --git a/policy/src/com/android/internal/policy/impl/PatternUnlockScreen.java b/policy/src/com/android/internal/policy/impl/PatternUnlockScreen.java
index a3db1c3..0cafeb5a 100644
--- a/policy/src/com/android/internal/policy/impl/PatternUnlockScreen.java
+++ b/policy/src/com/android/internal/policy/impl/PatternUnlockScreen.java
@@ -199,7 +199,11 @@
         setFocusableInTouchMode(true);
     }
 
-
+    // TODO(bcolonna): This is to tell FaceLock where to draw...but this covers up the wireless
+    // service text, so we will want to change the way the area is specified
+    public View getUnlockAreaView() {
+        return mLockPatternView;
+    }
 
     public void setEnableFallback(boolean state) {
         if (DEBUG) Log.d(TAG, "setEnableFallback(" + state + ")");
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindow.java b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
index f5e3a45..20088b1 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneWindow.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
@@ -1401,7 +1401,9 @@
                 if (event.getRepeatCount() > 0) break;
                 if (featureId < 0) break;
                 // Currently don't do anything with long press.
-                dispatcher.startTracking(event, this);
+                if (dispatcher != null) {
+                    dispatcher.startTracking(event, this);
+                }
                 return true;
             }
 
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
index 304df72..86671bd 100755
--- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
@@ -189,16 +189,16 @@
     static final int STATUS_BAR_SUB_PANEL_LAYER = 14;
     static final int STATUS_BAR_LAYER = 15;
     static final int STATUS_BAR_PANEL_LAYER = 16;
-    // the navigation bar, if available, shows atop most things
-    static final int NAVIGATION_BAR_LAYER = 17;
     // the on-screen volume indicator and controller shown when the user
     // changes the device volume
-    static final int VOLUME_OVERLAY_LAYER = 18;
+    static final int VOLUME_OVERLAY_LAYER = 17;
+    // things in here CAN NOT take focus, but are shown on top of everything else.
+    static final int SYSTEM_OVERLAY_LAYER = 18;
+    // the navigation bar, if available, shows atop most things
+    static final int NAVIGATION_BAR_LAYER = 19;
     // the drag layer: input for drag-and-drop is associated with this window,
     // which sits above all other focusable windows
-    static final int DRAG_LAYER = 19;
-    // things in here CAN NOT take focus, but are shown on top of everything else.
-    static final int SYSTEM_OVERLAY_LAYER = 20;
+    static final int DRAG_LAYER = 20;
     static final int SECURE_SYSTEM_OVERLAY_LAYER = 21;
     static final int BOOT_PROGRESS_LAYER = 22;
     // the (mouse) pointer layer
@@ -894,10 +894,10 @@
                     WindowManager.LayoutParams.MATCH_PARENT,
                     WindowManager.LayoutParams.MATCH_PARENT);
             lp.type = WindowManager.LayoutParams.TYPE_SECURE_SYSTEM_OVERLAY;
-            lp.flags = 
-                WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE|
-                WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE|
-                WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
+            lp.flags = WindowManager.LayoutParams.FLAG_FULLSCREEN
+                    | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE
+                    | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
+                    | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
             lp.format = PixelFormat.TRANSLUCENT;
             lp.setTitle("PointerLocation");
             WindowManager wm = (WindowManager)
@@ -995,6 +995,7 @@
                 // These types of windows can't receive input events.
                 attrs.flags |= WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
                         | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
+                attrs.flags &= ~WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH;
                 break;
         }
     }
@@ -1993,6 +1994,13 @@
                                     "Laying out navigation bar window: (%d,%d - %d,%d)",
                                     pf.left, pf.top, pf.right, pf.bottom));
                     }
+                } else if (attrs.type == TYPE_SECURE_SYSTEM_OVERLAY
+                        && ((fl & FLAG_FULLSCREEN) != 0)) {
+                    // Fullscreen secure system overlays get what they ask for.
+                    pf.left = df.left = mUnrestrictedScreenLeft;
+                    pf.top = df.top = mUnrestrictedScreenTop;
+                    pf.right = df.right = mUnrestrictedScreenLeft+mUnrestrictedScreenWidth;
+                    pf.bottom = df.bottom = mUnrestrictedScreenTop+mUnrestrictedScreenHeight;
                 } else {
                     pf.left = df.left = cf.left = mRestrictedScreenLeft;
                     pf.top = df.top = cf.top = mRestrictedScreenTop;
diff --git a/services/input/InputWindow.h b/services/input/InputWindow.h
index 8861bee..38968f9 100644
--- a/services/input/InputWindow.h
+++ b/services/input/InputWindow.h
@@ -103,6 +103,8 @@
         TYPE_STATUS_BAR_SUB_PANEL  = FIRST_SYSTEM_WINDOW+17,
         TYPE_POINTER            = FIRST_SYSTEM_WINDOW+18,
         TYPE_NAVIGATION_BAR     = FIRST_SYSTEM_WINDOW+19,
+        TYPE_VOLUME_OVERLAY = FIRST_SYSTEM_WINDOW+20,
+        TYPE_BOOT_PROGRESS = FIRST_SYSTEM_WINDOW+21,
         LAST_SYSTEM_WINDOW      = 2999,
     };
 
diff --git a/services/java/com/android/server/NetworkManagementService.java b/services/java/com/android/server/NetworkManagementService.java
index f774dea..349b4d2 100644
--- a/services/java/com/android/server/NetworkManagementService.java
+++ b/services/java/com/android/server/NetworkManagementService.java
@@ -1325,7 +1325,7 @@
         // TODO: remove knownLines check once 5087722 verified
         final HashSet<String> knownLines = Sets.newHashSet();
         // TODO: remove lastIdx check once 5270106 verified
-        int lastIdx = 0;
+        int lastIdx;
 
         final ArrayList<String> keys = Lists.newArrayList();
         final ArrayList<String> values = Lists.newArrayList();
@@ -1339,6 +1339,7 @@
             // parse first line as header
             line = reader.readLine();
             splitLine(line, keys);
+            lastIdx = 1;
 
             // parse remaining lines
             while ((line = reader.readLine()) != null) {
@@ -1350,7 +1351,7 @@
                 }
 
                 final int idx = getParsedInt(parsed, KEY_IDX);
-                if (idx > lastIdx + 1) {
+                if (idx != lastIdx + 1) {
                     throw new IllegalStateException(
                             "inconsistent idx=" + idx + " after lastIdx=" + lastIdx);
                 }
diff --git a/services/java/com/android/server/StatusBarManagerService.java b/services/java/com/android/server/StatusBarManagerService.java
index ca3b12d..bab9f8a 100644
--- a/services/java/com/android/server/StatusBarManagerService.java
+++ b/services/java/com/android/server/StatusBarManagerService.java
@@ -301,7 +301,7 @@
         // also allows calls from window manager which is in this process.
         enforceStatusBarService();
 
-        if (SPEW) Slog.d(TAG, "setSystemUiVisibility(" + vis + ")");
+        if (SPEW) Slog.d(TAG, "setSystemUiVisibility(0x" + Integer.toHexString(vis) + ")");
 
         synchronized (mLock) {
             updateUiVisibilityLocked(vis);
diff --git a/services/java/com/android/server/TelephonyRegistry.java b/services/java/com/android/server/TelephonyRegistry.java
index 4447ad0..bc256ed 100644
--- a/services/java/com/android/server/TelephonyRegistry.java
+++ b/services/java/com/android/server/TelephonyRegistry.java
@@ -383,7 +383,7 @@
 
     public void notifyDataConnection(int state, boolean isDataConnectivityPossible,
             String reason, String apn, String apnType, LinkProperties linkProperties,
-            LinkCapabilities linkCapabilities, int networkType) {
+            LinkCapabilities linkCapabilities, int networkType, boolean roaming) {
         if (!checkNotifyPermission("notifyDataConnection()" )) {
             return;
         }
@@ -437,7 +437,7 @@
             }
         }
         broadcastDataConnectionStateChanged(state, isDataConnectivityPossible, reason, apn,
-                apnType, linkProperties, linkCapabilities);
+                apnType, linkProperties, linkCapabilities, roaming);
     }
 
     public void notifyDataConnectionFailed(String reason, String apnType) {
@@ -596,7 +596,7 @@
     private void broadcastDataConnectionStateChanged(int state,
             boolean isDataConnectivityPossible,
             String reason, String apn, String apnType, LinkProperties linkProperties,
-            LinkCapabilities linkCapabilities) {
+            LinkCapabilities linkCapabilities, boolean roaming) {
         // Note: not reporting to the battery stats service here, because the
         // status bar takes care of that after taking into account all of the
         // required info.
@@ -618,6 +618,8 @@
         if (linkCapabilities != null) {
             intent.putExtra(Phone.DATA_LINK_CAPABILITIES_KEY, linkCapabilities);
         }
+        if (roaming) intent.putExtra(Phone.DATA_NETWORK_ROAMING_KEY, true);
+
         intent.putExtra(Phone.DATA_APN_KEY, apn);
         intent.putExtra(Phone.DATA_APN_TYPE_KEY, apnType);
         mContext.sendStickyBroadcast(intent);
diff --git a/services/java/com/android/server/WiredAccessoryObserver.java b/services/java/com/android/server/WiredAccessoryObserver.java
index e45c368..6a63eac 100644
--- a/services/java/com/android/server/WiredAccessoryObserver.java
+++ b/services/java/com/android/server/WiredAccessoryObserver.java
@@ -107,25 +107,18 @@
     private synchronized final void updateState(String name, int state)
     {
         if (name.equals("usb_audio")) {
-            if (state == 1) {
-                switchState = ((mHeadsetState & (BIT_HEADSET|BIT_HEADSET_NO_MIC|
-                                                 BIT_USB_HEADSET_DGTL|BIT_HDMI_AUDIO)) |
-                               (state << 2));
-            } else if (state == 2) {
-                switchState = ((mHeadsetState & (BIT_HEADSET|BIT_HEADSET_NO_MIC|
-                                                 BIT_USB_HEADSET_ANLG|BIT_HDMI_AUDIO)) |
-                               (state << 3));
-            } else switchState = (mHeadsetState & (BIT_HEADSET|BIT_HEADSET_NO_MIC|BIT_HDMI_AUDIO));
-        }
-        else if (name.equals("hdmi")) {
+            switchState = ((mHeadsetState & (BIT_HEADSET|BIT_HEADSET_NO_MIC|BIT_HDMI_AUDIO)) |
+                           ((state == 1) ? BIT_USB_HEADSET_ANLG :
+                                         ((state == 2) ? BIT_USB_HEADSET_DGTL : 0)));
+        } else if (name.equals("hdmi")) {
             switchState = ((mHeadsetState & (BIT_HEADSET|BIT_HEADSET_NO_MIC|
                                              BIT_USB_HEADSET_DGTL|BIT_USB_HEADSET_ANLG)) |
-                           (state << 4));
-        }
-        else {
+                           ((state == 1) ? BIT_HDMI_AUDIO : 0));
+        } else {
             switchState = ((mHeadsetState & (BIT_HDMI_AUDIO|BIT_USB_HEADSET_ANLG|
                                              BIT_USB_HEADSET_DGTL)) |
-                           state);
+                            ((state == 1) ? BIT_HEADSET :
+                                          ((state == 2) ? BIT_HEADSET_NO_MIC : 0)));
         }
         update(name, switchState);
     }
diff --git a/services/java/com/android/server/accessibility/TouchExplorer.java b/services/java/com/android/server/accessibility/TouchExplorer.java
index eb399ad..aa43bb6 100644
--- a/services/java/com/android/server/accessibility/TouchExplorer.java
+++ b/services/java/com/android/server/accessibility/TouchExplorer.java
@@ -203,6 +203,7 @@
                     }
                     case 1: {
                         mSendHoverDelayed.remove();
+                        mPerformLongPressDelayed.remove();
                         // Send a hover for every finger down so the user gets feedback.
                         final int pointerId = pointerTracker.getPrimaryActivePointerId();
                         final int pointerIdBits = (1 << pointerId);
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index 57bfaed..41af137 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -3327,20 +3327,28 @@
         boolean didSomething = killPackageProcessesLocked(name, uid, -100,
                 callerWillRestart, false, doit, evenPersistent);
         
-        for (i=mMainStack.mHistory.size()-1; i>=0; i--) {
+        TaskRecord lastTask = null;
+        for (i=0; i<mMainStack.mHistory.size(); i++) {
             ActivityRecord r = (ActivityRecord)mMainStack.mHistory.get(i);
-            if (r.packageName.equals(name)
+            final boolean samePackage = r.packageName.equals(name);
+            if ((samePackage || r.task == lastTask)
                     && (r.app == null || evenPersistent || !r.app.persistent)) {
                 if (!doit) {
                     return true;
                 }
                 didSomething = true;
                 Slog.i(TAG, "  Force finishing activity " + r);
-                if (r.app != null) {
-                    r.app.removed = true;
+                if (samePackage) {
+                    if (r.app != null) {
+                        r.app.removed = true;
+                    }
+                    r.app = null;
                 }
-                r.app = null;
-                r.stack.finishActivityLocked(r, i, Activity.RESULT_CANCELED, null, "uninstall");
+                lastTask = r.task;
+                if (r.stack.finishActivityLocked(r, i, Activity.RESULT_CANCELED,
+                        null, "force-stop")) {
+                    i--;
+                }
             }
         }
 
@@ -5159,6 +5167,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);
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
index 0ff1cce..c9567d5 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
@@ -22,6 +22,7 @@
 
 #include <utils/Errors.h>
 #include <utils/String8.h>
+#include <utils/Vector.h>
 
 #include <hardware/hardware.h>
 
@@ -29,6 +30,7 @@
 
 #include <EGL/egl.h>
 
+#include "LayerBase.h"
 #include "HWComposer.h"
 #include "SurfaceFlinger.h"
 
@@ -133,7 +135,8 @@
     return mList ? mList->hwLayers : 0;
 }
 
-void HWComposer::dump(String8& result, char* buffer, size_t SIZE) const {
+void HWComposer::dump(String8& result, char* buffer, size_t SIZE,
+        const Vector< sp<LayerBase> >& visibleLayersSortedByZ) const {
     if (mHwc && mList) {
         result.append("Hardware Composer state:\n");
 
@@ -143,11 +146,12 @@
 
         for (size_t i=0 ; i<mList->numHwLayers ; i++) {
             const hwc_layer_t& l(mList->hwLayers[i]);
-            snprintf(buffer, SIZE, "  %8s | %08x | %08x | %02x | %04x | [%5d,%5d,%5d,%5d] |  [%5d,%5d,%5d,%5d]\n",
+            snprintf(buffer, SIZE, "  %8s | %08x | %08x | %02x | %04x | [%5d,%5d,%5d,%5d] |  [%5d,%5d,%5d,%5d] %s\n",
                     l.compositionType ? "OVERLAY" : "FB",
                     l.hints, l.flags, l.transform, l.blending,
                     l.sourceCrop.left, l.sourceCrop.top, l.sourceCrop.right, l.sourceCrop.bottom,
-                    l.displayFrame.left, l.displayFrame.top, l.displayFrame.right, l.displayFrame.bottom);
+                    l.displayFrame.left, l.displayFrame.top, l.displayFrame.right, l.displayFrame.bottom,
+                    visibleLayersSortedByZ[i]->getName().string());
             result.append(buffer);
         }
 
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h
index 77c1a4b..8758a80 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.h
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.h
@@ -25,12 +25,14 @@
 #include <hardware/hwcomposer.h>
 
 #include <utils/StrongPointer.h>
+#include <utils/Vector.h>
 
 namespace android {
 // ---------------------------------------------------------------------------
 
 class String8;
 class SurfaceFlinger;
+class LayerBase;
 
 class HWComposer
 {
@@ -63,7 +65,8 @@
     hwc_layer_t* getLayers() const;
 
     // for debugging
-    void dump(String8& out, char* scratch, size_t SIZE) const;
+    void dump(String8& out, char* scratch, size_t SIZE,
+            const Vector< sp<LayerBase> >& visibleLayersSortedByZ) const;
 
 private:
     struct cb_context {
diff --git a/services/surfaceflinger/LayerBase.cpp b/services/surfaceflinger/LayerBase.cpp
index 603fb60..e5ce814 100644
--- a/services/surfaceflinger/LayerBase.cpp
+++ b/services/surfaceflinger/LayerBase.cpp
@@ -43,7 +43,7 @@
     : dpy(display), contentDirty(false),
       sequence(uint32_t(android_atomic_inc(&sSequence))),
       mFlinger(flinger), mFiltering(false),
-      mNeedsFiltering(false),
+      mNeedsFiltering(false), mInOverlay(false),
       mOrientation(0),
       mTransactionFlags(0),
       mPremultipliedAlpha(true), mName("unnamed"), mDebug(false),
@@ -344,6 +344,14 @@
     hwcl->handle = NULL;
 }
 
+void LayerBase::setOverlay(bool inOverlay) {
+    mInOverlay = inOverlay;
+}
+
+bool LayerBase::isOverlay() const {
+    return mInOverlay;
+}
+
 void LayerBase::setFiltering(bool filtering)
 {
     mFiltering = filtering;
@@ -472,12 +480,13 @@
 {
     const Layer::State& s(drawingState());
     snprintf(buffer, SIZE,
-            "+ %s %p\n"
+            "+ %s %p (%s)\n"
             "      "
             "z=%9d, pos=(%g,%g), size=(%4d,%4d), "
             "isOpaque=%1d, needsDithering=%1d, invalidate=%1d, "
             "alpha=0x%02x, flags=0x%08x, tr=[%.2f, %.2f][%.2f, %.2f]\n",
-            getTypeId(), this, s.z, s.transform.tx(), s.transform.ty(), s.w, s.h,
+            getTypeId(), this, getName().string(),
+            s.z, s.transform.tx(), s.transform.ty(), s.w, s.h,
             isOpaque(), needsDithering(), contentDirty,
             s.alpha, s.flags,
             s.transform[0][0], s.transform[0][1],
@@ -553,9 +562,7 @@
 
     sp<Client> client(mClientRef.promote());
     snprintf(buffer, SIZE,
-            "      name=%s\n"
             "      client=%p, identity=%u\n",
-            getName().string(),
             client.get(), getIdentity());
 
     result.append(buffer);
diff --git a/services/surfaceflinger/LayerBase.h b/services/surfaceflinger/LayerBase.h
index d20f06a..ee50428 100644
--- a/services/surfaceflinger/LayerBase.h
+++ b/services/surfaceflinger/LayerBase.h
@@ -109,8 +109,10 @@
     virtual const char* getTypeId() const { return "LayerBase"; }
 
     virtual void setGeometry(hwc_layer_t* hwcl);
-
     virtual void setPerFrameData(hwc_layer_t* hwcl);
+            void setOverlay(bool inOverlay);
+            bool isOverlay() const;
+
 
     /**
      * draw - performs some global clipping optimizations
@@ -242,6 +244,11 @@
                 // Whether filtering is needed b/c of the drawingstate
                 bool            mNeedsFiltering;
 
+                // this layer is currently handled by the hwc. this is
+                // updated at composition time, always frmo the composition
+                // thread.
+                bool            mInOverlay;
+
 protected:
                 // cached during validateVisibility()
                 int32_t         mOrientation;
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 4a3a8ea..df13640 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -817,20 +817,6 @@
     mHwWorkListDirty = false;
     HWComposer& hwc(graphicPlane(0).displayHardware().getHwComposer());
     if (hwc.initCheck() == NO_ERROR) {
-
-        const DisplayHardware& hw(graphicPlane(0).displayHardware());
-        uint32_t flags = hw.getFlags();
-        if ((flags & DisplayHardware::SWAP_RECTANGLE) ||
-            (flags & DisplayHardware::BUFFER_PRESERVED))
-        {
-            // we need to redraw everything (the whole screen)
-            // NOTE: we could be more subtle here and redraw only
-            // the area which will end-up in an overlay. But since this
-            // shouldn't happen often, we invalidate everything.
-            mDirtyRegion.set(hw.bounds());
-            mInvalidRegion = mDirtyRegion;
-        }
-
         const Vector< sp<LayerBase> >& currentLayers(mVisibleLayersSortedByZ);
         const size_t count = currentLayers.size();
         hwc.createWorkList(count);
@@ -890,30 +876,30 @@
         }
     }
 
-    // compose all surfaces
+    Region expandDirty = setupHardwareComposer(mDirtyRegion);
+    mDirtyRegion.orSelf(expandDirty);
+    mInvalidRegion.orSelf(mDirtyRegion);
     composeSurfaces(mDirtyRegion);
 
     // clear the dirty regions
     mDirtyRegion.clear();
 }
 
-void SurfaceFlinger::composeSurfaces(const Region& dirty)
+Region SurfaceFlinger::setupHardwareComposer(const Region& dirty)
 {
-    if (UNLIKELY(!mWormholeRegion.isEmpty())) {
-        // should never happen unless the window manager has a bug
-        // draw something...
-        drawWormhole();
-    }
-
-    status_t err = NO_ERROR;
-    const Vector< sp<LayerBase> >& layers(mVisibleLayersSortedByZ);
-    size_t count = layers.size();
+    Region dirtyOut(dirty);
 
     const DisplayHardware& hw(graphicPlane(0).displayHardware());
     HWComposer& hwc(hw.getHwComposer());
     hwc_layer_t* const cur(hwc.getLayers());
+    if (!cur) {
+        return dirtyOut;
+    }
 
-    LOGE_IF(cur && hwc.getNumLayers() != count,
+    const Vector< sp<LayerBase> >& layers(mVisibleLayersSortedByZ);
+    size_t count = layers.size();
+
+    LOGE_IF(hwc.getNumLayers() != count,
             "HAL number of layers (%d) doesn't match surfaceflinger (%d)",
             hwc.getNumLayers(), count);
 
@@ -926,57 +912,95 @@
      *  update the per-frame h/w composer data for each layer
      *  and build the transparent region of the FB
      */
-    Region transparent;
-    if (cur) {
-        for (size_t i=0 ; i<count ; i++) {
-            const sp<LayerBase>& layer(layers[i]);
-            layer->setPerFrameData(&cur[i]);
-        }
-        err = hwc.prepare();
-        LOGE_IF(err, "HWComposer::prepare failed (%s)", strerror(-err));
+    for (size_t i=0 ; i<count ; i++) {
+        const sp<LayerBase>& layer(layers[i]);
+        layer->setPerFrameData(&cur[i]);
+    }
+    status_t err = hwc.prepare();
+    LOGE_IF(err, "HWComposer::prepare failed (%s)", strerror(-err));
 
-        if (err == NO_ERROR) {
-            for (size_t i=0 ; i<count ; i++) {
-                if (cur[i].hints & HWC_HINT_CLEAR_FB) {
-                    const sp<LayerBase>& layer(layers[i]);
-                    if (layer->isOpaque()) {
-                        transparent.orSelf(layer->visibleRegionScreen);
-                    }
-                }
+    if (err == NO_ERROR) {
+        Region transparent;
+        for (size_t i=0 ; i<count ; i++) {
+            // what's happening here is tricky.
+            // we want to clear all the layers with the CLEAR_FB flags
+            // that are opaque.
+            // however, since some GPU have are efficient at preserving
+            // the backbuffer, we want to take advantage of that so we do the
+            // clear only in the dirty region (other areas will be preserved
+            // on those GPUs).
+            //   NOTE: on non backbuffer preserving GPU, the dirty region
+            //   has already been expanded as needed, so the code is correct
+            //   there too.
+            // However, the content of the framebuffer cannot be trusted when
+            // we switch to/from FB/OVERLAY, in which case we need to
+            // expand the dirty region to those areas too.
+            //
+            // Also we want to make sure to not clear areas that belong to
+            // layers above that won't redraw (we would just erasing them),
+            // that is, we can't erase anything outside the dirty region.
+
+            const sp<LayerBase>& layer(layers[i]);
+            if ((cur[i].hints & HWC_HINT_CLEAR_FB) && layer->isOpaque()) {
+                transparent.orSelf(layer->visibleRegionScreen);
             }
 
-            /*
-             *  clear the area of the FB that need to be transparent
-             */
-            transparent.andSelf(dirty);
-            if (!transparent.isEmpty()) {
-                glClearColor(0,0,0,0);
-                Region::const_iterator it = transparent.begin();
-                Region::const_iterator const end = transparent.end();
-                const int32_t height = hw.getHeight();
-                while (it != end) {
-                    const Rect& r(*it++);
-                    const GLint sy = height - (r.top + r.height());
-                    glScissor(r.left, sy, r.width(), r.height());
-                    glClear(GL_COLOR_BUFFER_BIT);
-                }
+            bool isOverlay = (cur[i].compositionType != HWC_FRAMEBUFFER) &&
+                !(cur[i].flags & HWC_SKIP_LAYER);
+
+            if (isOverlay != layer->isOverlay()) {
+                // we transitioned to/from overlay, so add this layer
+                // to the dirty region so the framebuffer can be either
+                // cleared or redrawn.
+                dirtyOut.orSelf(layer->visibleRegionScreen);
+            }
+            layer->setOverlay(isOverlay);
+        }
+
+
+        /*
+         *  clear the area of the FB that need to be transparent
+         */
+        // don't erase stuff outside the dirty region
+        transparent.andSelf(dirtyOut);
+        if (!transparent.isEmpty()) {
+            glClearColor(0,0,0,0);
+            Region::const_iterator it = transparent.begin();
+            Region::const_iterator const end = transparent.end();
+            const int32_t height = hw.getHeight();
+            while (it != end) {
+                const Rect& r(*it++);
+                const GLint sy = height - (r.top + r.height());
+                glScissor(r.left, sy, r.width(), r.height());
+                glClear(GL_COLOR_BUFFER_BIT);
             }
         }
     }
+    return dirtyOut;
+}
 
+void SurfaceFlinger::composeSurfaces(const Region& dirty)
+{
+    if (UNLIKELY(!mWormholeRegion.isEmpty())) {
+        // should never happen unless the window manager has a bug
+        // draw something...
+        drawWormhole();
+    }
+
+    const DisplayHardware& hw(graphicPlane(0).displayHardware());
+    HWComposer& hwc(hw.getHwComposer());
+    hwc_layer_t* const cur(hwc.getLayers());
 
     /*
      * and then, render the layers targeted at the framebuffer
      */
+    const Vector< sp<LayerBase> >& layers(mVisibleLayersSortedByZ);
+    size_t count = layers.size();
     for (size_t i=0 ; i<count ; i++) {
-        if (cur) {
-            if ((cur[i].compositionType != HWC_FRAMEBUFFER) &&
+        if (cur && (cur[i].compositionType != HWC_FRAMEBUFFER) &&
                 !(cur[i].flags & HWC_SKIP_LAYER)) {
-                // skip layers handled by the HAL
-                continue;
-            }
+            continue;
         }
-
         const sp<LayerBase>& layer(layers[i]);
         const Region clip(dirty.intersect(layer->visibleRegionScreen));
         if (!clip.isEmpty()) {
@@ -1597,7 +1621,7 @@
                 hwc.initCheck()==NO_ERROR ? "present" : "not present",
                 (mDebugDisableHWC || mDebugRegion) ? "disabled" : "enabled");
         result.append(buffer);
-        hwc.dump(result, buffer, SIZE);
+        hwc.dump(result, buffer, SIZE, mVisibleLayersSortedByZ);
 
         /*
          * Dump gralloc state
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 5f8eb08..126ca39 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -277,6 +277,7 @@
             void        handleWorkList();
             void        handleRepaint();
             void        postFramebuffer();
+            Region      setupHardwareComposer(const Region& dirty);
             void        composeSurfaces(const Region& dirty);
             void        repaintEverything();
 
diff --git a/telephony/java/com/android/internal/telephony/DefaultPhoneNotifier.java b/telephony/java/com/android/internal/telephony/DefaultPhoneNotifier.java
index aa7568b..f769157 100644
--- a/telephony/java/com/android/internal/telephony/DefaultPhoneNotifier.java
+++ b/telephony/java/com/android/internal/telephony/DefaultPhoneNotifier.java
@@ -113,10 +113,15 @@
         TelephonyManager telephony = TelephonyManager.getDefault();
         LinkProperties linkProperties = null;
         LinkCapabilities linkCapabilities = null;
+        boolean roaming = false;
+
         if (state == Phone.DataState.CONNECTED) {
             linkProperties = sender.getLinkProperties(apnType);
             linkCapabilities = sender.getLinkCapabilities(apnType);
         }
+        ServiceState ss = sender.getServiceState();
+        if (ss != null) roaming = ss.getRoaming();
+
         try {
             mRegistry.notifyDataConnection(
                     convertDataState(state),
@@ -126,7 +131,8 @@
                     linkProperties,
                     linkCapabilities,
                     ((telephony!=null) ? telephony.getNetworkType() :
-                    TelephonyManager.NETWORK_TYPE_UNKNOWN));
+                    TelephonyManager.NETWORK_TYPE_UNKNOWN),
+                    roaming);
         } catch (RemoteException ex) {
             // system process is dead
         }
diff --git a/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl b/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl
index 3c83e50..1f19282 100644
--- a/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl
@@ -35,7 +35,7 @@
     void notifyDataActivity(int state);
     void notifyDataConnection(int state, boolean isDataConnectivityPossible,
             String reason, String apn, String apnType, in LinkProperties linkProperties,
-            in LinkCapabilities linkCapabilities, int networkType);
+            in LinkCapabilities linkCapabilities, int networkType, boolean roaming);
     void notifyDataConnectionFailed(String reason, String apnType);
     void notifyCellLocation(in Bundle cellLocation);
     void notifyOtaspChanged(in int otaspMode);
diff --git a/telephony/java/com/android/internal/telephony/Phone.java b/telephony/java/com/android/internal/telephony/Phone.java
index 6347f37..5e64148 100644
--- a/telephony/java/com/android/internal/telephony/Phone.java
+++ b/telephony/java/com/android/internal/telephony/Phone.java
@@ -106,6 +106,7 @@
 
     static final String DATA_IFACE_NAME_KEY = "iface";
     static final String NETWORK_UNAVAILABLE_KEY = "networkUnvailable";
+    static final String DATA_NETWORK_ROAMING_KEY = "networkRoaming";
     static final String PHONE_IN_ECM_STATE = "phoneinECMState";
 
     /**
diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java b/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java
index 1a077d0..a728d0a 100644
--- a/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java
@@ -582,7 +582,12 @@
      */
     @Override
     protected void onRoamingOff() {
-        trySetupData(Phone.REASON_ROAMING_OFF);
+        if (getDataOnRoamingEnabled() == false) {
+            notifyDataAvailability(Phone.REASON_ROAMING_OFF);
+            trySetupData(Phone.REASON_ROAMING_OFF);
+        } else {
+            notifyDataConnection(Phone.REASON_ROAMING_OFF);
+        }
     }
 
     /**
@@ -592,9 +597,11 @@
     protected void onRoamingOn() {
         if (getDataOnRoamingEnabled()) {
             trySetupData(Phone.REASON_ROAMING_ON);
+            notifyDataConnection(Phone.REASON_ROAMING_ON);
         } else {
             if (DBG) log("Tear down data connection on roaming.");
             cleanUpAllConnections(null);
+            notifyDataAvailability(Phone.REASON_ROAMING_ON);
         }
     }
 
diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
index 00fb0e0..4e43fcd 100644
--- a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
+++ b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
@@ -1681,23 +1681,25 @@
     @Override
     protected void onRoamingOff() {
         if (DBG) log("onRoamingOff");
-        // Notify data availability so APN can be enabled.
-        notifyDataAvailability(Phone.REASON_ROAMING_OFF);
 
-        setupDataOnReadyApns(Phone.REASON_ROAMING_OFF);
+        if (getDataOnRoamingEnabled() == false) {
+            notifyDataAvailability(Phone.REASON_ROAMING_OFF);
+            setupDataOnReadyApns(Phone.REASON_ROAMING_OFF);
+        } else {
+            notifyDataConnection(Phone.REASON_ROAMING_OFF);
+        }
     }
 
     @Override
     protected void onRoamingOn() {
-        // Notify data availability so APN can be enabled.
-        notifyDataAvailability(Phone.REASON_ROAMING_ON);
-
         if (getDataOnRoamingEnabled()) {
             if (DBG) log("onRoamingOn: setup data on roaming");
             setupDataOnReadyApns(Phone.REASON_ROAMING_ON);
+            notifyDataConnection(Phone.REASON_ROAMING_ON);
         } else {
             if (DBG) log("onRoamingOn: Tear down data connection on roaming.");
             cleanUpAllConnections(true, Phone.REASON_ROAMING_ON);
+            notifyDataAvailability(Phone.REASON_ROAMING_ON);
         }
     }
 
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/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
diff --git a/wifi/java/android/net/wifi/WifiWatchdogStateMachine.java b/wifi/java/android/net/wifi/WifiWatchdogStateMachine.java
index c52142d..fe0e850 100644
--- a/wifi/java/android/net/wifi/WifiWatchdogStateMachine.java
+++ b/wifi/java/android/net/wifi/WifiWatchdogStateMachine.java
@@ -77,15 +77,15 @@
     /**
      * Low signal is defined as less than or equal to cut off
      */
-    private static final int LOW_SIGNAL_CUTOFF = 1;
+    private static final int LOW_SIGNAL_CUTOFF = 0;
 
     private static final long DEFAULT_DNS_CHECK_SHORT_INTERVAL_MS = 2 * 60 * 1000;
-    private static final long DEFAULT_DNS_CHECK_LONG_INTERVAL_MS = 30 * 60 * 1000;
+    private static final long DEFAULT_DNS_CHECK_LONG_INTERVAL_MS = 60 * 60 * 1000;
     private static final long DEFAULT_WALLED_GARDEN_INTERVAL_MS = 30 * 60 * 1000;
 
     private static final int DEFAULT_MAX_SSID_BLACKLISTS = 7;
-    private static final int DEFAULT_NUM_DNS_PINGS = 15; // Multiple pings to detect setup issues
-    private static final int DEFAULT_MIN_DNS_RESPONSES = 3;
+    private static final int DEFAULT_NUM_DNS_PINGS = 5; // Multiple pings to detect setup issues
+    private static final int DEFAULT_MIN_DNS_RESPONSES = 1;
 
     private static final int DEFAULT_DNS_PING_TIMEOUT_MS = 2000;
 
@@ -95,7 +95,9 @@
     private static final String DEFAULT_WALLED_GARDEN_URL =
             "http://clients3.google.com/generate_204";
     private static final int WALLED_GARDEN_SOCKET_TIMEOUT_MS = 10000;
-    private static final int DNS_INTRATEST_PING_INTERVAL = 200; // Long delay to detect setup issues
+    private static final int DNS_INTRATEST_PING_INTERVAL_MS = 200;
+    /* With some router setups, it takes a few hunder milli-seconds before connection is active */
+    private static final int DNS_START_DELAY_MS = 1000;
 
     private static final int BASE = Protocol.BASE_WIFI_WATCHDOG;
 
@@ -677,7 +679,7 @@
             for (int i=0; i < mNumDnsPings; i++) {
                 for (int j = 0; j < numDnses; j++) {
                     idDnsMap.put(mDnsPinger.pingDnsAsync(mDnsList.get(j), mDnsPingTimeoutMs,
-                            DNS_INTRATEST_PING_INTERVAL * i), j);
+                            DNS_START_DELAY_MS + DNS_INTRATEST_PING_INTERVAL_MS * i), j);
                 }
             }
         }
diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pService.java b/wifi/java/android/net/wifi/p2p/WifiP2pService.java
index e2b2249..2f7b927 100644
--- a/wifi/java/android/net/wifi/p2p/WifiP2pService.java
+++ b/wifi/java/android/net/wifi/p2p/WifiP2pService.java
@@ -132,6 +132,9 @@
     /* User rejected to disable Wi-Fi in order to enable p2p */
     private static final int WIFI_DISABLE_USER_REJECT       =   BASE + 5;
 
+    /* Airplane mode changed */
+    private static final int AIRPLANE_MODE_CHANGED          =   BASE + 6;
+
     private final boolean mP2pSupported;
     private final String mDeviceType;
     private String mDeviceName;
@@ -168,6 +171,7 @@
         // broadcasts
         IntentFilter filter = new IntentFilter();
         filter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION);
+        filter.addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED);
         filter.addAction(WifiManager.WIFI_AP_STATE_CHANGED_ACTION);
         mContext.registerReceiver(new WifiStateReceiver(), filter);
 
@@ -187,6 +191,8 @@
             } else if (intent.getAction().equals(WifiManager.WIFI_AP_STATE_CHANGED_ACTION)) {
                 mWifiApState = intent.getIntExtra(WifiManager.EXTRA_WIFI_AP_STATE,
                         WifiManager.WIFI_AP_STATE_DISABLED);
+            } else if (intent.getAction().equals(Intent.ACTION_AIRPLANE_MODE_CHANGED)) {
+                mP2pStateMachine.sendMessage(AIRPLANE_MODE_CHANGED);
             }
         }
     }
@@ -352,7 +358,10 @@
                 case WifiP2pManager.REQUEST_GROUP_INFO:
                     replyToMessage(message, WifiP2pManager.RESPONSE_GROUP_INFO, mGroup);
                     break;
-                // Ignore
+                case AIRPLANE_MODE_CHANGED:
+                    if (isAirplaneModeOn()) sendMessage(WifiP2pManager.DISABLE_P2P);
+                    break;
+                    // Ignore
                 case WIFI_DISABLE_USER_ACCEPT:
                 case WIFI_DISABLE_USER_REJECT:
                 case GROUP_NEGOTIATION_TIMED_OUT:
@@ -1266,5 +1275,17 @@
         }
     }
 
+    private boolean isAirplaneSensitive() {
+        String airplaneModeRadios = Settings.System.getString(mContext.getContentResolver(),
+                Settings.System.AIRPLANE_MODE_RADIOS);
+        return airplaneModeRadios == null
+            || airplaneModeRadios.contains(Settings.System.RADIO_WIFI);
+    }
+
+    private boolean isAirplaneModeOn() {
+        return isAirplaneSensitive() && Settings.System.getInt(mContext.getContentResolver(),
+                Settings.System.AIRPLANE_MODE_ON, 0) == 1;
+    }
+
     }
 }