Merge "Add RS watchdog."
diff --git a/CleanSpec.mk b/CleanSpec.mk
index c1799a1..d0aa368 100644
--- a/CleanSpec.mk
+++ b/CleanSpec.mk
@@ -109,6 +109,7 @@
 $(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/media/audio/)
 $(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework_intermediates/src/core/java/android/nfc/)
 $(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework_intermediates/src/wifi/java)
+$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework_intermediates/src/wifi/java)
 # ************************************************
 # NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
 # ************************************************
diff --git a/api/current.txt b/api/current.txt
index 804a524..69e1cd5 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -5118,6 +5118,7 @@
     field public static final java.lang.String USB_SERVICE = "usb";
     field public static final java.lang.String VIBRATOR_SERVICE = "vibrator";
     field public static final java.lang.String WALLPAPER_SERVICE = "wallpaper";
+    field public static final java.lang.String WIFI_P2P_SERVICE = "wifip2p";
     field public static final java.lang.String WIFI_SERVICE = "wifi";
     field public static final java.lang.String WINDOW_SERVICE = "window";
   }
@@ -10868,16 +10869,6 @@
     method public abstract void onScanCompleted(java.lang.String, android.net.Uri);
   }
 
-  public class Metadata {
-    method public boolean getBoolean(int);
-    method public boolean has(int);
-    method public java.util.Set<java.lang.Integer> keySet();
-    field public static final int PAUSE_AVAILABLE = 1; // 0x1
-    field public static final int SEEK_AVAILABLE = 4; // 0x4
-    field public static final int SEEK_BACKWARD_AVAILABLE = 2; // 0x2
-    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);
@@ -12444,6 +12435,142 @@
     method public void setWorkSource(android.os.WorkSource);
   }
 
+  public class WpsInfo implements android.os.Parcelable {
+    ctor public WpsInfo();
+    ctor public WpsInfo(android.net.wifi.WpsInfo);
+    method public int describeContents();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator CREATOR;
+    field public static final int DISPLAY = 1; // 0x1
+    field public static final int INVALID = 4; // 0x4
+    field public static final int KEYPAD = 2; // 0x2
+    field public static final int LABEL = 3; // 0x3
+    field public static final int PBC = 0; // 0x0
+    field public java.lang.String pin;
+    field public int setup;
+  }
+
+}
+
+package android.net.wifi.p2p {
+
+  public class WifiP2pConfig implements android.os.Parcelable {
+    ctor public WifiP2pConfig();
+    ctor public WifiP2pConfig(android.net.wifi.p2p.WifiP2pConfig);
+    method public int describeContents();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator CREATOR;
+    field public java.lang.String deviceAddress;
+    field public int groupOwnerIntent;
+    field public android.net.wifi.WpsInfo wps;
+  }
+
+  public class WifiP2pDevice implements android.os.Parcelable {
+    ctor public WifiP2pDevice();
+    ctor public WifiP2pDevice(android.net.wifi.p2p.WifiP2pDevice);
+    method public int describeContents();
+    method public boolean isGroupOwner();
+    method public boolean isServiceDiscoveryCapable();
+    method public boolean wpsDisplaySupported();
+    method public boolean wpsKeypadSupported();
+    method public boolean wpsPbcSupported();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final int AVAILABLE = 3; // 0x3
+    field public static final int CONNECTED = 0; // 0x0
+    field public static final android.os.Parcelable.Creator CREATOR;
+    field public static final int FAILED = 2; // 0x2
+    field public static final int INVITED = 1; // 0x1
+    field public static final int UNAVAILABLE = 4; // 0x4
+    field public java.lang.String deviceAddress;
+    field public java.lang.String deviceName;
+    field public java.lang.String primaryDeviceType;
+    field public java.lang.String secondaryDeviceType;
+    field public int status;
+  }
+
+  public class WifiP2pDeviceList implements android.os.Parcelable {
+    ctor public WifiP2pDeviceList();
+    ctor public WifiP2pDeviceList(android.net.wifi.p2p.WifiP2pDeviceList);
+    method public int describeContents();
+    method public java.util.Collection<android.net.wifi.p2p.WifiP2pDevice> getDeviceList();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator CREATOR;
+  }
+
+  public class WifiP2pGroup implements android.os.Parcelable {
+    ctor public WifiP2pGroup();
+    ctor public WifiP2pGroup(android.net.wifi.p2p.WifiP2pGroup);
+    method public int describeContents();
+    method public java.util.Collection<android.net.wifi.p2p.WifiP2pDevice> getClientList();
+    method public java.lang.String getInterface();
+    method public java.lang.String getNetworkName();
+    method public android.net.wifi.p2p.WifiP2pDevice getOwner();
+    method public java.lang.String getPassphrase();
+    method public boolean isGroupOwner();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator CREATOR;
+  }
+
+  public class WifiP2pInfo implements android.os.Parcelable {
+    ctor public WifiP2pInfo();
+    ctor public WifiP2pInfo(android.net.wifi.p2p.WifiP2pInfo);
+    method public int describeContents();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator CREATOR;
+    field public boolean groupFormed;
+    field public java.net.InetAddress groupOwnerAddress;
+    field public boolean isGroupOwner;
+  }
+
+  public class WifiP2pManager {
+    method public void cancelConnect(android.net.wifi.p2p.WifiP2pManager.Channel, android.net.wifi.p2p.WifiP2pManager.ActionListener);
+    method public void connect(android.net.wifi.p2p.WifiP2pManager.Channel, android.net.wifi.p2p.WifiP2pConfig, android.net.wifi.p2p.WifiP2pManager.ActionListener);
+    method public void createGroup(android.net.wifi.p2p.WifiP2pManager.Channel, android.net.wifi.p2p.WifiP2pManager.ActionListener);
+    method public void discoverPeers(android.net.wifi.p2p.WifiP2pManager.Channel, android.net.wifi.p2p.WifiP2pManager.ActionListener);
+    method public android.net.wifi.p2p.WifiP2pManager.Channel initialize(android.content.Context, android.os.Looper, android.net.wifi.p2p.WifiP2pManager.ChannelListener);
+    method public void removeGroup(android.net.wifi.p2p.WifiP2pManager.Channel, android.net.wifi.p2p.WifiP2pManager.ActionListener);
+    method public void requestConnectionInfo(android.net.wifi.p2p.WifiP2pManager.Channel, android.net.wifi.p2p.WifiP2pManager.ConnectionInfoListener);
+    method public void requestGroupInfo(android.net.wifi.p2p.WifiP2pManager.Channel, android.net.wifi.p2p.WifiP2pManager.GroupInfoListener);
+    method public void requestPeers(android.net.wifi.p2p.WifiP2pManager.Channel, android.net.wifi.p2p.WifiP2pManager.PeerListListener);
+    field public static final int BUSY = 2; // 0x2
+    field public static final int ERROR = 0; // 0x0
+    field public static final java.lang.String EXTRA_NETWORK_INFO = "networkInfo";
+    field public static final java.lang.String EXTRA_WIFI_P2P_DEVICE = "wifiP2pDevice";
+    field public static final java.lang.String EXTRA_WIFI_P2P_INFO = "wifiP2pInfo";
+    field public static final java.lang.String EXTRA_WIFI_STATE = "wifi_p2p_state";
+    field public static final int P2P_UNSUPPORTED = 1; // 0x1
+    field public static final java.lang.String WIFI_P2P_CONNECTION_CHANGED_ACTION = "android.net.wifi.p2p.CONNECTION_STATE_CHANGE";
+    field public static final java.lang.String WIFI_P2P_PEERS_CHANGED_ACTION = "android.net.wifi.p2p.PEERS_CHANGED";
+    field public static final java.lang.String WIFI_P2P_STATE_CHANGED_ACTION = "android.net.wifi.p2p.STATE_CHANGED";
+    field public static final int WIFI_P2P_STATE_DISABLED = 1; // 0x1
+    field public static final int WIFI_P2P_STATE_ENABLED = 2; // 0x2
+    field public static final java.lang.String WIFI_P2P_THIS_DEVICE_CHANGED_ACTION = "android.net.wifi.p2p.THIS_DEVICE_CHANGED";
+  }
+
+  public static abstract interface WifiP2pManager.ActionListener {
+    method public abstract void onFailure(int);
+    method public abstract void onSuccess();
+  }
+
+  public static class WifiP2pManager.Channel {
+  }
+
+  public static abstract interface WifiP2pManager.ChannelListener {
+    method public abstract void onChannelDisconnected();
+  }
+
+  public static abstract interface WifiP2pManager.ConnectionInfoListener {
+    method public abstract void onConnectionInfoAvailable(android.net.wifi.p2p.WifiP2pInfo);
+  }
+
+  public static abstract interface WifiP2pManager.GroupInfoListener {
+    method public abstract void onGroupInfoAvailable(android.net.wifi.p2p.WifiP2pGroup);
+  }
+
+  public static abstract interface WifiP2pManager.PeerListListener {
+    method public abstract void onPeersAvailable(android.net.wifi.p2p.WifiP2pDeviceList);
+  }
+
 }
 
 package android.nfc {
@@ -23017,6 +23144,7 @@
     method public void scrollTo(int, int);
     method public void sendAccessibilityEvent(int);
     method public void sendAccessibilityEventUnchecked(android.view.accessibility.AccessibilityEvent);
+    method public void setAccessibilityDelegate(android.view.View.AccessibilityDelegate);
     method public void setActivated(boolean);
     method public void setAlpha(float);
     method public void setAnimation(android.view.animation.Animation);
@@ -23193,6 +23321,17 @@
     field public static android.util.Property Y;
   }
 
+  public static class View.AccessibilityDelegate {
+    ctor public View.AccessibilityDelegate();
+    method public boolean dispatchPopulateAccessibilityEvent(android.view.View, android.view.accessibility.AccessibilityEvent);
+    method public void onInitializeAccessibilityEvent(android.view.View, android.view.accessibility.AccessibilityEvent);
+    method public void onInitializeAccessibilityNodeInfo(android.view.View, android.view.accessibility.AccessibilityNodeInfo);
+    method public void onPopulateAccessibilityEvent(android.view.View, android.view.accessibility.AccessibilityEvent);
+    method public boolean onRequestSendAccessibilityEvent(android.view.ViewGroup, android.view.View, android.view.accessibility.AccessibilityEvent);
+    method public void sendAccessibilityEvent(android.view.View, int);
+    method public void sendAccessibilityEventUnchecked(android.view.View, android.view.accessibility.AccessibilityEvent);
+  }
+
   public static class View.BaseSavedState extends android.view.AbsSavedState {
     ctor public View.BaseSavedState(android.os.Parcel);
     ctor public View.BaseSavedState(android.os.Parcelable);
diff --git a/core/java/android/accounts/AccountManager.java b/core/java/android/accounts/AccountManager.java
index 029d107..be9070d 100644
--- a/core/java/android/accounts/AccountManager.java
+++ b/core/java/android/accounts/AccountManager.java
@@ -189,6 +189,7 @@
     public static final String KEY_ERROR_CODE = "errorCode";
     public static final String KEY_ERROR_MESSAGE = "errorMessage";
     public static final String KEY_USERDATA = "userdata";
+
     /**
      * Authenticators using 'customTokens' option will also get the UID of the
      * caller
@@ -814,11 +815,13 @@
             final Activity activity, AccountManagerCallback<Bundle> callback, Handler handler) {
         if (account == null) throw new IllegalArgumentException("account is null");
         if (authTokenType == null) throw new IllegalArgumentException("authTokenType is null");
+        final Bundle optionsIn = options == null ? new Bundle() : options;
+        optionsIn.putString(KEY_ANDROID_PACKAGE_NAME, mContext.getPackageName());
         return new AmsTask(activity, handler, callback) {
             public void doWork() throws RemoteException {
                 mService.getAuthToken(mResponse, account, authTokenType,
                         false /* notifyOnAuthFailure */, true /* expectActivityLaunch */,
-                        options);
+                        optionsIn);
             }
         }.start();
     }
@@ -895,16 +898,11 @@
      */
     @Deprecated
     public AccountManagerFuture<Bundle> getAuthToken(
-            final Account account, final String authTokenType, final boolean notifyAuthFailure,
+            final Account account, final String authTokenType, 
+            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 */, null /* options */);
-            }
-        }.start();
+        return getAuthToken(account, authTokenType, null, notifyAuthFailure, callback, 
+                handler);
     }
 
     /**
@@ -978,15 +976,18 @@
      * account before requesting an auth token.
      */
     public AccountManagerFuture<Bundle> getAuthToken(
-            final Account account, final String authTokenType,
-            final Bundle options, final boolean notifyAuthFailure,
+            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");
+        final Bundle optionsIn = options == null ? new Bundle() : options;
+        optionsIn.putString(KEY_ANDROID_PACKAGE_NAME, mContext.getPackageName());
         return new AmsTask(null, handler, callback) {
             public void doWork() throws RemoteException {
                 mService.getAuthToken(mResponse, account, authTokenType,
-                        notifyAuthFailure, false /* expectActivityLaunch */, options);
+                        notifyAuthFailure, false /* expectActivityLaunch */, optionsIn);
             }
         }.start();
     }
@@ -1044,10 +1045,14 @@
             final Bundle addAccountOptions,
             final Activity activity, AccountManagerCallback<Bundle> callback, Handler handler) {
         if (accountType == null) throw new IllegalArgumentException("accountType is null");
+        final Bundle options = (addAccountOptions == null) ? new Bundle() :
+            addAccountOptions;
+        options.putString(KEY_ANDROID_PACKAGE_NAME, mContext.getPackageName());
+
         return new AmsTask(activity, handler, callback) {
             public void doWork() throws RemoteException {
                 mService.addAcount(mResponse, accountType, authTokenType,
-                        requiredFeatures, activity != null, addAccountOptions);
+                        requiredFeatures, activity != null, options);
             }
         }.start();
     }
diff --git a/core/java/android/accounts/AccountManagerService.java b/core/java/android/accounts/AccountManagerService.java
index 20d5b96..173da8d 100644
--- a/core/java/android/accounts/AccountManagerService.java
+++ b/core/java/android/accounts/AccountManagerService.java
@@ -16,10 +16,6 @@
 
 package android.accounts;
 
-import com.android.internal.R;
-import com.android.internal.telephony.ITelephony;
-import com.android.internal.telephony.TelephonyIntents;
-
 import android.Manifest;
 import android.app.ActivityManager;
 import android.app.Notification;
@@ -51,13 +47,13 @@
 import android.os.Looper;
 import android.os.Message;
 import android.os.RemoteException;
-import android.os.ServiceManager;
 import android.os.SystemClock;
-import android.telephony.TelephonyManager;
 import android.text.TextUtils;
 import android.util.Log;
 import android.util.Pair;
 
+import com.android.internal.R;
+
 import java.io.File;
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -924,9 +920,6 @@
         if (account == null) throw new IllegalArgumentException("account is null");
         if (authTokenType == null) throw new IllegalArgumentException("authTokenType is null");
         checkBinderPermission(Manifest.permission.USE_CREDENTIALS);
-        final int callerUid = Binder.getCallingUid();
-        final int callerPid = Binder.getCallingPid();
-
         AccountAuthenticatorCache.ServiceInfo<AuthenticatorDescription> authenticatorInfo =
             mAuthenticatorCache.getServiceInfo(
                     AuthenticatorDescription.newKey(account.type));
@@ -934,20 +927,19 @@
             authenticatorInfo != null && authenticatorInfo.type.customTokens;
 
         // skip the check if customTokens
+        final int callerUid = Binder.getCallingUid();
         final boolean permissionGranted = customTokens ||
             permissionIsGranted(account, authTokenType, callerUid);
 
         final Bundle loginOptions = (loginOptionsIn == null) ? new Bundle() :
             loginOptionsIn;
-        if (customTokens) {
-            // let authenticator know the identity of the caller
-            loginOptions.putInt(AccountManager.KEY_CALLER_UID, callerUid);
-            loginOptions.putInt(AccountManager.KEY_CALLER_PID, callerPid);
-            if (notifyOnAuthFailure) {
-                loginOptions.putBoolean(AccountManager.KEY_NOTIFY_ON_FAILURE, true);
-            }
+        // let authenticator know the identity of the caller
+        loginOptions.putInt(AccountManager.KEY_CALLER_UID, callerUid);
+        loginOptions.putInt(AccountManager.KEY_CALLER_PID, Binder.getCallingPid());
+        if (notifyOnAuthFailure) {
+            loginOptions.putBoolean(AccountManager.KEY_NOTIFY_ON_FAILURE, true);
         }
-
+        
         long identityToken = clearCallingIdentity();
         try {
             // if the caller has permission, do the peek. otherwise go the more expensive
@@ -1120,7 +1112,7 @@
 
     public void addAcount(final IAccountManagerResponse response, final String accountType,
             final String authTokenType, final String[] requiredFeatures,
-            final boolean expectActivityLaunch, final Bundle options) {
+            final boolean expectActivityLaunch, final Bundle optionsIn) {
         if (Log.isLoggable(TAG, Log.VERBOSE)) {
             Log.v(TAG, "addAccount: accountType " + accountType
                     + ", response " + response
@@ -1133,6 +1125,13 @@
         if (response == null) throw new IllegalArgumentException("response is null");
         if (accountType == null) throw new IllegalArgumentException("accountType is null");
         checkManageAccountsPermission();
+
+        final int pid = Binder.getCallingPid();
+        final int uid = Binder.getCallingUid();
+        final Bundle options = (optionsIn == null) ? new Bundle() : optionsIn;
+        options.putInt(AccountManager.KEY_CALLER_UID, uid);
+        options.putInt(AccountManager.KEY_CALLER_PID, pid);
+
         long identityToken = clearCallingIdentity();
         try {
             new Session(response, accountType, expectActivityLaunch,
diff --git a/core/java/android/app/ActionBar.java b/core/java/android/app/ActionBar.java
index 0d4a067..be00aa5 100644
--- a/core/java/android/app/ActionBar.java
+++ b/core/java/android/app/ActionBar.java
@@ -915,6 +915,7 @@
                     com.android.internal.R.styleable.ActionBar_LayoutParams);
             gravity = a.getInt(
                     com.android.internal.R.styleable.ActionBar_LayoutParams_layout_gravity, -1);
+            a.recycle();
         }
 
         public LayoutParams(int width, int height) {
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 48f94d0..9468581 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -1647,11 +1647,10 @@
     /**
      * Use with {@link #getSystemService} to retrieve a {@link
      * android.net.wifi.p2p.WifiP2pManager} for handling management of
-     * Wi-Fi p2p.
+     * Wi-Fi peer-to-peer connections.
      *
      * @see #getSystemService
      * @see android.net.wifi.p2p.WifiP2pManager
-     * @hide
      */
     public static final String WIFI_P2P_SERVICE = "wifip2p";
 
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index c61e32f..e7b844c 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -92,6 +92,7 @@
 
     private String mArchiveSourcePath;
     private String[] mSeparateProcesses;
+    private boolean mOnlyCoreApps;
     private static final int SDK_VERSION = Build.VERSION.SDK_INT;
     private static final String SDK_CODENAME = "REL".equals(Build.VERSION.CODENAME)
             ? null : Build.VERSION.CODENAME;
@@ -180,6 +181,10 @@
         mSeparateProcesses = procs;
     }
 
+    public void setOnlyCoreApps(boolean onlyCoreApps) {
+        mOnlyCoreApps = onlyCoreApps;
+    }
+
     private static final boolean isPackageFilename(String name) {
         return name.endsWith(".apk");
     }
@@ -433,18 +438,22 @@
 
 
         if (pkg == null) {
-            if (errorException != null) {
-                Slog.w(TAG, mArchiveSourcePath, errorException);
-            } else {
-                Slog.w(TAG, mArchiveSourcePath + " (at "
-                        + parser.getPositionDescription()
-                        + "): " + errorText[0]);
+            // If we are only parsing core apps, then a null with INSTALL_SUCCEEDED
+            // just means to skip this app so don't make a fuss about it.
+            if (!mOnlyCoreApps || mParseError != PackageManager.INSTALL_SUCCEEDED) {
+                if (errorException != null) {
+                    Slog.w(TAG, mArchiveSourcePath, errorException);
+                } else {
+                    Slog.w(TAG, mArchiveSourcePath + " (at "
+                            + parser.getPositionDescription()
+                            + "): " + errorText[0]);
+                }
+                if (mParseError == PackageManager.INSTALL_SUCCEEDED) {
+                    mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
+                }
             }
             parser.close();
             assmgr.close();
-            if (mParseError == PackageManager.INSTALL_SUCCEEDED) {
-                mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
-            }
             return null;
         }
 
@@ -782,6 +791,14 @@
         }
         int type;
 
+        if (mOnlyCoreApps) {
+            boolean core = attrs.getAttributeBooleanValue(null, "coreApp", false);
+            if (!core) {
+                mParseError = PackageManager.INSTALL_SUCCEEDED;
+                return null;
+            }
+        }
+
         final Package pkg = new Package(pkgName);
         boolean foundApp = false;
         
diff --git a/core/java/android/content/res/Resources.java b/core/java/android/content/res/Resources.java
index d7f901a..4f19010 100755
--- a/core/java/android/content/res/Resources.java
+++ b/core/java/android/content/res/Resources.java
@@ -72,6 +72,7 @@
     static final String TAG = "Resources";
     private static final boolean DEBUG_LOAD = false;
     private static final boolean DEBUG_CONFIG = false;
+    private static final boolean DEBUG_ATTRIBUTES_CACHE = false;
     private static final boolean TRACE_FOR_PRELOAD = false;
     private static final boolean TRACE_FOR_MISS_PRELOAD = false;
 
@@ -104,6 +105,7 @@
     private boolean mPreloading;
 
     /*package*/ TypedArray mCachedStyledAttributes = null;
+    RuntimeException mLastRetrievedAttrs = null;
 
     private int mLastCachedXmlBlockIndex = -1;
     private final int[] mCachedXmlBlockIds = { 0, 0, 0, 0 };
@@ -2167,6 +2169,10 @@
             TypedArray attrs = mCachedStyledAttributes;
             if (attrs != null) {
                 mCachedStyledAttributes = null;
+                if (DEBUG_ATTRIBUTES_CACHE) {
+                    mLastRetrievedAttrs = new RuntimeException("here");
+                    mLastRetrievedAttrs.fillInStackTrace();
+                }
 
                 attrs.mLength = len;
                 int fullLen = len * AssetManager.STYLE_NUM_ENTRIES;
@@ -2177,6 +2183,15 @@
                 attrs.mIndices = new int[1+len];
                 return attrs;
             }
+            if (DEBUG_ATTRIBUTES_CACHE) {
+                RuntimeException here = new RuntimeException("here");
+                here.fillInStackTrace();
+                if (mLastRetrievedAttrs != null) {
+                    Log.i(TAG, "Allocated new TypedArray of " + len + " in " + this, here);
+                    Log.i(TAG, "Last retrieved attributes here", mLastRetrievedAttrs);
+                }
+                mLastRetrievedAttrs = here;
+            }
             return new TypedArray(this,
                     new int[len*AssetManager.STYLE_NUM_ENTRIES],
                     new int[1+len], len);
diff --git a/core/java/android/net/MobileDataStateTracker.java b/core/java/android/net/MobileDataStateTracker.java
index 65c1bd5..bcf6239 100644
--- a/core/java/android/net/MobileDataStateTracker.java
+++ b/core/java/android/net/MobileDataStateTracker.java
@@ -394,7 +394,7 @@
                     && lastReason != null)
                 reason = lastReason;
             mNetworkInfo.setDetailedState(state, reason, extraInfo);
-            Message msg = mTarget.obtainMessage(EVENT_STATE_CHANGED, mNetworkInfo);
+            Message msg = mTarget.obtainMessage(EVENT_STATE_CHANGED, new NetworkInfo(mNetworkInfo));
             msg.sendToTarget();
         }
     }
diff --git a/core/java/android/net/NetworkStatsHistory.java b/core/java/android/net/NetworkStatsHistory.java
index d07d899..d8ac31f 100644
--- a/core/java/android/net/NetworkStatsHistory.java
+++ b/core/java/android/net/NetworkStatsHistory.java
@@ -29,6 +29,7 @@
 
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.util.MathUtils;
 
 import java.io.CharArrayWriter;
 import java.io.DataInputStream;
@@ -207,6 +208,34 @@
     }
 
     /**
+     * Return index of bucket that contains or is immediately before the
+     * requested time.
+     */
+    public int getIndexBefore(long time) {
+        int index = Arrays.binarySearch(bucketStart, 0, bucketCount, time);
+        if (index < 0) {
+            index = (~index) - 1;
+        } else {
+            index -= 1;
+        }
+        return MathUtils.constrain(index, 0, bucketCount - 1);
+    }
+
+    /**
+     * Return index of bucket that contains or is immediately after the
+     * requested time.
+     */
+    public int getIndexAfter(long time) {
+        int index = Arrays.binarySearch(bucketStart, 0, bucketCount, time);
+        if (index < 0) {
+            index = ~index;
+        } else {
+            index += 1;
+        }
+        return MathUtils.constrain(index, 0, bucketCount - 1);
+    }
+
+    /**
      * Return specific stats entry.
      */
     public Entry getValues(int i, Entry recycle) {
@@ -247,7 +276,8 @@
 
         // distribute data usage into buckets
         long duration = end - start;
-        for (int i = bucketCount - 1; i >= 0; i--) {
+        final int startIndex = getIndexAfter(end);
+        for (int i = startIndex; i >= 0; i--) {
             final long curStart = bucketStart[i];
             final long curEnd = curStart + bucketDuration;
 
@@ -406,7 +436,8 @@
         entry.txPackets = txPackets != null ? 0 : UNKNOWN;
         entry.operations = operations != null ? 0 : UNKNOWN;
 
-        for (int i = bucketCount - 1; i >= 0; i--) {
+        final int startIndex = getIndexAfter(end);
+        for (int i = startIndex; i >= 0; i--) {
             final long curStart = bucketStart[i];
             final long curEnd = curStart + bucketDuration;
 
@@ -417,8 +448,14 @@
 
             // include full value for active buckets, otherwise only fractional
             final boolean activeBucket = curStart < now && curEnd > now;
-            final long overlap = activeBucket ? bucketDuration
-                    : Math.min(curEnd, end) - Math.max(curStart, start);
+            final long overlap;
+            if (activeBucket) {
+                overlap = bucketDuration;
+            } else {
+                final long overlapEnd = curEnd < end ? curEnd : end;
+                final long overlapStart = curStart > start ? curStart : start;
+                overlap = overlapEnd - overlapStart;
+            }
             if (overlap <= 0) continue;
 
             // integer math each time is faster than floating point
diff --git a/core/java/android/text/TextLine.java b/core/java/android/text/TextLine.java
index 68a6b3e..a52d48e 100644
--- a/core/java/android/text/TextLine.java
+++ b/core/java/android/text/TextLine.java
@@ -723,7 +723,7 @@
         float ret = 0;
 
         int contextLen = contextEnd - contextStart;
-        if (needWidth || (c != null && (wp.bgColor != 0 || wp.underlineCount != 0 || runIsRtl))) {
+        if (needWidth || (c != null && (wp.bgColor != 0 || wp.underlineColor != 0 || runIsRtl))) {
             int flags = runIsRtl ? Paint.DIRECTION_RTL : Paint.DIRECTION_LTR;
             if (mCharsValid) {
                 ret = wp.getTextRunAdvances(mChars, start, runLen,
@@ -753,7 +753,7 @@
                 wp.setColor(previousColor);
             }
 
-            if (wp.underlineCount != 0) {
+            if (wp.underlineColor != 0) {
                 // kStdUnderline_Offset = 1/9, defined in SkTextFormatParams.h
                 float underlineTop = y + wp.baselineShift + (1.0f / 9.0f) * wp.getTextSize();
 
@@ -764,11 +764,8 @@
                 wp.setStyle(Paint.Style.FILL);
                 wp.setAntiAlias(true);
 
-                for (int i = 0; i < wp.underlineCount; i++) {
-                    wp.setColor(wp.underlineColors[i]);
-                    c.drawRect(x, underlineTop, x + ret, underlineTop + wp.underlineThicknesses[i],
-                            wp);
-                }
+                wp.setColor(wp.underlineColor);
+                c.drawRect(x, underlineTop, x + ret, underlineTop + wp.underlineThickness, wp);
 
                 wp.setStyle(previousStyle);
                 wp.setColor(previousColor);
diff --git a/core/java/android/text/TextPaint.java b/core/java/android/text/TextPaint.java
index afd9892..0447117 100644
--- a/core/java/android/text/TextPaint.java
+++ b/core/java/android/text/TextPaint.java
@@ -24,8 +24,6 @@
  */
 public class TextPaint extends Paint {
 
-    private static final int DEFAULT_UNDERLINE_SIZE = 3;
-
     // Special value 0 means no background paint
     public int bgColor;
     public int baselineShift;
@@ -36,17 +34,12 @@
      * Special value 0 means no custom underline
      * @hide
      */
-    public int[] underlineColors;
+    public int underlineColor = 0;
     /**
      * Defined as a multiplier of the default underline thickness. Use 1.0f for default thickness.
      * @hide
      */
-    public float[] underlineThicknesses;
-    /**
-     * The number of underlines currently stored in the array. If 0, no underline is drawn.
-     * @hide
-     */
-    public int underlineCount;
+    public float underlineThickness;
 
     public TextPaint() {
         super();
@@ -72,16 +65,8 @@
         linkColor = tp.linkColor;
         drawableState = tp.drawableState;
         density = tp.density;
-
-        if (tp.underlineColors != null) {
-            if (underlineColors == null || underlineColors.length < tp.underlineCount) {
-                underlineColors = new int[tp.underlineCount];
-                underlineThicknesses = new float[tp.underlineCount];
-            }
-            System.arraycopy(tp.underlineColors, 0, underlineColors, 0, tp.underlineCount);
-            System.arraycopy(tp.underlineThicknesses, 0, underlineThicknesses, 0, tp.underlineCount);
-        }
-        underlineCount = tp.underlineCount;
+        underlineColor = tp.underlineColor;
+        underlineThickness = tp.underlineThickness;
     }
 
     /**
@@ -91,31 +76,7 @@
      * @hide
      */
     public void setUnderlineText(int color, float thickness) {
-        if (color == 0) {
-            // No underline
-            return;
-        }
-
-        if (underlineCount == 0) {
-            underlineColors = new int[DEFAULT_UNDERLINE_SIZE];
-            underlineThicknesses = new float[DEFAULT_UNDERLINE_SIZE];
-            underlineColors[underlineCount] = color;
-            underlineThicknesses[underlineCount] = thickness;
-            underlineCount++;
-        } else {
-            if (underlineCount == underlineColors.length) {
-                int[] newColors = new int[underlineColors.length + DEFAULT_UNDERLINE_SIZE];
-                float[] newThickness = new float[underlineThicknesses.length
-                        + DEFAULT_UNDERLINE_SIZE];
-                System.arraycopy(underlineColors, 0, newColors, 0, underlineColors.length);
-                System.arraycopy(
-                        underlineThicknesses, 0, newThickness, 0, underlineThicknesses.length);
-                underlineColors = newColors;
-                underlineThicknesses = newThickness;
-            }
-            underlineColors[underlineCount] = color;
-            underlineThicknesses[underlineCount] = thickness;
-            underlineCount++;
-        }
+        underlineColor = color;
+        underlineThickness = thickness;
     }
 }
diff --git a/core/java/android/text/style/SuggestionSpan.java b/core/java/android/text/style/SuggestionSpan.java
index 51e9d7d..1379dd2d 100644
--- a/core/java/android/text/style/SuggestionSpan.java
+++ b/core/java/android/text/style/SuggestionSpan.java
@@ -108,7 +108,8 @@
     /**
      * @param context Context for the application
      * @param locale locale Locale of the suggestions
-     * @param suggestions Suggestions for the string under the span
+     * @param suggestions Suggestions for the string under the span. Only the first up to
+     * {@link SuggestionSpan#SUGGESTIONS_MAX_SIZE} will be considered.
      * @param flags Additional flags indicating how this span is handled in TextView
      * @param notificationTargetClass if not null, this class will get notified when the user
      * selects one of the suggestions.
@@ -258,10 +259,16 @@
 
     @Override
     public void updateDrawState(TextPaint tp) {
-        if ((mFlags & FLAG_MISSPELLED) != 0) {
-            tp.setUnderlineText(mMisspelledUnderlineColor, mMisspelledUnderlineThickness);
-        } else if ((mFlags & FLAG_EASY_CORRECT) != 0) {
-            tp.setUnderlineText(mEasyCorrectUnderlineColor, mEasyCorrectUnderlineThickness);
+        final boolean misspelled = (mFlags & FLAG_MISSPELLED) != 0;
+        final boolean easy = (mFlags & FLAG_EASY_CORRECT) != 0;
+        if (easy) {
+            if (!misspelled) {
+                tp.setUnderlineText(mEasyCorrectUnderlineColor, mEasyCorrectUnderlineThickness);
+            } else if (tp.underlineColor == 0) {
+                // Spans are rendered in an arbitrary order. Since misspelled is less prioritary
+                // than just easy, do not apply misspelled if an easy (or a mispelled) has been set
+                tp.setUnderlineText(mMisspelledUnderlineColor, mMisspelledUnderlineThickness);
+            }
         }
     }
 
@@ -272,8 +279,15 @@
      */
     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;
+        final boolean misspelled = (mFlags & FLAG_MISSPELLED) != 0;
+        final boolean easy = (mFlags & FLAG_EASY_CORRECT) != 0;
+        if (easy) {
+            if (!misspelled) {
+                return mEasyCorrectUnderlineColor;
+            } else {
+                return mMisspelledUnderlineColor;
+            }
+        }
         return 0;
     }
 }
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index eedf19f..65e9857 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -27,7 +27,6 @@
 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;
@@ -2272,8 +2271,6 @@
      */
     int mOldHeightMeasureSpec = Integer.MIN_VALUE;
 
-    private Resources mResources = null;
-
     private Drawable mBGDrawable;
 
     private int mBackgroundResource;
@@ -2336,6 +2333,8 @@
      */
     protected Context mContext;
 
+    private final Resources mResources;
+
     private ScrollabilityCache mScrollCache;
 
     private int[] mDrawableState = null;
@@ -2552,6 +2551,11 @@
     private boolean mSendingHoverAccessibilityEvents;
 
     /**
+     * Delegate for injecting accessiblity functionality.
+     */
+    AccessibilityDelegate mAccessibilityDelegate;
+
+    /**
      * Text direction is inherited thru {@link ViewGroup}
      * @hide
      */
@@ -3012,6 +3016,8 @@
             }
         }
 
+        a.recycle();
+
         setOverScrollMode(overScrollMode);
 
         if (background != null) {
@@ -3069,14 +3075,13 @@
         }
 
         computeOpaqueFlags();
-
-        a.recycle();
     }
 
     /**
      * Non-public constructor for use in testing
      */
     View() {
+        mResources = null;
     }
 
     /**
@@ -3774,14 +3779,34 @@
      * and last calls
      * {@link ViewParent#requestSendAccessibilityEvent(View, AccessibilityEvent)}
      * on its parent to resuest sending of the event to interested parties.
+     * <p>
+     * If an {@link AccessibilityDelegate} has been specified via calling
+     * {@link #setAccessibilityDelegate(AccessibilityDelegate)} its
+     * {@link AccessibilityDelegate#sendAccessibilityEvent(View, int)} is
+     * responsible for handling this call.
+     * </p>
      *
      * @param eventType The type of the event to send.
      *
      * @see #onInitializeAccessibilityEvent(AccessibilityEvent)
      * @see #dispatchPopulateAccessibilityEvent(AccessibilityEvent)
      * @see ViewParent#requestSendAccessibilityEvent(View, AccessibilityEvent)
+     * @see AccessibilityDelegate
      */
     public void sendAccessibilityEvent(int eventType) {
+        if (mAccessibilityDelegate != null) {
+            mAccessibilityDelegate.sendAccessibilityEvent(this, eventType);
+        } else {
+            sendAccessibilityEventInternal(eventType);
+        }
+    }
+
+    /**
+     * @see #sendAccessibilityEvent(int)
+     *
+     * Note: Called from the default {@link AccessibilityDelegate}.
+     */
+    void sendAccessibilityEventInternal(int eventType) {
         if (AccessibilityManager.getInstance(mContext).isEnabled()) {
             sendAccessibilityEventUnchecked(AccessibilityEvent.obtain(eventType));
         }
@@ -3790,13 +3815,32 @@
     /**
      * This method behaves exactly as {@link #sendAccessibilityEvent(int)} but
      * takes as an argument an empty {@link AccessibilityEvent} and does not
-     * perfrom a check whether accessibility is enabled.
+     * perform a check whether accessibility is enabled.
+     * <p>
+     * If an {@link AccessibilityDelegate} has been specified via calling
+     * {@link #setAccessibilityDelegate(AccessibilityDelegate)} its
+     * {@link AccessibilityDelegate#sendAccessibilityEventUnchecked(View, AccessibilityEvent)}
+     * is responsible for handling this call.
+     * </p>
      *
      * @param event The event to send.
      *
      * @see #sendAccessibilityEvent(int)
      */
     public void sendAccessibilityEventUnchecked(AccessibilityEvent event) {
+        if (mAccessibilityDelegate != null) {
+           mAccessibilityDelegate.sendAccessibilityEventUnchecked(this, event);
+        } else {
+            sendAccessibilityEventUncheckedInternal(event);
+        }
+    }
+
+    /**
+     * @see #sendAccessibilityEventUnchecked(AccessibilityEvent)
+     *
+     * Note: Called from the default {@link AccessibilityDelegate}.
+     */
+    void sendAccessibilityEventUncheckedInternal(AccessibilityEvent event) {
         if (!isShown()) {
             return;
         }
@@ -3811,18 +3855,36 @@
      * to its children for adding their text content to the event. Note that the
      * event text is populated in a separate dispatch path since we add to the
      * event not only the text of the source but also the text of all its descendants.
-     * </p>
      * A typical implementation will call
      * {@link #onPopulateAccessibilityEvent(AccessibilityEvent)} on the this view
      * and then call the {@link #dispatchPopulateAccessibilityEvent(AccessibilityEvent)}
      * on each child. Override this method if custom population of the event text
      * content is required.
+     * <p>
+     * If an {@link AccessibilityDelegate} has been specified via calling
+     * {@link #setAccessibilityDelegate(AccessibilityDelegate)} its
+     * {@link AccessibilityDelegate#dispatchPopulateAccessibilityEvent(View, AccessibilityEvent)}
+     * is responsible for handling this call.
+     * </p>
      *
      * @param event The event.
      *
      * @return True if the event population was completed.
      */
     public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) {
+        if (mAccessibilityDelegate != null) {
+            return mAccessibilityDelegate.dispatchPopulateAccessibilityEvent(this, event);
+        } else {
+            return dispatchPopulateAccessibilityEventInternal(event);
+        }
+    }
+
+    /**
+     * @see #dispatchPopulateAccessibilityEvent(AccessibilityEvent)
+     *
+     * Note: Called from the default {@link AccessibilityDelegate}.
+     */
+    boolean dispatchPopulateAccessibilityEventInternal(AccessibilityEvent event) {
         onPopulateAccessibilityEvent(event);
         return false;
     }
@@ -3845,6 +3907,12 @@
      *     event.getText().add(selectedDateUtterance);
      * }
      * </code></pre></p>
+     * <p>
+     * If an {@link AccessibilityDelegate} has been specified via calling
+     * {@link #setAccessibilityDelegate(AccessibilityDelegate)} its
+     * {@link AccessibilityDelegate#onPopulateAccessibilityEvent(View, AccessibilityEvent)}
+     * is responsible for handling this call.
+     * </p>
      *
      * @param event The accessibility event which to populate.
      *
@@ -3852,13 +3920,27 @@
      * @see #dispatchPopulateAccessibilityEvent(AccessibilityEvent)
      */
     public void onPopulateAccessibilityEvent(AccessibilityEvent event) {
+        if (mAccessibilityDelegate != null) {
+            mAccessibilityDelegate.onPopulateAccessibilityEvent(this, event);
+        } else {
+            onPopulateAccessibilityEventInternal(event);
+        }
     }
 
     /**
-     * Initializes an {@link AccessibilityEvent} with information about the
-     * the type of the event and this View which is the event source. In other
-     * words, the source of an accessibility event is the view whose state
-     * change triggered firing the event.
+     * @see #onPopulateAccessibilityEvent(AccessibilityEvent)
+     *
+     * Note: Called from the default {@link AccessibilityDelegate}.
+     */
+    void onPopulateAccessibilityEventInternal(AccessibilityEvent event) {
+
+    }
+
+    /**
+     * Initializes an {@link AccessibilityEvent} with information about
+     * this View which is the event source. In other words, the source of
+     * an accessibility event is the view whose state change triggered firing
+     * the event.
      * <p>
      * Example: Setting the password property of an event in addition
      *          to properties set by the super implementation.
@@ -3868,12 +3950,32 @@
      *    event.setPassword(true);
      * }
      * </code></pre></p>
-     * @param event The event to initialeze.
+     * <p>
+     * If an {@link AccessibilityDelegate} has been specified via calling
+     * {@link #setAccessibilityDelegate(AccessibilityDelegate)} its
+     * {@link AccessibilityDelegate#onInitializeAccessibilityEvent(View, AccessibilityEvent)}
+     * is responsible for handling this call.
+     * </p>
+     *
+     * @param event The event to initialize.
      *
      * @see #sendAccessibilityEvent(int)
      * @see #dispatchPopulateAccessibilityEvent(AccessibilityEvent)
      */
     public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
+        if (mAccessibilityDelegate != null) {
+            mAccessibilityDelegate.onInitializeAccessibilityEvent(this, event);
+        } else {
+            onInitializeAccessibilityEventInternal(event);
+        }
+    }
+
+    /**
+     * @see #onInitializeAccessibilityEvent(AccessibilityEvent)
+     *
+     * Note: Called from the default {@link AccessibilityDelegate}.
+     */
+    void onInitializeAccessibilityEventInternal(AccessibilityEvent event) {
         event.setSource(this);
         event.setClassName(getClass().getName());
         event.setPackageName(getContext().getPackageName());
@@ -3942,9 +4044,29 @@
      * Subclasses should override this method, call the super implementation,
      * and set additional attributes.
      * </p>
+     * <p>
+     * If an {@link AccessibilityDelegate} has been specified via calling
+     * {@link #setAccessibilityDelegate(AccessibilityDelegate)} its
+     * {@link AccessibilityDelegate#onInitializeAccessibilityNodeInfo(View, AccessibilityNodeInfo)}
+     * is responsible for handling this call.
+     * </p>
+     *
      * @param info The instance to initialize.
      */
     public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
+        if (mAccessibilityDelegate != null) {
+            mAccessibilityDelegate.onInitializeAccessibilityNodeInfo(this, info);
+        } else {
+            onInitializeAccessibilityNodeInfoInternal(info);
+        }
+    }
+
+    /**
+     * @see #onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo)
+     *
+     * Note: Called from the default {@link AccessibilityDelegate}.
+     */
+    void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) {
         Rect bounds = mAttachInfo.mTmpInvalRect;
         getDrawingRect(bounds);
         info.setBoundsInParent(bounds);
@@ -3988,6 +4110,19 @@
     }
 
     /**
+     * Sets a delegate for implementing accessibility support via compositon as
+     * opposed to inheritance. The delegate's primary use is for implementing
+     * backwards compatible widgets. For more details see {@link AccessibilityDelegate}.
+     *
+     * @param delegate The delegate instance.
+     *
+     * @see AccessibilityDelegate
+     */
+    public void setAccessibilityDelegate(AccessibilityDelegate delegate) {
+        mAccessibilityDelegate = delegate;
+    }
+
+    /**
      * Gets the unique identifier of this view on the screen for accessibility purposes.
      * If this {@link View} is not attached to any window, {@value #NO_ID} is returned.
      *
@@ -10192,7 +10327,7 @@
 
     /**
      * Setting a solid background color for the drawing cache's bitmaps will improve
-     * perfromance and memory usage. Note, though that this should only be used if this
+     * performance and memory usage. Note, though that this should only be used if this
      * view will always be drawn on top of a solid color.
      *
      * @param color The background color to use for the drawing cache's bitmap
@@ -13039,6 +13174,10 @@
                         shadowSize.x, shadowSize.y,
                         shadowTouchPoint.x, shadowTouchPoint.y, data);
                 if (ViewDebug.DEBUG_DRAG) Log.d(VIEW_LOG_TAG, "performDrag returned " + okay);
+
+                // Off and running!  Release our local surface instance; the drag
+                // shadow surface is now managed by the system process.
+                surface.release();
             }
         } catch (Exception e) {
             Log.e(VIEW_LOG_TAG, "Unable to initiate drag", e);
@@ -14417,4 +14556,205 @@
             mIsPending = false;
         }
     }
+
+    /**
+     * <p>
+     * This class represents a delegate that can be registered in a {@link View}
+     * to enhance accessibility support via composition rather via inheritance.
+     * It is specifically targeted to widget developers that extend basic View
+     * classes i.e. classes in package android.view, that would like their
+     * applications to be backwards compatible.
+     * </p>
+     * <p>
+     * A scenario in which a developer would like to use an accessibility delegate
+     * is overriding a method introduced in a later API version then the minimal API
+     * version supported by the application. For example, the method
+     * {@link View#onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo)} is not available
+     * in API version 4 when the accessibility APIs were first introduced. If a
+     * developer would like his application to run on API version 4 devices (assuming
+     * all other APIs used by the application are version 4 or lower) and take advantage
+     * of this method, instead of overriding the method which would break the application's
+     * backwards compatibility, he can override the corresponding method in this
+     * delegate and register the delegate in the target View if the API version of
+     * the system is high enough i.e. the API version is same or higher to the API
+     * version that introduced
+     * {@link View#onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo)}.
+     * </p>
+     * <p>
+     * Here is an example implementation:
+     * </p>
+     * <code><pre><p>
+     * if (Build.VERSION.SDK_INT >= 14) {
+     *     // If the API version is equal of higher than the version in
+     *     // which onInitializeAccessibilityNodeInfo was introduced we
+     *     // register a delegate with a customized implementation.
+     *     View view = findViewById(R.id.view_id);
+     *     view.setAccessibilityDelegate(new AccessibilityDelegate() {
+     *         public void onInitializeAccessibilityNodeInfo(View host,
+     *                 AccessibilityNodeInfo info) {
+     *             // Let the default implementation populate the info.
+     *             super.onInitializeAccessibilityNodeInfo(host, info);
+     *             // Set some other information.
+     *             info.setEnabled(host.isEnabled());
+     *         }
+     *     });
+     * }
+     * </code></pre></p>
+     * <p>
+     * This delegate contains methods that correspond to the accessibility methods
+     * in View. If a delegate has been specified the implementation in View hands
+     * off handling to the corresponding method in this delegate. The default
+     * implementation the delegate methods behaves exactly as the corresponding
+     * method in View for the case of no accessibility delegate been set. Hence,
+     * to customize the behavior of a View method, clients can override only the
+     * corresponding delegate method without altering the behavior of the rest
+     * accessibility related methods of the host view.
+     * </p>
+     */
+    public static class AccessibilityDelegate {
+
+        /**
+         * Sends an accessibility event of the given type. If accessibility is not
+         * enabled this method has no effect.
+         * <p>
+         * The default implementation behaves as {@link View#sendAccessibilityEvent(int)
+         *  View#sendAccessibilityEvent(int)} for the case of no accessibility delegate
+         * been set.
+         * </p>
+         *
+         * @param host The View hosting the delegate.
+         * @param eventType The type of the event to send.
+         *
+         * @see View#sendAccessibilityEvent(int) View#sendAccessibilityEvent(int)
+         */
+        public void sendAccessibilityEvent(View host, int eventType) {
+            host.sendAccessibilityEventInternal(eventType);
+        }
+
+        /**
+         * Sends an accessibility event. This method behaves exactly as
+         * {@link #sendAccessibilityEvent(View, int)} but takes as an argument an
+         * empty {@link AccessibilityEvent} and does not perform a check whether
+         * accessibility is enabled.
+         * <p>
+         * The default implementation behaves as
+         * {@link View#sendAccessibilityEventUnchecked(AccessibilityEvent)
+         *  View#sendAccessibilityEventUnchecked(AccessibilityEvent)} for
+         * the case of no accessibility delegate been set.
+         * </p>
+         *
+         * @param host The View hosting the delegate.
+         * @param event The event to send.
+         *
+         * @see View#sendAccessibilityEventUnchecked(AccessibilityEvent)
+         *      View#sendAccessibilityEventUnchecked(AccessibilityEvent)
+         */
+        public void sendAccessibilityEventUnchecked(View host, AccessibilityEvent event) {
+            host.sendAccessibilityEventUncheckedInternal(event);
+        }
+
+        /**
+         * Dispatches an {@link AccessibilityEvent} to the host {@link View} first and then
+         * to its children for adding their text content to the event.
+         * <p>
+         * The default implementation behaves as
+         * {@link View#dispatchPopulateAccessibilityEvent(AccessibilityEvent)
+         *  View#dispatchPopulateAccessibilityEvent(AccessibilityEvent)} for
+         * the case of no accessibility delegate been set.
+         * </p>
+         *
+         * @param host The View hosting the delegate.
+         * @param event The event.
+         * @return True if the event population was completed.
+         *
+         * @see View#dispatchPopulateAccessibilityEvent(AccessibilityEvent)
+         *      View#dispatchPopulateAccessibilityEvent(AccessibilityEvent)
+         */
+        public boolean dispatchPopulateAccessibilityEvent(View host, AccessibilityEvent event) {
+            return host.dispatchPopulateAccessibilityEventInternal(event);
+        }
+
+        /**
+         * Gives a chance to the host View to populate the accessibility event with its
+         * text content.
+         * <p>
+         * The default implementation behaves as
+         * {@link View#onPopulateAccessibilityEvent(AccessibilityEvent)
+         *  View#onPopulateAccessibilityEvent(AccessibilityEvent)} for
+         * the case of no accessibility delegate been set.
+         * </p>
+         *
+         * @param host The View hosting the delegate.
+         * @param event The accessibility event which to populate.
+         *
+         * @see View#onPopulateAccessibilityEvent(AccessibilityEvent)
+         *      View#onPopulateAccessibilityEvent(AccessibilityEvent)
+         */
+        public void onPopulateAccessibilityEvent(View host, AccessibilityEvent event) {
+            host.onPopulateAccessibilityEventInternal(event);
+        }
+
+        /**
+         * Initializes an {@link AccessibilityEvent} with information about the
+         * the host View which is the event source.
+         * <p>
+         * The default implementation behaves as
+         * {@link View#onInitializeAccessibilityEvent(AccessibilityEvent)
+         *  View#onInitializeAccessibilityEvent(AccessibilityEvent)} for
+         * the case of no accessibility delegate been set.
+         * </p>
+         *
+         * @param host The View hosting the delegate.
+         * @param event The event to initialize.
+         *
+         * @see View#onInitializeAccessibilityEvent(AccessibilityEvent)
+         *      View#onInitializeAccessibilityEvent(AccessibilityEvent)
+         */
+        public void onInitializeAccessibilityEvent(View host, AccessibilityEvent event) {
+            host.onInitializeAccessibilityEventInternal(event);
+        }
+
+        /**
+         * Initializes an {@link AccessibilityNodeInfo} with information about the host view.
+         * <p>
+         * The default implementation behaves as
+         * {@link View#onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo)
+         *  View#onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo)} for
+         * the case of no accessibility delegate been set.
+         * </p>
+         *
+         * @param host The View hosting the delegate.
+         * @param info The instance to initialize.
+         *
+         * @see View#onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo)
+         *      View#onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo)
+         */
+        public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfo info) {
+            host.onInitializeAccessibilityNodeInfoInternal(info);
+        }
+
+        /**
+         * Called when a child of the host View has requested sending an
+         * {@link AccessibilityEvent} and gives an opportunity to the parent (the host)
+         * to augment the event.
+         * <p>
+         * The default implementation behaves as
+         * {@link ViewGroup#onRequestSendAccessibilityEvent(View, AccessibilityEvent)
+         *  ViewGroup#onRequestSendAccessibilityEvent(View, AccessibilityEvent)} for
+         * the case of no accessibility delegate been set.
+         * </p>
+         *
+         * @param host The View hosting the delegate.
+         * @param child The child which requests sending the event.
+         * @param event The event to be sent.
+         * @return True if the event should be sent
+         *
+         * @see ViewGroup#onRequestSendAccessibilityEvent(View, AccessibilityEvent)
+         *      ViewGroup#onRequestSendAccessibilityEvent(View, AccessibilityEvent)
+         */
+        public boolean onRequestSendAccessibilityEvent(ViewGroup host, View child,
+                AccessibilityEvent event) {
+            return host.onRequestSendAccessibilityEventInternal(child, event);
+        }
+    }
 }
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index 0e420d6..1bd0782 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -34,6 +34,7 @@
 import android.util.AttributeSet;
 import android.util.Log;
 import android.util.SparseArray;
+import android.view.View.AccessibilityDelegate;
 import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.AccessibilityNodeInfo;
 import android.view.animation.Animation;
@@ -606,6 +607,12 @@
     /**
      * Called when a child has requested sending an {@link AccessibilityEvent} and
      * gives an opportunity to its parent to augment the event.
+     * <p>
+     * If an {@link AccessibilityDelegate} has been specified via calling
+     * {@link #setAccessibilityDelegate(AccessibilityDelegate)} its
+     * {@link AccessibilityDelegate#onRequestSendAccessibilityEvent(ViewGroup, View, AccessibilityEvent)}
+     * is responsible for handling this call.
+     * </p>
      *
      * @param child The child which requests sending the event.
      * @param event The event to be sent.
@@ -614,6 +621,19 @@
      * @see #requestSendAccessibilityEvent(View, AccessibilityEvent)
      */
     public boolean onRequestSendAccessibilityEvent(View child, AccessibilityEvent event) {
+        if (mAccessibilityDelegate != null) {
+            return mAccessibilityDelegate.onRequestSendAccessibilityEvent(this, child, event);
+        } else {
+            return onRequestSendAccessibilityEventInternal(child, event);
+        }
+    }
+
+    /**
+     * @see #onRequestSendAccessibilityEvent(View, AccessibilityEvent)
+     *
+     * Note: Called from the default {@link View.AccessibilityDelegate}.
+     */
+    boolean onRequestSendAccessibilityEventInternal(View child, AccessibilityEvent event) {
         return true;
     }
 
@@ -2142,9 +2162,9 @@
     }
 
     @Override
-    public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) {
+    boolean dispatchPopulateAccessibilityEventInternal(AccessibilityEvent event) {
         // We first get a chance to populate the event.
-        onPopulateAccessibilityEvent(event);
+        super.dispatchPopulateAccessibilityEventInternal(event);
         // Let our children have a shot in populating the event.
         for (int i = 0, count = getChildCount(); i < count; i++) {
             View child = getChildAt(i);
@@ -2159,8 +2179,8 @@
     }
 
     @Override
-    public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
-        super.onInitializeAccessibilityNodeInfo(info);
+    void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) {
+        super.onInitializeAccessibilityNodeInfoInternal(info);
         // If the view is not the topmost one in the view hierarchy and it is
         // marked as the logical root of a view hierarchy, do not go any deeper.
         if ((!(getParent() instanceof ViewRootImpl)) && (mPrivateFlags & IS_ROOT_NAMESPACE) != 0) {
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index fb3f6e8..81f9d78 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -164,11 +164,14 @@
 
     final W mWindow;
 
+    final int mTargetSdkVersion;
+
     View mView;
     View mFocusedView;
     View mRealFocusedView;  // this is not set to null in touch mode
     int mViewVisibility;
     boolean mAppVisible = true;
+    int mOrigWindowType = -1;
 
     // Set to true if the owner of this window is in the stopped state,
     // so the window should no longer be active.
@@ -331,6 +334,7 @@
         mVisRect = new Rect();
         mWinFrame = new Rect();
         mWindow = new W(this);
+        mTargetSdkVersion = context.getApplicationInfo().targetSdkVersion;
         mInputMethodCallback = new InputMethodCallback(this);
         mViewVisibility = View.GONE;
         mTransparentRegion = new Region();
@@ -461,6 +465,7 @@
                     mInputChannel = new InputChannel();
                 }
                 try {
+                    mOrigWindowType = mWindowAttributes.type;
                     res = sWindowSession.add(mWindow, mWindowAttributes,
                             getHostVisibility(), mAttachInfo.mContentInsets,
                             mInputChannel);
@@ -3481,6 +3486,14 @@
         }
         mPendingConfiguration.seq = 0;
         //Log.d(TAG, ">>>>>> CALLING relayout");
+        if (params != null && mOrigWindowType != params.type) {
+            // For compatibility with old apps, don't crash here.
+            if (mTargetSdkVersion < android.os.Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
+                Slog.w(TAG, "Window type can not be changed after "
+                        + "the window is added; ignoring change of " + mView);
+                params.type = mOrigWindowType;
+            }
+        }
         int relayoutResult = sWindowSession.relayout(
                 mWindow, params,
                 (int) (mView.getMeasuredWidth() * appScale + 0.5f),
diff --git a/core/java/android/view/animation/Animation.java b/core/java/android/view/animation/Animation.java
index c1eec6f..0d57c9b 100644
--- a/core/java/android/view/animation/Animation.java
+++ b/core/java/android/view/animation/Animation.java
@@ -232,11 +232,6 @@
         setFillBefore(a.getBoolean(com.android.internal.R.styleable.Animation_fillBefore, mFillBefore));
         setFillAfter(a.getBoolean(com.android.internal.R.styleable.Animation_fillAfter, mFillAfter));
 
-        final int resID = a.getResourceId(com.android.internal.R.styleable.Animation_interpolator, 0);
-        if (resID > 0) {
-            setInterpolator(context, resID);
-        }
-
         setRepeatCount(a.getInt(com.android.internal.R.styleable.Animation_repeatCount, mRepeatCount));
         setRepeatMode(a.getInt(com.android.internal.R.styleable.Animation_repeatMode, RESTART));
 
@@ -245,10 +240,16 @@
         setBackgroundColor(a.getInt(com.android.internal.R.styleable.Animation_background, 0));
 
         setDetachWallpaper(a.getBoolean(com.android.internal.R.styleable.Animation_detachWallpaper, false));
-        
-        ensureInterpolator();
+
+        final int resID = a.getResourceId(com.android.internal.R.styleable.Animation_interpolator, 0);
 
         a.recycle();
+
+        if (resID > 0) {
+            setInterpolator(context, resID);
+        }
+
+        ensureInterpolator();
     }
 
     @Override
diff --git a/core/java/android/webkit/WebSettings.java b/core/java/android/webkit/WebSettings.java
index 77f6776..9c44138 100644
--- a/core/java/android/webkit/WebSettings.java
+++ b/core/java/android/webkit/WebSettings.java
@@ -643,10 +643,10 @@
 
     /**
      * Set whether the WebView will enable smooth transition while panning or
-     * zooming. If it is true, WebView will choose a solution to maximize the
-     * performance. e.g. the WebView's content may not be updated during the
-     * transition. If it is false, WebView will keep its fidelity. The default
-     * value is false.
+     * zooming or while the window hosting the WebView does not have focus.
+     * If it is true, WebView will choose a solution to maximize the performance.
+     * e.g. the WebView's content may not be updated during the transition.
+     * If it is false, WebView will keep its fidelity. The default value is false.
      */
     public void setEnableSmoothTransition(boolean enable) {
         mEnableSmoothTransition = enable;
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 47abbc2..065beb1 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -908,6 +908,9 @@
     // used for serializing asynchronously handled touch events.
     private final TouchEventQueue mTouchEventQueue = new TouchEventQueue();
 
+    // Used to track whether picture updating was paused due to a window focus change.
+    private boolean mPictureUpdatePausedForFocusChange = false;
+
     // Used to notify listeners of a new picture.
     private PictureListener mPictureListener;
     /**
@@ -5570,8 +5573,20 @@
         setActive(hasWindowFocus);
         if (hasWindowFocus) {
             JWebCoreJavaBridge.setActiveWebView(this);
+            if (mPictureUpdatePausedForFocusChange) {
+                WebViewCore.resumeUpdatePicture(mWebViewCore);
+                nativeSetIsScrolling(false);
+                mPictureUpdatePausedForFocusChange = false;
+            }
         } else {
             JWebCoreJavaBridge.removeActiveWebView(this);
+            final WebSettings settings = getSettings();
+            if (settings != null && settings.enableSmoothTransition() &&
+                    mWebViewCore != null && !WebViewCore.isUpdatePicturePaused(mWebViewCore)) {
+                WebViewCore.pauseUpdatePicture(mWebViewCore);
+                nativeSetIsScrolling(true);
+                mPictureUpdatePausedForFocusChange = true;
+            }
         }
         super.onWindowFocusChanged(hasWindowFocus);
     }
diff --git a/core/java/android/webkit/WebViewCore.java b/core/java/android/webkit/WebViewCore.java
index c61bd48..843a624 100644
--- a/core/java/android/webkit/WebViewCore.java
+++ b/core/java/android/webkit/WebViewCore.java
@@ -2107,6 +2107,10 @@
         }
     }
 
+    static boolean isUpdatePicturePaused(WebViewCore core) {
+        return core != null ? core.mDrawIsPaused : false;
+    }
+
     //////////////////////////////////////////////////////////////////////////
 
     private void restoreState(int index) {
diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java
index d7fb7a0..353d83c 100644
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -3774,6 +3774,10 @@
                 }
                 // Fall through
             case TOUCH_MODE_FLING: {
+                if (mDataChanged) {
+                    layoutChildren();
+                }
+
                 if (mItemCount == 0 || getChildCount() == 0) {
                     endFling();
                     return;
diff --git a/core/java/android/widget/AdapterView.java b/core/java/android/widget/AdapterView.java
index 2d10bbe..72db8e8 100644
--- a/core/java/android/widget/AdapterView.java
+++ b/core/java/android/widget/AdapterView.java
@@ -896,6 +896,7 @@
 
     @Override
     public void onPopulateAccessibilityEvent(AccessibilityEvent event) {
+        super.onPopulateAccessibilityEvent(event);
         // We send selection events only from AdapterView to avoid
         // generation of such event for each child.
         getSelectedView().dispatchPopulateAccessibilityEvent(event);
diff --git a/core/java/android/widget/CheckedTextView.java b/core/java/android/widget/CheckedTextView.java
index 7598e54..0a54743 100644
--- a/core/java/android/widget/CheckedTextView.java
+++ b/core/java/android/widget/CheckedTextView.java
@@ -26,6 +26,7 @@
 import android.view.Gravity;
 import android.view.ViewDebug;
 import android.view.accessibility.AccessibilityEvent;
+import android.view.accessibility.AccessibilityNodeInfo;
 
 
 /**
@@ -231,4 +232,10 @@
             event.getText().add(mContext.getString(R.string.radiobutton_not_selected));
         }
     }
+
+    @Override
+    public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
+        super.onInitializeAccessibilityNodeInfo(info);
+        info.setChecked(mChecked);
+    }
 }
diff --git a/core/java/android/widget/HorizontalScrollView.java b/core/java/android/widget/HorizontalScrollView.java
index a7a05be..9ce8fe0 100644
--- a/core/java/android/widget/HorizontalScrollView.java
+++ b/core/java/android/widget/HorizontalScrollView.java
@@ -16,14 +16,10 @@
 
 package android.widget;
 
-import com.android.internal.R;
-
 import android.content.Context;
-import android.content.res.Resources;
 import android.content.res.TypedArray;
 import android.graphics.Canvas;
 import android.graphics.Rect;
-import android.graphics.drawable.Drawable;
 import android.util.AttributeSet;
 import android.view.FocusFinder;
 import android.view.InputDevice;
@@ -569,16 +565,18 @@
                     final int oldX = mScrollX;
                     final int oldY = mScrollY;
                     final int range = getScrollRange();
-                    if (overScrollBy(deltaX, 0, mScrollX, 0, range, 0,
+                    final int overscrollMode = getOverScrollMode();
+                    final boolean canOverscroll = overscrollMode == OVER_SCROLL_ALWAYS ||
+                            (overscrollMode == OVER_SCROLL_IF_CONTENT_SCROLLS && range > 0);
+
+                    if (canOverscroll && overScrollBy(deltaX, 0, mScrollX, 0, range, 0,
                             mOverscrollDistance, 0, true)) {
                         // Break our velocity if we hit a scroll barrier.
                         mVelocityTracker.clear();
                     }
                     onScrollChanged(mScrollX, mScrollY, oldX, oldY);
 
-                    final int overscrollMode = getOverScrollMode();
-                    if (overscrollMode == OVER_SCROLL_ALWAYS ||
-                            (overscrollMode == OVER_SCROLL_IF_CONTENT_SCROLLS && range > 0)) {
+                    if (canOverscroll) {
                         final int pulledToX = oldX + deltaX;
                         if (pulledToX < 0) {
                             mEdgeGlowLeft.onPull((float) deltaX / getWidth());
@@ -604,11 +602,15 @@
                     velocityTracker.computeCurrentVelocity(1000, mMaximumVelocity);
                     int initialVelocity = (int) velocityTracker.getXVelocity(mActivePointerId);
 
-                    if (getChildCount() > 0) {
+                    final int right = getScrollRange();
+                    final int overscrollMode = getOverScrollMode();
+                    final boolean canOverscroll = overscrollMode == OVER_SCROLL_ALWAYS ||
+                            (overscrollMode == OVER_SCROLL_IF_CONTENT_SCROLLS && right > 0);
+
+                    if (getChildCount() > 0 && canOverscroll) {
                         if ((Math.abs(initialVelocity) > mMinimumVelocity)) {
                             fling(-initialVelocity);
                         } else {
-                            final int right = getScrollRange();
                             if (mScroller.springBack(mScrollX, mScrollY, 0, right, 0, 0)) {
                                 invalidate();
                             }
@@ -1187,14 +1189,16 @@
             int y = mScroller.getCurrY();
 
             if (oldX != x || oldY != y) {
-                overScrollBy(x - oldX, y - oldY, oldX, oldY, getScrollRange(), 0,
+                final int range = getScrollRange();
+                final int overscrollMode = getOverScrollMode();
+                final boolean canOverscroll = overscrollMode == OVER_SCROLL_ALWAYS ||
+                        (overscrollMode == OVER_SCROLL_IF_CONTENT_SCROLLS && range > 0);
+
+                overScrollBy(x - oldX, y - oldY, oldX, oldY, range, 0,
                         mOverflingDistance, 0, false);
                 onScrollChanged(mScrollX, mScrollY, oldX, oldY);
 
-                final int range = getScrollRange();
-                final int overscrollMode = getOverScrollMode();
-                if (overscrollMode == OVER_SCROLL_ALWAYS ||
-                        (overscrollMode == OVER_SCROLL_IF_CONTENT_SCROLLS && range > 0)) {
+                if (canOverscroll) {
                     if (x < 0 && oldX >= 0) {
                         mEdgeGlowLeft.onAbsorb((int) mScroller.getCurrVelocity());
                     } else if (x > range && oldX <= range) {
@@ -1202,6 +1206,7 @@
                     }
                 }
             }
+
             awakenScrollBars();
 
             // Keep on drawing until the animation has finished.
diff --git a/core/java/android/widget/ImageView.java b/core/java/android/widget/ImageView.java
index b92130d..a5d6c9a 100644
--- a/core/java/android/widget/ImageView.java
+++ b/core/java/android/widget/ImageView.java
@@ -212,6 +212,7 @@
 
     @Override
     public void onPopulateAccessibilityEvent(AccessibilityEvent event) {
+        super.onPopulateAccessibilityEvent(event);
         CharSequence contentDescription = getContentDescription();
         if (!TextUtils.isEmpty(contentDescription)) {
             event.getText().add(contentDescription);
diff --git a/core/java/android/widget/ListView.java b/core/java/android/widget/ListView.java
index 5a97317..e37ccf8 100644
--- a/core/java/android/widget/ListView.java
+++ b/core/java/android/widget/ListView.java
@@ -264,7 +264,7 @@
 
         // in the case of re-adding a header view, or adding one later on,
         // we need to notify the observer
-        if (mDataSetObserver != null) {
+        if (mAdapter != null && mDataSetObserver != null) {
             mDataSetObserver.onChanged();
         }
     }
@@ -299,7 +299,7 @@
     public boolean removeHeaderView(View v) {
         if (mHeaderViewInfos.size() > 0) {
             boolean result = false;
-            if (((HeaderViewListAdapter) mAdapter).removeHeader(v)) {
+            if (mAdapter != null && ((HeaderViewListAdapter) mAdapter).removeHeader(v)) {
                 if (mDataSetObserver != null) {
                     mDataSetObserver.onChanged();
                 }
@@ -350,7 +350,7 @@
 
         // in the case of re-adding a footer view, or adding one later on,
         // we need to notify the observer
-        if (mDataSetObserver != null) {
+        if (mAdapter != null && mDataSetObserver != null) {
             mDataSetObserver.onChanged();
         }
     }
@@ -384,7 +384,7 @@
     public boolean removeFooterView(View v) {
         if (mFooterViewInfos.size() > 0) {
             boolean result = false;
-            if (((HeaderViewListAdapter) mAdapter).removeFooter(v)) {
+            if (mAdapter != null && ((HeaderViewListAdapter) mAdapter).removeFooter(v)) {
                 if (mDataSetObserver != null) {
                     mDataSetObserver.onChanged();
                 }
diff --git a/core/java/android/widget/ScrollView.java b/core/java/android/widget/ScrollView.java
index 6a6bc23..d91eeb2 100644
--- a/core/java/android/widget/ScrollView.java
+++ b/core/java/android/widget/ScrollView.java
@@ -19,11 +19,9 @@
 import com.android.internal.R;
 
 import android.content.Context;
-import android.content.res.Resources;
 import android.content.res.TypedArray;
 import android.graphics.Canvas;
 import android.graphics.Rect;
-import android.graphics.drawable.Drawable;
 import android.os.StrictMode;
 import android.util.AttributeSet;
 import android.view.FocusFinder;
@@ -581,16 +579,18 @@
                     final int oldX = mScrollX;
                     final int oldY = mScrollY;
                     final int range = getScrollRange();
-                    if (overScrollBy(0, deltaY, 0, mScrollY, 0, range,
-                            0, mOverscrollDistance, true)) {
+                    final int overscrollMode = getOverScrollMode();
+                    final boolean canOverscroll = overscrollMode == OVER_SCROLL_ALWAYS ||
+                            (overscrollMode == OVER_SCROLL_IF_CONTENT_SCROLLS && range > 0);
+
+                    if (canOverscroll && overScrollBy(0, deltaY, 0, mScrollY,
+                            0, range, 0, mOverscrollDistance, true)) {
                         // Break our velocity if we hit a scroll barrier.
                         mVelocityTracker.clear();
                     }
                     onScrollChanged(mScrollX, mScrollY, oldX, oldY);
 
-                    final int overscrollMode = getOverScrollMode();
-                    if (overscrollMode == OVER_SCROLL_ALWAYS ||
-                            (overscrollMode == OVER_SCROLL_IF_CONTENT_SCROLLS && range > 0)) {
+                    if (canOverscroll) {
                         final int pulledToY = oldY + deltaY;
                         if (pulledToY < 0) {
                             mEdgeGlowTop.onPull((float) deltaY / getHeight());
@@ -616,11 +616,15 @@
                     velocityTracker.computeCurrentVelocity(1000, mMaximumVelocity);
                     int initialVelocity = (int) velocityTracker.getYVelocity(mActivePointerId);
 
-                    if (getChildCount() > 0) {
+                    final int bottom = getScrollRange();
+                    final int overscrollMode = getOverScrollMode();
+                    final boolean canOverscroll = overscrollMode == OVER_SCROLL_ALWAYS ||
+                            (overscrollMode == OVER_SCROLL_IF_CONTENT_SCROLLS && bottom > 0);
+
+                    if (getChildCount() > 0 && canOverscroll) {
                         if ((Math.abs(initialVelocity) > mMinimumVelocity)) {
                             fling(-initialVelocity);
                         } else {
-                            final int bottom = getScrollRange();
                             if (mScroller.springBack(mScrollX, mScrollY, 0, 0, 0, bottom)) {
                                 invalidate();
                             }
@@ -1193,14 +1197,16 @@
             int y = mScroller.getCurrY();
 
             if (oldX != x || oldY != y) {
-                overScrollBy(x - oldX, y - oldY, oldX, oldY, 0, getScrollRange(),
+                final int range = getScrollRange();
+                final int overscrollMode = getOverScrollMode();
+                final boolean canOverscroll = overscrollMode == OVER_SCROLL_ALWAYS ||
+                        (overscrollMode == OVER_SCROLL_IF_CONTENT_SCROLLS && range > 0);
+
+                overScrollBy(x - oldX, y - oldY, oldX, oldY, 0, range,
                         0, mOverflingDistance, false);
                 onScrollChanged(mScrollX, mScrollY, oldX, oldY);
 
-                final int range = getScrollRange();
-                final int overscrollMode = getOverScrollMode();
-                if (overscrollMode == OVER_SCROLL_ALWAYS ||
-                        (overscrollMode == OVER_SCROLL_IF_CONTENT_SCROLLS && range > 0)) {
+                if (canOverscroll) {
                     if (y < 0 && oldY >= 0) {
                         mEdgeGlowTop.onAbsorb((int) mScroller.getCurrVelocity());
                     } else if (y > range && oldY <= range) {
@@ -1208,6 +1214,7 @@
                     }
                 }
             }
+
             awakenScrollBars();
 
             // Keep on drawing until the animation has finished.
diff --git a/core/java/android/widget/TabWidget.java b/core/java/android/widget/TabWidget.java
index 191c4ca..80bfe99 100644
--- a/core/java/android/widget/TabWidget.java
+++ b/core/java/android/widget/TabWidget.java
@@ -489,6 +489,7 @@
     public void sendAccessibilityEventUnchecked(AccessibilityEvent event) {
         // this class fires events only when tabs are focused or selected
         if (event.getEventType() == AccessibilityEvent.TYPE_VIEW_FOCUSED && isFocused()) {
+            event.recycle();
             return;
         }
         super.sendAccessibilityEventUnchecked(event);
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 40d85d8..ecd99b2 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -461,10 +461,6 @@
         mMovement = getDefaultMovementMethod();
         mTransformation = null;
 
-        TypedArray a =
-            context.obtainStyledAttributes(
-                attrs, com.android.internal.R.styleable.TextView, defStyle, 0);
-
         int textColorHighlight = 0;
         ColorStateList textColor = null;
         ColorStateList textColorHint = null;
@@ -474,18 +470,23 @@
         int styleIndex = -1;
         boolean allCaps = false;
 
+        final Resources.Theme theme = context.getTheme();
+
         /*
          * Look the appearance up without checking first if it exists because
          * almost every TextView has one and it greatly simplifies the logic
          * to be able to parse the appearance first and then let specific tags
          * for this View override it.
          */
+        TypedArray a = theme.obtainStyledAttributes(
+                    attrs, com.android.internal.R.styleable.TextViewAppearance, defStyle, 0);
         TypedArray appearance = null;
-        int ap = a.getResourceId(com.android.internal.R.styleable.TextView_textAppearance, -1);
+        int ap = a.getResourceId(
+                com.android.internal.R.styleable.TextViewAppearance_textAppearance, -1);
+        a.recycle();
         if (ap != -1) {
-            appearance = context.obtainStyledAttributes(ap,
-                                com.android.internal.R.styleable.
-                                TextAppearance);
+            appearance = theme.obtainStyledAttributes(
+                    ap, com.android.internal.R.styleable.TextAppearance);
         }
         if (appearance != null) {
             int n = appearance.getIndexCount();
@@ -552,6 +553,9 @@
         boolean password = false;
         int inputType = EditorInfo.TYPE_NULL;
 
+        a = theme.obtainStyledAttributes(
+                    attrs, com.android.internal.R.styleable.TextView, defStyle, 0);
+
         int n = a.getIndexCount();
         for (int i = 0; i < n; i++) {
             int attr = a.getIndex(i);
@@ -9556,6 +9560,9 @@
         private int mNumberOfSuggestions;
         private boolean mCursorWasVisibleBeforeSuggestions;
         private SuggestionAdapter mSuggestionsAdapter;
+        private final Comparator<SuggestionSpan> mSuggestionSpanComparator;
+        private final HashMap<SuggestionSpan, Integer> mSpansLengths;
+
 
         private class CustomPopupWindow extends PopupWindow {
             public CustomPopupWindow(Context context, int defStyle) {
@@ -9581,6 +9588,8 @@
 
         public SuggestionsPopupWindow() {
             mCursorWasVisibleBeforeSuggestions = mCursorVisible;
+            mSuggestionSpanComparator = new SuggestionSpanComparator();
+            mSpansLengths = new HashMap<SuggestionSpan, Integer>();
         }
 
         @Override
@@ -9659,6 +9668,26 @@
             }
         }
 
+        private class SuggestionSpanComparator implements Comparator<SuggestionSpan> {
+            public int compare(SuggestionSpan span1, SuggestionSpan span2) {
+                final int flag1 = span1.getFlags();
+                final int flag2 = span2.getFlags();
+                if (flag1 != flag2) {
+                    // The order here should match what is used in updateDrawState
+                    final boolean easy1 = (flag1 & SuggestionSpan.FLAG_EASY_CORRECT) != 0;
+                    final boolean easy2 = (flag2 & SuggestionSpan.FLAG_EASY_CORRECT) != 0;
+                    final boolean misspelled1 = (flag1 & SuggestionSpan.FLAG_MISSPELLED) != 0;
+                    final boolean misspelled2 = (flag2 & SuggestionSpan.FLAG_MISSPELLED) != 0;
+                    if (easy1 && !misspelled1) return -1;
+                    if (easy2 && !misspelled2) return 1;
+                    if (misspelled1) return -1;
+                    if (misspelled2) return 1;
+                }
+
+                return mSpansLengths.get(span1).intValue() - mSpansLengths.get(span2).intValue();
+            }
+        }
+
         /**
          * Returns the suggestion spans that cover the current cursor position. The suggestion
          * spans are sorted according to the length of text that they are attached to.
@@ -9668,24 +9697,16 @@
             Spannable spannable = (Spannable) TextView.this.mText;
             SuggestionSpan[] suggestionSpans = spannable.getSpans(pos, pos, SuggestionSpan.class);
 
-            // Cache the span length for performance reason.
-            final HashMap<SuggestionSpan, Integer> spansLengths =
-                    new HashMap<SuggestionSpan, Integer>();
-
+            mSpansLengths.clear();
             for (SuggestionSpan suggestionSpan : suggestionSpans) {
                 int start = spannable.getSpanStart(suggestionSpan);
                 int end = spannable.getSpanEnd(suggestionSpan);
-                spansLengths.put(suggestionSpan, Integer.valueOf(end - start));
+                mSpansLengths.put(suggestionSpan, Integer.valueOf(end - start));
             }
 
-            // The suggestions are sorted according to the lenght of the text that they cover
-            // (shorter first)
-            Arrays.sort(suggestionSpans, new Comparator<SuggestionSpan>() {
-                public int compare(SuggestionSpan span1, SuggestionSpan span2) {
-                    return spansLengths.get(span1).intValue() - spansLengths.get(span2).intValue();
-                }
-            });
-
+            // The suggestions are sorted according to their types (easy correction first, then
+            // misspelled) and to the length of the text that they cover (shorter first).
+            Arrays.sort(suggestionSpans, mSuggestionSpanComparator);
             return suggestionSpans;
         }
 
diff --git a/core/java/com/android/internal/view/menu/ListMenuPresenter.java b/core/java/com/android/internal/view/menu/ListMenuPresenter.java
index e6538b0..0141427 100644
--- a/core/java/com/android/internal/view/menu/ListMenuPresenter.java
+++ b/core/java/com/android/internal/view/menu/ListMenuPresenter.java
@@ -62,6 +62,7 @@
     public ListMenuPresenter(Context context, int itemLayoutRes) {
         this(itemLayoutRes, 0);
         mContext = context;
+        mInflater = LayoutInflater.from(mContext);
     }
 
     /**
@@ -78,10 +79,13 @@
     public void initForMenu(Context context, MenuBuilder menu) {
         if (mThemeRes != 0) {
             mContext = new ContextThemeWrapper(context, mThemeRes);
+            mInflater = LayoutInflater.from(mContext);
         } else if (mContext != null) {
             mContext = context;
+            if (mInflater == null) {
+                mInflater = LayoutInflater.from(mContext);
+            }
         }
-        mInflater = LayoutInflater.from(mContext);
         mMenu = menu;
     }
 
diff --git a/core/java/com/android/internal/widget/ActionBarView.java b/core/java/com/android/internal/widget/ActionBarView.java
index 7434df3a..bbecb6c 100644
--- a/core/java/com/android/internal/widget/ActionBarView.java
+++ b/core/java/com/android/internal/widget/ActionBarView.java
@@ -268,8 +268,10 @@
 
         if (mTabScrollView != null && mIncludeTabs) {
             ViewGroup.LayoutParams lp = mTabScrollView.getLayoutParams();
-            lp.width = LayoutParams.WRAP_CONTENT;
-            lp.height = LayoutParams.MATCH_PARENT;
+            if (lp != null) {
+                lp.width = LayoutParams.WRAP_CONTENT;
+                lp.height = LayoutParams.MATCH_PARENT;
+            }
             mTabScrollView.setAllowCollapse(true);
         }
     }
diff --git a/core/jni/android_server_BluetoothEventLoop.cpp b/core/jni/android_server_BluetoothEventLoop.cpp
index 0335ce7..e8933fe 100644
--- a/core/jni/android_server_BluetoothEventLoop.cpp
+++ b/core/jni/android_server_BluetoothEventLoop.cpp
@@ -1562,8 +1562,8 @@
         LOG_AND_FREE_DBUS_ERROR(&err);
     }
 
-    LOGV("... Health Device Code = %d, result = %d", code, result);
     jint code = *(int *) user;
+    LOGV("... Health Device Code = %d, result = %d", code, result);
     env->CallVoidMethod(nat->me,
                         method_onHealthDeviceConnectionResult,
                         code,
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 72863a2..9f2eef5 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -18,7 +18,7 @@
 */
 -->
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="android" android:sharedUserId="android.uid.system"
+    package="android" coreApp="true" android:sharedUserId="android.uid.system"
     android:sharedUserLabel="@string/android_system_label">
 
     <!-- ================================================ -->
diff --git a/core/res/res/drawable-hdpi/sym_def_app_icon.png b/core/res/res/drawable-hdpi/sym_def_app_icon.png
index 075d908..c8a38ed 100644
--- a/core/res/res/drawable-hdpi/sym_def_app_icon.png
+++ b/core/res/res/drawable-hdpi/sym_def_app_icon.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/sym_def_app_icon.png b/core/res/res/drawable-mdpi/sym_def_app_icon.png
index 9777d11..b3e10f6 100644
--- a/core/res/res/drawable-mdpi/sym_def_app_icon.png
+++ b/core/res/res/drawable-mdpi/sym_def_app_icon.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/sym_def_app_icon.png b/core/res/res/drawable-xhdpi/sym_def_app_icon.png
index f360399..f381f86 100644
--- a/core/res/res/drawable-xhdpi/sym_def_app_icon.png
+++ b/core/res/res/drawable-xhdpi/sym_def_app_icon.png
Binary files differ
diff --git a/core/res/res/layout/list_menu_item_layout.xml b/core/res/res/layout/list_menu_item_layout.xml
index 93bd76b..680eca7 100644
--- a/core/res/res/layout/list_menu_item_layout.xml
+++ b/core/res/res/layout/list_menu_item_layout.xml
@@ -26,8 +26,8 @@
         android:layout_weight="1"
         android:layout_height="wrap_content"
         android:layout_gravity="center_vertical"
-        android:layout_marginLeft="16dip"
-        android:layout_marginRight="16dip"
+        android:layout_marginLeft="?android:attr/listPreferredItemPaddingLeft"
+        android:layout_marginRight="?android:attr/listPreferredItemPaddingRight"
         android:duplicateParentState="true">
         
         <TextView 
diff --git a/core/res/res/mipmap-hdpi/sym_def_app_icon.png b/core/res/res/mipmap-hdpi/sym_def_app_icon.png
index 075d908..c8a38ed 100644
--- a/core/res/res/mipmap-hdpi/sym_def_app_icon.png
+++ b/core/res/res/mipmap-hdpi/sym_def_app_icon.png
Binary files differ
diff --git a/core/res/res/mipmap-mdpi/sym_def_app_icon.png b/core/res/res/mipmap-mdpi/sym_def_app_icon.png
index 9777d11..b3e10f6 100644
--- a/core/res/res/mipmap-mdpi/sym_def_app_icon.png
+++ b/core/res/res/mipmap-mdpi/sym_def_app_icon.png
Binary files differ
diff --git a/core/res/res/mipmap-xhdpi/sym_def_app_icon.png b/core/res/res/mipmap-xhdpi/sym_def_app_icon.png
new file mode 100644
index 0000000..f381f86
--- /dev/null
+++ b/core/res/res/mipmap-xhdpi/sym_def_app_icon.png
Binary files differ
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index fc84f53..c990125 100755
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -3177,6 +3177,10 @@
         <!-- Present the text in ALL CAPS. This may use a small-caps form when available. -->
         <attr name="textAllCaps" />
     </declare-styleable>
+    <declare-styleable name="TextViewAppearance">
+        <!-- Base text color, typeface, size, and style. -->
+        <attr name="textAppearance" />
+    </declare-styleable>
     <declare-styleable name="SuggestionSpan">
         <attr name="textUnderlineColor" />
         <attr name="textUnderlineThickness" />
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 051ed14..8fd2cd1 100755
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -385,6 +385,9 @@
     <!-- Default value for LED on time when the battery is low on charge in miliseconds -->
     <integer name="config_notificationsBatteryLedOn">125</integer>
 
+    <!-- Is the notification LED intrusive? Used to decide if there should be a disable option -->
+    <bool name="config_intrusiveNotificationLed">false</bool>
+
     <!-- Default value for LED off time when the battery is low on charge in miliseconds -->
     <integer name="config_notificationsBatteryLedOff">2875</integer>
 
diff --git a/core/res/res/values/themes.xml b/core/res/res/values/themes.xml
index c8f7fb8..3378dc8 100644
--- a/core/res/res/values/themes.xml
+++ b/core/res/res/values/themes.xml
@@ -616,6 +616,9 @@
         <item name="textAppearanceLargeInverse">@android:style/TextAppearance.Large.Inverse</item>
         <item name="textAppearanceMediumInverse">@android:style/TextAppearance.Medium.Inverse</item>
         <item name="textAppearanceSmallInverse">@android:style/TextAppearance.Small.Inverse</item>
+
+        <item name="listPreferredItemPaddingLeft">10dip</item>
+        <item name="listPreferredItemPaddingRight">10dip</item>
     </style>
 
     <!-- Variation of Theme.Dialog that does not include a frame (or background).
@@ -640,6 +643,8 @@
         <item name="windowTitleStyle">@android:style/DialogWindowTitle</item>
         <item name="windowContentOverlay">@null</item>
         <item name="itemTextAppearance">@android:style/TextAppearance.Large.Inverse</item>
+        <item name="textAppearanceListItem">@android:style/TextAppearance.Large.Inverse</item>
+        <item name="textAppearanceListItemSmall">@android:style/TextAppearance.Large.Inverse</item>
     </style>
     
     <!-- Default dark theme for panel windows.  This removes all extraneous
diff --git a/core/tests/coretests/src/android/net/NetworkStatsHistoryTest.java b/core/tests/coretests/src/android/net/NetworkStatsHistoryTest.java
index b888d9a..e1db073 100644
--- a/core/tests/coretests/src/android/net/NetworkStatsHistoryTest.java
+++ b/core/tests/coretests/src/android/net/NetworkStatsHistoryTest.java
@@ -407,6 +407,54 @@
         assertEquals(Long.MAX_VALUE - 40, performVarLong(Long.MAX_VALUE - 40));
     }
 
+    public void testIndexBeforeAfter() throws Exception {
+        final long BUCKET_SIZE = HOUR_IN_MILLIS;
+        stats = new NetworkStatsHistory(BUCKET_SIZE);
+
+        final long FIRST_START = TEST_START;
+        final long FIRST_END = FIRST_START + (2 * HOUR_IN_MILLIS);
+        final long SECOND_START = TEST_START + WEEK_IN_MILLIS;
+        final long SECOND_END = SECOND_START + HOUR_IN_MILLIS;
+        final long THIRD_START = TEST_START + (2 * WEEK_IN_MILLIS);
+        final long THIRD_END = THIRD_START + (2 * HOUR_IN_MILLIS);
+
+        stats.recordData(FIRST_START, FIRST_END,
+                new NetworkStats.Entry(1024L, 10L, 2048L, 20L, 2L));
+        stats.recordData(SECOND_START, SECOND_END,
+                new NetworkStats.Entry(1024L, 10L, 2048L, 20L, 2L));
+        stats.recordData(THIRD_START, THIRD_END,
+                new NetworkStats.Entry(1024L, 10L, 2048L, 20L, 2L));
+
+        // should have buckets: 2+1+2
+        assertEquals(5, stats.size());
+
+        assertIndexBeforeAfter(stats, 0, 0, Long.MIN_VALUE);
+        assertIndexBeforeAfter(stats, 0, 1, FIRST_START);
+        assertIndexBeforeAfter(stats, 0, 1, FIRST_START + MINUTE_IN_MILLIS);
+        assertIndexBeforeAfter(stats, 0, 2, FIRST_START + HOUR_IN_MILLIS);
+        assertIndexBeforeAfter(stats, 1, 2, FIRST_START + HOUR_IN_MILLIS + MINUTE_IN_MILLIS);
+        assertIndexBeforeAfter(stats, 1, 2, FIRST_END - MINUTE_IN_MILLIS);
+        assertIndexBeforeAfter(stats, 1, 2, FIRST_END);
+        assertIndexBeforeAfter(stats, 1, 2, FIRST_END + MINUTE_IN_MILLIS);
+        assertIndexBeforeAfter(stats, 1, 2, SECOND_START - MINUTE_IN_MILLIS);
+        assertIndexBeforeAfter(stats, 1, 3, SECOND_START);
+        assertIndexBeforeAfter(stats, 2, 3, SECOND_END);
+        assertIndexBeforeAfter(stats, 2, 3, SECOND_END + MINUTE_IN_MILLIS);
+        assertIndexBeforeAfter(stats, 2, 3, THIRD_START - MINUTE_IN_MILLIS);
+        assertIndexBeforeAfter(stats, 2, 4, THIRD_START);
+        assertIndexBeforeAfter(stats, 3, 4, THIRD_START + MINUTE_IN_MILLIS);
+        assertIndexBeforeAfter(stats, 3, 4, THIRD_START + HOUR_IN_MILLIS);
+        assertIndexBeforeAfter(stats, 4, 4, THIRD_END);
+        assertIndexBeforeAfter(stats, 4, 4, THIRD_END + MINUTE_IN_MILLIS);
+        assertIndexBeforeAfter(stats, 4, 4, Long.MAX_VALUE);
+    }
+
+    private static void assertIndexBeforeAfter(
+            NetworkStatsHistory stats, int before, int after, long time) {
+        assertEquals("unexpected before", before, stats.getIndexBefore(time));
+        assertEquals("unexpected after", after, stats.getIndexAfter(time));
+    }
+
     private static long performVarLong(long before) throws Exception {
         final ByteArrayOutputStream out = new ByteArrayOutputStream();
         writeVarLong(new DataOutputStream(out), before);
diff --git a/docs/html/guide/topics/manifest/provider-element.jd b/docs/html/guide/topics/manifest/provider-element.jd
index dd00224..4558800 100644
--- a/docs/html/guide/topics/manifest/provider-element.jd
+++ b/docs/html/guide/topics/manifest/provider-element.jd
@@ -27,7 +27,8 @@
 
 <dt>can contain:</dt>
 <dd><code><a href="{@docRoot}guide/topics/manifest/meta-data-element.html">&lt;meta-data&gt;</a></code>
-<br/><code><a href="{@docRoot}guide/topics/manifest/grant-uri-permission-element.html">&lt;grant-uri-permission&gt;</a></code></dd>
+<br/><code><a href="{@docRoot}guide/topics/manifest/grant-uri-permission-element.html">&lt;grant-uri-permission&gt;</a></code>
+<br/><code><a href="{@docRoot}guide/topics/manifest/path-permission-element.html">&lt;path-permission&gt;</a></code></dd>
 
 <dt>description:</dt>
 <dd>Declares a content provider &mdash; a subclass of 
@@ -252,7 +253,7 @@
 <dt><a name="sync"></a>{@code android:syncable}</dt>
 <dd>Whether or not the data under the content provider's control 
 is to be synchronized with data on a server &mdash; "{@code true}" 
-if it is to be synchronized, and "{@ code false}" if not.</dd>
+if it is to be synchronized, and "{@code false}" if not.</dd>
 
 <dt><a name="wprmsn"></a>{@code android:writePermission}</dt>
 <dd>A permission that clients must have to make changes to the data 
diff --git a/graphics/java/android/graphics/drawable/AnimatedRotateDrawable.java b/graphics/java/android/graphics/drawable/AnimatedRotateDrawable.java
index 7c4e147..34f9070 100644
--- a/graphics/java/android/graphics/drawable/AnimatedRotateDrawable.java
+++ b/graphics/java/android/graphics/drawable/AnimatedRotateDrawable.java
@@ -79,7 +79,7 @@
         float px = st.mPivotXRel ? (w * st.mPivotX) : st.mPivotX;
         float py = st.mPivotYRel ? (h * st.mPivotY) : st.mPivotY;
 
-        canvas.rotate(mCurrentDegrees, px, py);
+        canvas.rotate(mCurrentDegrees, px + bounds.left, py + bounds.top);
 
         drawable.draw(canvas);
 
diff --git a/media/java/android/media/Metadata.java b/media/java/android/media/Metadata.java
index 591a8b9..b566653 100644
--- a/media/java/android/media/Metadata.java
+++ b/media/java/android/media/Metadata.java
@@ -39,6 +39,8 @@
 
    The caller is expected to know the type of the metadata and call
    the right get* method to fetch its value.
+   
+   @hide
  */
 public class Metadata
 {
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
index 8f213da..bf83849 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
@@ -26,6 +26,9 @@
 
 namespace android {
 
+// static
+const int64_t NuPlayer::Renderer::kMinPositionUpdateDelayUs = 100000ll;
+
 NuPlayer::Renderer::Renderer(
         const sp<MediaPlayerBase::AudioSink> &sink,
         const sp<AMessage> &notify)
@@ -43,7 +46,8 @@
       mHasAudio(false),
       mHasVideo(false),
       mSyncQueues(false),
-      mPaused(false) {
+      mPaused(false),
+      mLastPositionUpdateUs(-1ll) {
 }
 
 NuPlayer::Renderer::~Renderer() {
@@ -190,7 +194,7 @@
     mDrainAudioQueuePending = true;
     sp<AMessage> msg = new AMessage(kWhatDrainAudioQueue, id());
     msg->setInt32("generation", mAudioQueueGeneration);
-    msg->post(10000);
+    msg->post();
 }
 
 void NuPlayer::Renderer::signalAudioSinkChanged() {
@@ -198,7 +202,6 @@
 }
 
 void NuPlayer::Renderer::onDrainAudioQueue() {
-
     for (;;) {
         if (mAudioQueue.empty()) {
             break;
@@ -562,6 +565,13 @@
     }
 
     int64_t nowUs = ALooper::GetNowUs();
+
+    if (mLastPositionUpdateUs >= 0
+            && nowUs < mLastPositionUpdateUs + kMinPositionUpdateDelayUs) {
+        return;
+    }
+    mLastPositionUpdateUs = nowUs;
+
     int64_t positionUs = (nowUs - mAnchorTimeRealUs) + mAnchorTimeMediaUs;
 
     sp<AMessage> notify = mNotify->dup();
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h
index 2713031..3a641a2 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h
@@ -74,6 +74,8 @@
         status_t mFinalResult;
     };
 
+    static const int64_t kMinPositionUpdateDelayUs;
+
     sp<MediaPlayerBase::AudioSink> mAudioSink;
     sp<AMessage> mNotify;
     List<QueueEntry> mAudioQueue;
@@ -98,6 +100,8 @@
 
     bool mPaused;
 
+    int64_t mLastPositionUpdateUs;
+
     void onDrainAudioQueue();
     void postDrainAudioQueue();
 
diff --git a/media/libstagefright/AVIExtractor.cpp b/media/libstagefright/AVIExtractor.cpp
index 62d17da..4e46414 100644
--- a/media/libstagefright/AVIExtractor.cpp
+++ b/media/libstagefright/AVIExtractor.cpp
@@ -117,14 +117,12 @@
         }
     }
 
-    int64_t timeUs =
-        (mSampleIndex * 1000000ll * mTrack.mRate) / mTrack.mScale;
-
     off64_t offset;
     size_t size;
     bool isKey;
+    int64_t timeUs;
     status_t err = mExtractor->getSampleInfo(
-            mTrackIndex, mSampleIndex, &offset, &size, &isKey);
+            mTrackIndex, mSampleIndex, &offset, &size, &isKey, &timeUs);
 
     ++mSampleIndex;
 
@@ -396,6 +394,8 @@
     uint32_t rate = U32LE_AT(&data[20]);
     uint32_t scale = U32LE_AT(&data[24]);
 
+    uint32_t sampleSize = U32LE_AT(&data[44]);
+
     const char *mime = NULL;
     Track::Kind kind = Track::OTHER;
 
@@ -427,6 +427,7 @@
     track->mMeta = meta;
     track->mRate = rate;
     track->mScale = scale;
+    track->mBytesPerSample = sampleSize;
     track->mKind = kind;
     track->mNumSyncSamples = 0;
     track->mThumbnailSampleSize = 0;
@@ -612,11 +613,12 @@
         off64_t offset;
         size_t size;
         bool isKey;
-        status_t err = getSampleInfo(0, 0, &offset, &size, &isKey);
+        int64_t timeUs;
+        status_t err = getSampleInfo(0, 0, &offset, &size, &isKey, &timeUs);
 
         if (err != OK) {
             mOffsetsAreAbsolute = !mOffsetsAreAbsolute;
-            err = getSampleInfo(0, 0, &offset, &size, &isKey);
+            err = getSampleInfo(0, 0, &offset, &size, &isKey, &timeUs);
 
             if (err != OK) {
                 return err;
@@ -630,8 +632,9 @@
     for (size_t i = 0; i < mTracks.size(); ++i) {
         Track *track = &mTracks.editItemAt(i);
 
-        int64_t durationUs =
-            (track->mSamples.size() * 1000000ll * track->mRate) / track->mScale;
+        int64_t durationUs;
+        CHECK_EQ((status_t)OK,
+                 getSampleTime(i, track->mSamples.size() - 1, &durationUs));
 
         LOGV("track %d duration = %.2f secs", i, durationUs / 1E6);
 
@@ -645,9 +648,10 @@
 
         if (!strncasecmp("video/", mime.c_str(), 6)
                 && track->mThumbnailSampleIndex >= 0) {
-            int64_t thumbnailTimeUs =
-                (track->mThumbnailSampleIndex * 1000000ll * track->mRate)
-                    / track->mScale;
+            int64_t thumbnailTimeUs;
+            CHECK_EQ((status_t)OK,
+                     getSampleTime(i, track->mThumbnailSampleIndex,
+                                   &thumbnailTimeUs));
 
             track->mMeta->setInt64(kKeyThumbnailTime, thumbnailTimeUs);
 
@@ -659,6 +663,21 @@
                 }
             }
         }
+
+        if (track->mBytesPerSample != 0) {
+            // Assume all chunks are the same size for now.
+
+            off64_t offset;
+            size_t size;
+            bool isKey;
+            int64_t sampleTimeUs;
+            CHECK_EQ((status_t)OK,
+                     getSampleInfo(
+                         i, 0,
+                         &offset, &size, &isKey, &sampleTimeUs));
+
+            track->mRate *= size / track->mBytesPerSample;
+        }
     }
 
     mFoundIndex = true;
@@ -720,7 +739,9 @@
     off64_t offset;
     size_t size;
     bool isKey;
-    status_t err = getSampleInfo(trackIndex, 0, &offset, &size, &isKey);
+    int64_t timeUs;
+    status_t err =
+        getSampleInfo(trackIndex, 0, &offset, &size, &isKey, &timeUs);
 
     if (err != OK) {
         return err;
@@ -762,7 +783,8 @@
 
 status_t AVIExtractor::getSampleInfo(
         size_t trackIndex, size_t sampleIndex,
-        off64_t *offset, size_t *size, bool *isKey) {
+        off64_t *offset, size_t *size, bool *isKey,
+        int64_t *sampleTimeUs) {
     if (trackIndex >= mTracks.size()) {
         return -ERANGE;
     }
@@ -801,9 +823,20 @@
 
     *isKey = info.mIsKey;
 
+    *sampleTimeUs = (sampleIndex * 1000000ll * track.mRate) / track.mScale;
+
     return OK;
 }
 
+status_t AVIExtractor::getSampleTime(
+        size_t trackIndex, size_t sampleIndex, int64_t *sampleTimeUs) {
+    off64_t offset;
+    size_t size;
+    bool isKey;
+    return getSampleInfo(
+            trackIndex, sampleIndex, &offset, &size, &isKey, sampleTimeUs);
+}
+
 status_t AVIExtractor::getSampleIndexAtTime(
         size_t trackIndex,
         int64_t timeUs, MediaSource::ReadOptions::SeekMode mode,
diff --git a/media/libstagefright/include/AVIExtractor.h b/media/libstagefright/include/AVIExtractor.h
index 375a94d..b575347 100644
--- a/media/libstagefright/include/AVIExtractor.h
+++ b/media/libstagefright/include/AVIExtractor.h
@@ -54,6 +54,11 @@
         uint32_t mRate;
         uint32_t mScale;
 
+        // If bytes per sample == 0, each chunk represents a single sample,
+        // otherwise each chunk should me a multiple of bytes-per-sample in
+        // size.
+        uint32_t mBytesPerSample;
+
         enum Kind {
             AUDIO,
             VIDEO,
@@ -84,7 +89,11 @@
 
     status_t getSampleInfo(
             size_t trackIndex, size_t sampleIndex,
-            off64_t *offset, size_t *size, bool *isKey);
+            off64_t *offset, size_t *size, bool *isKey,
+            int64_t *sampleTimeUs);
+
+    status_t getSampleTime(
+            size_t trackIndex, size_t sampleIndex, int64_t *sampleTimeUs);
 
     status_t getSampleIndexAtTime(
             size_t trackIndex,
diff --git a/packages/DefaultContainerService/AndroidManifest.xml b/packages/DefaultContainerService/AndroidManifest.xml
index 0f47482..319eb8d 100755
--- a/packages/DefaultContainerService/AndroidManifest.xml
+++ b/packages/DefaultContainerService/AndroidManifest.xml
@@ -1,5 +1,5 @@
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-        package="com.android.defcontainer">
+        package="com.android.defcontainer" coreApp="true">
     <uses-permission android:name="android.permission.ACCESS_DOWNLOAD_MANAGER"/>
     <uses-permission android:name="android.permission.ACCESS_ALL_DOWNLOADS"/>
     <uses-permission android:name="android.permission.ASEC_ACCESS"/>
diff --git a/packages/SettingsProvider/AndroidManifest.xml b/packages/SettingsProvider/AndroidManifest.xml
index dd0d064..0719426 100644
--- a/packages/SettingsProvider/AndroidManifest.xml
+++ b/packages/SettingsProvider/AndroidManifest.xml
@@ -1,5 +1,6 @@
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
         package="com.android.providers.settings"
+        coreApp="true"
         android:sharedUserId="android.uid.system">
 
     <application android:allowClearUserData="false"
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index d10911f..a2452c4 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -1,5 +1,6 @@
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
         package="com.android.systemui"
+        coreApp="true"
         android:sharedUserId="android.uid.system"
         android:process="system"
         >
diff --git a/packages/SystemUI/res/drawable/notification_list_shadow.xml b/packages/SystemUI/res/drawable/notification_list_shadow.xml
new file mode 100644
index 0000000..7f33153
--- /dev/null
+++ b/packages/SystemUI/res/drawable/notification_list_shadow.xml
@@ -0,0 +1,26 @@
+<?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.
+-->
+
+<shape
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    >
+    <gradient
+        android:angle="90"
+        android:endColor="@color/notification_list_shadow_top"
+        android:startColor="#00000000"
+        android:type="linear"
+        />
+</shape>
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 eae3e52..167d362 100644
--- a/packages/SystemUI/res/layout-land/status_bar_recent_item.xml
+++ b/packages/SystemUI/res/layout-land/status_bar_recent_item.xml
@@ -42,6 +42,7 @@
             <ImageView android:id="@+id/app_thumbnail_image"
                 android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
+                android:visibility="invisible"
             />
         </FrameLayout>
 
@@ -71,6 +72,7 @@
             android:singleLine="true"
             android:ellipsize="marquee"
             android:visibility="invisible"
+            android:textColor="@color/status_bar_recents_app_label_color"
         />
 
         <TextView android:id="@+id/app_description"
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 b14ef595..de80a51 100644
--- a/packages/SystemUI/res/layout-port/status_bar_recent_item.xml
+++ b/packages/SystemUI/res/layout-port/status_bar_recent_item.xml
@@ -40,6 +40,7 @@
             <ImageView android:id="@+id/app_thumbnail_image"
                 android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
+                android:visibility="invisible"
             />
         </FrameLayout>
 
@@ -67,6 +68,7 @@
             android:layout_marginLeft="@dimen/status_bar_recents_app_label_left_margin"
             android:singleLine="true"
             android:ellipsize="marquee"
+            android:textColor="@color/status_bar_recents_app_label_color"
         />
 
         <View android:id="@+id/recents_callout_line"
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 f4be651..07088d5 100644
--- a/packages/SystemUI/res/layout-sw600dp/status_bar_recent_item.xml
+++ b/packages/SystemUI/res/layout-sw600dp/status_bar_recent_item.xml
@@ -35,6 +35,7 @@
         <ImageView android:id="@+id/app_thumbnail_image"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
+            android:visibility="invisible"
         />
     </FrameLayout>
 
@@ -63,6 +64,7 @@
         android:layout_marginTop="32dip"
         android:singleLine="true"
         android:ellipsize="marquee"
+        android:textColor="@color/status_bar_recents_app_label_color"
     />
 
     <View android:id="@+id/recents_callout_line"
diff --git a/packages/SystemUI/res/layout/status_bar_expanded.xml b/packages/SystemUI/res/layout/status_bar_expanded.xml
index 0b3fb98..f9f31ca 100644
--- a/packages/SystemUI/res/layout/status_bar_expanded.xml
+++ b/packages/SystemUI/res/layout/status_bar_expanded.xml
@@ -32,6 +32,7 @@
         android:paddingTop="3dp"
         android:paddingBottom="5dp"
         android:paddingRight="3dp"
+        android:background="@drawable/notification_header_bg"
         >
         <com.android.systemui.statusbar.policy.DateView android:id="@+id/date"
             android:textAppearance="@style/TextAppearance.StatusBar.Clock"
@@ -104,12 +105,25 @@
             android:fadingEdge="none"
             android:overScrollMode="ifContentScrolls"
             >
-            <com.android.systemui.statusbar.policy.NotificationRowLayout
-                android:id="@+id/latestItems"
+            <LinearLayout
                 android:layout_width="match_parent"
                 android:layout_height="wrap_content"
-                systemui:rowHeight="@dimen/notification_height"
+                android:orientation="vertical"
+                >
+                <com.android.systemui.statusbar.policy.NotificationRowLayout
+                    android:id="@+id/latestItems"
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    systemui:rowHeight="@dimen/notification_height"
+                    android:background="@color/notification_list_shadow_top"
+                    />
+                <ImageView
+                    android:layout_width="match_parent"
+                    android:layout_height="16dp"
+                    android:src="@drawable/notification_list_shadow"
+                    android:scaleType="fitXY"
                 />
+            </LinearLayout>
         </ScrollView>
 
         <ImageView
diff --git a/packages/SystemUI/res/layout/status_bar_tracking.xml b/packages/SystemUI/res/layout/status_bar_tracking.xml
index 894248e..25c0237 100644
--- a/packages/SystemUI/res/layout/status_bar_tracking.xml
+++ b/packages/SystemUI/res/layout/status_bar_tracking.xml
@@ -30,7 +30,7 @@
          android:layout_width="match_parent"
          android:layout_height="wrap_content"
          android:layout_weight="1"
-         android:background="@drawable/status_bar_bg"
+         android:background="@drawable/notification_tracking_bg"
          />
 
     <com.android.systemui.statusbar.phone.CloseDragHandle android:id="@+id/close"
diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml
index 4c222f9..298536b4 100644
--- a/packages/SystemUI/res/values/colors.xml
+++ b/packages/SystemUI/res/values/colors.xml
@@ -23,5 +23,9 @@
     <drawable name="status_bar_background">#ff000000</drawable>
     <drawable name="status_bar_recents_background">#b3000000</drawable>
     <drawable name="status_bar_recents_app_thumbnail_background">#88000000</drawable>
+    <color name="status_bar_recents_app_label_color">#ffffffff</color>
     <drawable name="status_bar_notification_row_background_color">#ff000000</drawable>
+    <drawable name="notification_header_bg">#FF000000</drawable>
+    <drawable name="notification_tracking_bg">#cc111315</drawable>
+    <color name="notification_list_shadow_top">#80000000</color>
 </resources>
diff --git a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
index 0354fd7..07281d4 100644
--- a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
@@ -41,9 +41,10 @@
     public static final int Y = 1;
 
     private float SWIPE_ESCAPE_VELOCITY = 100f; // dp/sec
-    private int MAX_ESCAPE_ANIMATION_DURATION = 500; // ms
-    private int MAX_DISMISS_VELOCITY = 1000; // dp/sec
-    private static final int SNAP_ANIM_LEN = SLOW_ANIMATIONS ? 1000 : 250; // ms
+    private int DEFAULT_ESCAPE_ANIMATION_DURATION = 200; // ms
+    private int MAX_ESCAPE_ANIMATION_DURATION = 400; // ms
+    private int MAX_DISMISS_VELOCITY = 2000; // dp/sec
+    private static final int SNAP_ANIM_LEN = SLOW_ANIMATIONS ? 1000 : 150; // ms
 
     public static float ALPHA_FADE_START = 0f; // fraction of thumbnail width
                                                  // where fade starts
@@ -126,7 +127,10 @@
         } else if (pos < viewSize * (1.0f - ALPHA_FADE_START)) {
             result = 1.0f + (viewSize * ALPHA_FADE_START + pos) / fadeSize;
         }
-        return result;
+        // Make .03 alpha the minimum so you always see the item a bit-- slightly below
+        // .03, the item disappears entirely (as if alpha = 0) and that discontinuity looks
+        // a bit jarring
+        return Math.max(0.03f, result);
     }
 
     // invalidate the view's own bounds all the way up the view hierarchy
@@ -186,6 +190,7 @@
                 }
                 break;
             case MotionEvent.ACTION_UP:
+            case MotionEvent.ACTION_CANCEL:
                 mDragging = false;
                 mCurrView = null;
                 mCurrAnimView = null;
@@ -212,7 +217,10 @@
             duration = Math.min(duration,
                                 (int) (Math.abs(newPos - getTranslation(animView)) * 1000f / Math
                                         .abs(velocity)));
+        } else {
+            duration = DEFAULT_ESCAPE_ANIMATION_DURATION;
         }
+
         ObjectAnimator anim = createTranslationAnimation(animView, newPos);
         anim.setInterpolator(new LinearInterpolator());
         anim.setDuration(duration);
diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentsHorizontalScrollView.java b/packages/SystemUI/src/com/android/systemui/recent/RecentsHorizontalScrollView.java
index fc03a27..1c9d80d 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/RecentsHorizontalScrollView.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/RecentsHorizontalScrollView.java
@@ -44,15 +44,6 @@
     private SwipeHelper mSwipeHelper;
     private RecentsScrollViewPerformanceHelper mPerformanceHelper;
 
-    private OnLongClickListener mOnLongClick = new OnLongClickListener() {
-        public boolean onLongClick(View v) {
-            final View anchorView = v.findViewById(R.id.app_description);
-            final View thumbnailView = v.findViewById(R.id.app_thumbnail);
-            mCallback.handleLongPress(v, anchorView, thumbnailView);
-            return true;
-        }
-    };
-
     public RecentsHorizontalScrollView(Context context, AttributeSet attrs) {
         super(context, attrs, 0);
         float densityScale = getResources().getDisplayMetrics().density;
@@ -69,8 +60,6 @@
         mLinearLayout.removeAllViews();
         for (int i = 0; i < mAdapter.getCount(); i++) {
             final View view = mAdapter.getView(i, null, mLinearLayout);
-            view.setLongClickable(true);
-            view.setOnLongClickListener(mOnLongClick);
 
             if (mPerformanceHelper != null) {
                 mPerformanceHelper.addViewCallback(view);
@@ -81,18 +70,30 @@
                     mCallback.dismiss();
                 }
             });
+            // We don't want a click sound when we dimiss recents
+            view.setSoundEffectsEnabled(false);
 
             OnClickListener launchAppListener = new OnClickListener() {
                 public void onClick(View v) {
                     mCallback.handleOnClick(view);
                 }
             };
+            OnLongClickListener longClickListener = new OnLongClickListener() {
+                public boolean onLongClick(View v) {
+                    final View anchorView = view.findViewById(R.id.app_description);
+                    final View thumbnailView = view.findViewById(R.id.app_thumbnail);
+                    mCallback.handleLongPress(view, anchorView, thumbnailView);
+                    return true;
+                }
+            };
             final View thumbnail = view.findViewById(R.id.app_thumbnail);
             thumbnail.setClickable(true);
             thumbnail.setOnClickListener(launchAppListener);
+            thumbnail.setOnLongClickListener(longClickListener);
             final View appTitle = view.findViewById(R.id.app_label);
             appTitle.setClickable(true);
             appTitle.setOnClickListener(launchAppListener);
+            appTitle.setOnLongClickListener(longClickListener);
             mLinearLayout.addView(view);
         }
         // Scroll to end after layout.
diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java b/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java
index f7afe3a..0621b22 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java
@@ -186,12 +186,6 @@
                 holder.labelView = (TextView) convertView.findViewById(R.id.app_label);
                 holder.descriptionView = (TextView) convertView.findViewById(R.id.app_description);
 
-		/*                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);*/
                 convertView.setTag(holder);
             } else {
                 holder = (ViewHolder) convertView.getTag();
diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentsVerticalScrollView.java b/packages/SystemUI/src/com/android/systemui/recent/RecentsVerticalScrollView.java
index b12387a..213803c 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/RecentsVerticalScrollView.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/RecentsVerticalScrollView.java
@@ -43,15 +43,6 @@
     private SwipeHelper mSwipeHelper;
     private RecentsScrollViewPerformanceHelper mPerformanceHelper;
 
-    private OnLongClickListener mOnLongClick = new OnLongClickListener() {
-        public boolean onLongClick(View v) {
-            final View anchorView = v.findViewById(R.id.app_description);
-            final View thumbnailView = v.findViewById(R.id.app_thumbnail);
-            mCallback.handleLongPress(v, anchorView, thumbnailView);
-            return true;
-        }
-    };
-
     public RecentsVerticalScrollView(Context context, AttributeSet attrs) {
         super(context, attrs, 0);
         float densityScale = getResources().getDisplayMetrics().density;
@@ -83,28 +74,39 @@
             }
 
             if (old == null) {
-                view.setClickable(true);
-                view.setOnLongClickListener(mOnLongClick);
                 view.setOnClickListener(new OnClickListener() {
                     public void onClick(View v) {
                         mCallback.dismiss();
                     }
                 });
+                // We don't want a click sound when we dimiss recents
+                view.setSoundEffectsEnabled(false);
 
                 OnClickListener launchAppListener = new OnClickListener() {
                     public void onClick(View v) {
                         mCallback.handleOnClick(view);
                     }
                 };
+                OnLongClickListener longClickListener = new OnLongClickListener() {
+                    public boolean onLongClick(View v) {
+                        final View anchorView = view.findViewById(R.id.app_description);
+                        final View thumbnailView = view.findViewById(R.id.app_thumbnail);
+                        mCallback.handleLongPress(view, anchorView, thumbnailView);
+                        return true;
+                    }
+                };
                 final View thumbnail = view.findViewById(R.id.app_thumbnail);
                 thumbnail.setClickable(true);
                 thumbnail.setOnClickListener(launchAppListener);
+                thumbnail.setOnLongClickListener(longClickListener);
                 final View appTitle = view.findViewById(R.id.app_label);
                 appTitle.setClickable(true);
                 appTitle.setOnClickListener(launchAppListener);
+                appTitle.setOnLongClickListener(longClickListener);
                 final View calloutLine = view.findViewById(R.id.recents_callout_line);
                 calloutLine.setClickable(true);
                 calloutLine.setOnClickListener(launchAppListener);
+                calloutLine.setOnLongClickListener(longClickListener);
                 mLinearLayout.addView(view);
             }
         }
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 69e0752..0b65d01 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -1458,9 +1458,10 @@
             Slog.d(TAG, "Touch: rawY=" + event.getRawY() + " event=" + event + " mDisabled="
                 + mDisabled);
         } else if (CHATTY) {
-            if (event.getAction() == MotionEvent.ACTION_DOWN) {
+            if (event.getAction() != MotionEvent.ACTION_MOVE) {
                 Slog.d(TAG, String.format(
-                            "panel: ACTION_DOWN at (%f, %f) mDisabled=0x%08x",
+                            "panel: %s at (%f, %f) mDisabled=0x%08x",
+                            MotionEvent.actionToString(event.getAction()),
                             event.getRawX(), event.getRawY(), mDisabled));
             }
         }
@@ -1469,11 +1470,11 @@
             return false;
         }
 
+        final int action = event.getAction();
         final int statusBarSize = mStatusBarView.getHeight();
         final int hitSize = statusBarSize*2;
-        if (event.getAction() == MotionEvent.ACTION_DOWN) {
-            final int y = (int)event.getRawY();
-
+        final int y = (int)event.getRawY();
+        if (action == MotionEvent.ACTION_DOWN) {
             if (!mExpanded) {
                 mViewDelta = statusBarSize - y;
             } else {
@@ -1490,21 +1491,21 @@
                 final int edgeBorder = mEdgeBorder;
                 if (x >= edgeBorder && x < mDisplayMetrics.widthPixels - edgeBorder) {
                     prepareTracking(y, !mExpanded);// opening if we're not already fully visible
-                    mVelocityTracker.addMovement(event);
+                    trackMovement(event);
                 }
             }
         } else if (mTracking) {
-            mVelocityTracker.addMovement(event);
+            trackMovement(event);
             final int minY = statusBarSize + mCloseView.getHeight();
-            if (event.getAction() == MotionEvent.ACTION_MOVE) {
-                int y = (int)event.getRawY();
+            if (action == MotionEvent.ACTION_MOVE) {
                 if (mAnimatingReveal && y < minY) {
                     // nothing
                 } else  {
                     mAnimatingReveal = false;
                     updateExpandedViewPos(y + mViewDelta);
                 }
-            } else if (event.getAction() == MotionEvent.ACTION_UP) {
+            } else if (action == MotionEvent.ACTION_UP
+                    || action == MotionEvent.ACTION_CANCEL) {
                 mVelocityTracker.computeCurrentVelocity(1000);
 
                 float yVel = mVelocityTracker.getYVelocity();
@@ -1531,13 +1532,23 @@
                         vel));
                 }
 
-                performFling((int)event.getRawY(), vel, false);
+                performFling(y + mViewDelta, vel, false);
             }
 
         }
         return false;
     }
 
+    private void trackMovement(MotionEvent event) {
+        // Add movement to velocity tracker using raw screen X and Y coordinates instead
+        // of window coordinates because the window frame may be moving at the same time.
+        float deltaX = event.getRawX() - event.getX();
+        float deltaY = event.getRawY() - event.getY();
+        event.offsetLocation(deltaX, deltaY);
+        mVelocityTracker.addMovement(event);
+        event.offsetLocation(-deltaX, -deltaY);
+    }
+
     @Override // CommandQueue
     public void setSystemUiVisibility(int vis) {
         final int old = mSystemUiVisibility;
@@ -1834,7 +1845,7 @@
                 | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
                 | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS
                 | WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM,
-                PixelFormat.OPAQUE);
+                PixelFormat.TRANSLUCENT);
         if (ActivityManager.isHighEndGfx(mDisplay)) {
             lp.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
         }
diff --git a/packages/VpnDialogs/res/layout/manage.xml b/packages/VpnDialogs/res/layout/manage.xml
index 3dcbb46..ec710ff 100644
--- a/packages/VpnDialogs/res/layout/manage.xml
+++ b/packages/VpnDialogs/res/layout/manage.xml
@@ -19,7 +19,8 @@
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         android:padding="3mm"
-        android:stretchColumns="0,1">
+        android:stretchColumns="0,1"
+        android:shrinkColumns="1">
 
     <TableRow>
         <TextView android:text="@string/session" style="@style/label"/>
diff --git a/packages/VpnDialogs/res/values/strings.xml b/packages/VpnDialogs/res/values/strings.xml
index df6d36b..fcd58fa 100644
--- a/packages/VpnDialogs/res/values/strings.xml
+++ b/packages/VpnDialogs/res/values/strings.xml
@@ -35,8 +35,8 @@
 
     <string name="session">Session:</string>
     <string name="duration">Duration:</string>
-    <string name="data_transmitted">Data Transmitted:</string>
-    <string name="data_received">Data Received:</string>
+    <string name="data_transmitted">Sent:</string>
+    <string name="data_received">Received:</string>
 
     <string name="blank_value">--</string>
     <string name="data_value_format">
diff --git a/packages/VpnDialogs/res/values/styles.xml b/packages/VpnDialogs/res/values/styles.xml
index 6eae218..cf10596 100644
--- a/packages/VpnDialogs/res/values/styles.xml
+++ b/packages/VpnDialogs/res/values/styles.xml
@@ -24,7 +24,7 @@
 
     <style name="label">
         <item name="android:gravity">center_vertical|right</item>
-        <item name="android:paddingRight">5mm</item>
+        <item name="android:paddingRight">2mm</item>
         <item name="android:textSize">16sp</item>
     </style>
 
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index 94efa74..a58f64c 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -87,6 +87,8 @@
 // RecordThread loop sleep time upon application overrun or audio HAL read error
 static const int kRecordThreadSleepUs = 5000;
 
+static const nsecs_t kSetParametersTimeout = seconds(2);
+
 // ----------------------------------------------------------------------------
 
 static bool recordingAllowed() {
@@ -1032,7 +1034,7 @@
     mWaitWorkCV.signal();
     // wait condition with timeout in case the thread loop has exited
     // before the request could be processed
-    if (mParamCond.waitRelative(mLock, seconds(2)) == NO_ERROR) {
+    if (mParamCond.waitRelative(mLock, kSetParametersTimeout) == NO_ERROR) {
         status = mParamStatus;
         mWaitWorkCV.signal();
     } else {
@@ -2349,7 +2351,9 @@
 
         mParamStatus = status;
         mParamCond.signal();
-        mWaitWorkCV.wait(mLock);
+        // wait for condition with time out in case the thread calling ThreadBase::setParameters()
+        // already timed out waiting for the status and will never signal the condition.
+        mWaitWorkCV.waitRelative(mLock, kSetParametersTimeout);
     }
     return reconfig;
 }
@@ -2828,7 +2832,9 @@
 
         mParamStatus = status;
         mParamCond.signal();
-        mWaitWorkCV.wait(mLock);
+        // wait for condition with time out in case the thread calling ThreadBase::setParameters()
+        // already timed out waiting for the status and will never signal the condition.
+        mWaitWorkCV.waitRelative(mLock, kSetParametersTimeout);
     }
     return reconfig;
 }
@@ -4669,7 +4675,9 @@
 
         mParamStatus = status;
         mParamCond.signal();
-        mWaitWorkCV.wait(mLock);
+        // wait for condition with time out in case the thread calling ThreadBase::setParameters()
+        // already timed out waiting for the status and will never signal the condition.
+        mWaitWorkCV.waitRelative(mLock, kSetParametersTimeout);
     }
     return reconfig;
 }
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 2714fc5..7e28c4f 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -148,7 +148,8 @@
 
             Slog.i(TAG, "Package Manager");
             pm = PackageManagerService.main(context,
-                    factoryTest != SystemServer.FACTORY_TEST_OFF);
+                    factoryTest != SystemServer.FACTORY_TEST_OFF,
+                    false);
 
             ActivityManagerService.setSystemProcess();
 
diff --git a/services/java/com/android/server/WifiService.java b/services/java/com/android/server/WifiService.java
index 4b1a4e6..883fc71 100644
--- a/services/java/com/android/server/WifiService.java
+++ b/services/java/com/android/server/WifiService.java
@@ -37,7 +37,7 @@
 import android.net.wifi.WifiConfiguration;
 import android.net.wifi.WifiWatchdogStateMachine;
 import android.net.wifi.WifiConfiguration.KeyMgmt;
-import android.net.wifi.Wps;
+import android.net.wifi.WpsInfo;
 import android.net.wifi.WpsResult;
 import android.net.ConnectivityManager;
 import android.net.DhcpInfo;
@@ -288,7 +288,7 @@
                 }
                 case WifiManager.CMD_START_WPS: {
                     //replyTo has the original source
-                    mWifiStateMachine.startWps(msg.replyTo, (Wps)msg.obj);
+                    mWifiStateMachine.startWps(msg.replyTo, (WpsInfo)msg.obj);
                     break;
                 }
                 case WifiManager.CMD_DISABLE_NETWORK: {
diff --git a/services/java/com/android/server/pm/PackageManagerService.java b/services/java/com/android/server/pm/PackageManagerService.java
index bfb244b..4e5ca8e 100644
--- a/services/java/com/android/server/pm/PackageManagerService.java
+++ b/services/java/com/android/server/pm/PackageManagerService.java
@@ -221,6 +221,7 @@
 
     final Context mContext;
     final boolean mFactoryTest;
+    final boolean mOnlyCore;
     final boolean mNoDexOpt;
     final DisplayMetrics mMetrics;
     final int mDefParseFlags;
@@ -809,8 +810,9 @@
         return false;
     }
 
-    public static final IPackageManager main(Context context, boolean factoryTest) {
-        PackageManagerService m = new PackageManagerService(context, factoryTest);
+    public static final IPackageManager main(Context context, boolean factoryTest,
+            boolean onlyCore) {
+        PackageManagerService m = new PackageManagerService(context, factoryTest, onlyCore);
         ServiceManager.addService("package", m);
         return m;
     }
@@ -837,7 +839,7 @@
         return res;
     }
 
-    public PackageManagerService(Context context, boolean factoryTest) {
+    public PackageManagerService(Context context, boolean factoryTest, boolean onlyCore) {
         EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_START,
                 SystemClock.uptimeMillis());
 
@@ -847,6 +849,7 @@
 
         mContext = context;
         mFactoryTest = factoryTest;
+        mOnlyCore = onlyCore;
         mNoDexOpt = "eng".equals(SystemProperties.get("ro.build.type"));
         mMetrics = new DisplayMetrics();
         mSettings = new Settings();
@@ -1051,18 +1054,20 @@
             mInstaller.moveFiles();
 
             // Prune any system packages that no longer exist.
-            Iterator<PackageSetting> psit = mSettings.mPackages.values().iterator();
-            while (psit.hasNext()) {
-                PackageSetting ps = psit.next();
-                if ((ps.pkgFlags&ApplicationInfo.FLAG_SYSTEM) != 0
-                        && !mPackages.containsKey(ps.name)
-                        && !mSettings.mDisabledSysPackages.containsKey(ps.name)) {
-                    psit.remove();
-                    String msg = "System package " + ps.name
-                            + " no longer exists; wiping its data";
-                    reportSettingsProblem(Log.WARN, msg);
-                    mInstaller.remove(ps.name, 0);
-                    mUserManager.removePackageForAllUsers(ps.name);
+            if (!mOnlyCore) {
+                Iterator<PackageSetting> psit = mSettings.mPackages.values().iterator();
+                while (psit.hasNext()) {
+                    PackageSetting ps = psit.next();
+                    if ((ps.pkgFlags&ApplicationInfo.FLAG_SYSTEM) != 0
+                            && !mPackages.containsKey(ps.name)
+                            && !mSettings.mDisabledSysPackages.containsKey(ps.name)) {
+                        psit.remove();
+                        String msg = "System package " + ps.name
+                                + " no longer exists; wiping its data";
+                        reportSettingsProblem(Log.WARN, msg);
+                        mInstaller.remove(ps.name, 0);
+                        mUserManager.removePackageForAllUsers(ps.name);
+                    }
                 }
             }
             
@@ -1077,18 +1082,23 @@
             //delete tmp files
             deleteTempPackageFiles();
 
-            EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_DATA_SCAN_START,
-                    SystemClock.uptimeMillis());
-            mAppInstallObserver = new AppDirObserver(
-                mAppInstallDir.getPath(), OBSERVER_EVENTS, false);
-            mAppInstallObserver.startWatching();
-            scanDirLI(mAppInstallDir, 0, scanMode, 0);
-
-            mDrmAppInstallObserver = new AppDirObserver(
-                mDrmAppPrivateInstallDir.getPath(), OBSERVER_EVENTS, false);
-            mDrmAppInstallObserver.startWatching();
-            scanDirLI(mDrmAppPrivateInstallDir, PackageParser.PARSE_FORWARD_LOCK,
-                    scanMode, 0);
+            if (!mOnlyCore) {
+                EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_DATA_SCAN_START,
+                        SystemClock.uptimeMillis());
+                mAppInstallObserver = new AppDirObserver(
+                    mAppInstallDir.getPath(), OBSERVER_EVENTS, false);
+                mAppInstallObserver.startWatching();
+                scanDirLI(mAppInstallDir, 0, scanMode, 0);
+    
+                mDrmAppInstallObserver = new AppDirObserver(
+                    mDrmAppPrivateInstallDir.getPath(), OBSERVER_EVENTS, false);
+                mDrmAppInstallObserver.startWatching();
+                scanDirLI(mDrmAppPrivateInstallDir, PackageParser.PARSE_FORWARD_LOCK,
+                        scanMode, 0);
+            } else {
+                mAppInstallObserver = null;
+                mDrmAppInstallObserver = null;
+            }
 
             EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_SCAN_END,
                     SystemClock.uptimeMillis());
@@ -2749,6 +2759,7 @@
         parseFlags |= mDefParseFlags;
         PackageParser pp = new PackageParser(scanPath);
         pp.setSeparateProcesses(mSeparateProcesses);
+        pp.setOnlyCoreApps(mOnlyCore);
         final PackageParser.Package pkg = pp.parsePackage(scanFile,
                 scanPath, mMetrics, parseFlags);
         if (pkg == null) {
@@ -4044,7 +4055,7 @@
                         + " info=" + bp.pendingInfo);
                 if (bp.packageSetting == null && bp.pendingInfo != null) {
                     final BasePermission tree = findPermissionTreeLP(bp.name);
-                    if (tree != null) {
+                    if (tree != null && tree.perm != null) {
                         bp.packageSetting = tree.packageSetting;
                         bp.perm = new PackageParser.Permission(tree.perm.owner,
                                 new PermissionInfo(bp.pendingInfo));
diff --git a/services/java/com/android/server/wm/DimSurface.java b/services/java/com/android/server/wm/DimSurface.java
index d7bb8b3..dc6cc0d 100644
--- a/services/java/com/android/server/wm/DimSurface.java
+++ b/services/java/com/android/server/wm/DimSurface.java
@@ -53,19 +53,22 @@
     void show(int dw, int dh, int layer, int color) {
         if (!mDimShown) {
             if (WindowManagerService.SHOW_TRANSACTIONS) Slog.i(WindowManagerService.TAG, "  DIM " + mDimSurface + ": SHOW pos=(0,0) (" +
-                    dw + "x" + dh + ")");
+                    dw + "x" + dh + " layer=" + layer + ")");
             mDimShown = true;
             try {
                 mLastDimWidth = dw;
                 mLastDimHeight = dh;
                 mDimSurface.setPosition(0, 0);
                 mDimSurface.setSize(dw, dh);
+                mDimSurface.setLayer(layer);
                 mDimSurface.show();
             } catch (RuntimeException e) {
                 Slog.w(WindowManagerService.TAG, "Failure showing dim surface", e);
             }
         } else if (mLastDimWidth != dw || mLastDimHeight != dh || mDimColor != color
                 || mLayer != layer) {
+            if (WindowManagerService.SHOW_TRANSACTIONS) Slog.i(WindowManagerService.TAG, "  DIM " + mDimSurface + ": pos=(0,0) (" +
+                    dw + "x" + dh + " layer=" + layer + ")");
             mLastDimWidth = dw;
             mLastDimHeight = dh;
             mLayer = layer;
@@ -80,6 +83,7 @@
         if (mDimShown) {
             mDimShown = false;
             try {
+                if (WindowManagerService.SHOW_TRANSACTIONS) Slog.i(WindowManagerService.TAG, "  HIDE " + mDimSurface);
                 mDimSurface.hide();
             } catch (RuntimeException e) {
                 Slog.w(WindowManagerService.TAG, "Illegal argument exception hiding dim surface");
diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java
index df9698e..5a7fc9f 100644
--- a/services/java/com/android/server/wm/WindowManagerService.java
+++ b/services/java/com/android/server/wm/WindowManagerService.java
@@ -7458,9 +7458,12 @@
                                     windowDetachedWallpaper = w;
                                 }
                                 if (w.mAnimation.getBackgroundColor() != 0) {
-                                    windowAnimationBackground = w;
-                                    windowAnimationBackgroundColor =
-                                            w.mAnimation.getBackgroundColor();
+                                    if (windowAnimationBackground == null || w.mAnimLayer <
+                                            windowAnimationBackground.mAnimLayer) {
+                                        windowAnimationBackground = w;
+                                        windowAnimationBackgroundColor =
+                                                w.mAnimation.getBackgroundColor();
+                                    }
                                 }
                             }
                             animating = true;
@@ -7469,14 +7472,18 @@
                         // If this window's app token is running a detached wallpaper
                         // animation, make a note so we can ensure the wallpaper is
                         // displayed behind it.
-                        if (w.mAppToken != null && w.mAppToken.animation != null) {
+                        if (w.mAppToken != null && w.mAppToken.animation != null
+                                && w.mAppToken.animating) {
                             if (w.mAppToken.animation.getDetachWallpaper()) {
                                 windowDetachedWallpaper = w;
                             }
                             if (w.mAppToken.animation.getBackgroundColor() != 0) {
-                                windowAnimationBackground = w;
-                                windowAnimationBackgroundColor =
-                                        w.mAppToken.animation.getBackgroundColor();
+                                if (windowAnimationBackground == null || w.mAnimLayer <
+                                        windowAnimationBackground.mAnimLayer) {
+                                    windowAnimationBackground = w;
+                                    windowAnimationBackgroundColor =
+                                            w.mAppToken.animation.getBackgroundColor();
+                                }
                             }
                         }
 
diff --git a/services/java/com/android/server/wm/WindowState.java b/services/java/com/android/server/wm/WindowState.java
index bb36d3a7..0ee3f17 100644
--- a/services/java/com/android/server/wm/WindowState.java
+++ b/services/java/com/android/server/wm/WindowState.java
@@ -968,6 +968,7 @@
                         + mPolicyVisibilityAfterAnim);
             }
             mPolicyVisibility = mPolicyVisibilityAfterAnim;
+            mService.mLayoutNeeded = true;
             if (!mPolicyVisibility) {
                 if (mService.mCurrentFocus == this) {
                     mService.mFocusMayChange = true;
diff --git a/services/sensorservice/tests/sensorservicetest.cpp b/services/sensorservice/tests/sensorservicetest.cpp
index 54bce09..1025fa8 100644
--- a/services/sensorservice/tests/sensorservicetest.cpp
+++ b/services/sensorservice/tests/sensorservicetest.cpp
@@ -35,22 +35,21 @@
 
     while ((n = q->read(buffer, 8)) > 0) {
         for (int i=0 ; i<n ; i++) {
-            if (buffer[i].type == Sensor::TYPE_ACCELEROMETER) {
-                printf("time=%lld, value=<%5.1f,%5.1f,%5.1f>\n",
-                        buffer[i].timestamp,
-                        buffer[i].acceleration.x,
-                        buffer[i].acceleration.y,
-                        buffer[i].acceleration.z);
-            }
-
+            float t;
             if (oldTimeStamp) {
-                float t = float(buffer[i].timestamp - oldTimeStamp) / s2ns(1);
-                printf("%f ms (%f Hz)\n", t*1000, 1.0/t);
+                t = float(buffer[i].timestamp - oldTimeStamp) / s2ns(1);
             } else {
-                float t = float(buffer[i].timestamp - sStartTime) / s2ns(1);
-                printf("first event: %f ms\n", t*1000);
+                t = float(buffer[i].timestamp - sStartTime) / s2ns(1);
             }
             oldTimeStamp = buffer[i].timestamp;
+
+            if (buffer[i].type == Sensor::TYPE_ACCELEROMETER) {
+                printf("%lld\t%8f\t%8f\t%8f\t%f\n",
+                        buffer[i].timestamp,
+                        buffer[i].data[0], buffer[i].data[1], buffer[i].data[2],
+                        1.0/t);
+            }
+
         }
     }
     if (n<0 && n != -EAGAIN) {
@@ -79,7 +78,7 @@
 
     q->enableSensor(accelerometer);
 
-    q->setEventRate(accelerometer, ms2ns(200));
+    q->setEventRate(accelerometer, ms2ns(10));
 
     sp<Looper> loop = new Looper(false);
     loop->addFd(q->getFd(), 0, ALOOPER_EVENT_INPUT, receiver, q.get());
diff --git a/services/tests/servicestests/res/raw/xt_qtaguid_extended b/services/tests/servicestests/res/raw/xt_qtaguid_extended
index 5bef3dd..2f3b4ec 100644
--- a/services/tests/servicestests/res/raw/xt_qtaguid_extended
+++ b/services/tests/servicestests/res/raw/xt_qtaguid_extended
@@ -1,3 +1,3 @@
-acct_tag_hex uid_tag_int iface rx_bytes rx_packets tx_bytes tx_packets teleported_goats
-0x0 1000 test0 1024 10 2048 20 2716057
-0x0000F00D00000000 1000 test0 512 5 512 5 3370318
+acct_tag_hex uid_tag_int iface rx_bytes rx_packets tx_bytes tx_packets teleported_goats idx
+0x0 1000 test0 1024 10 2048 20 2716057 2
+0x0000F00D00000000 1000 test0 512 5 512 5 3370318 3
diff --git a/services/tests/servicestests/res/raw/xt_qtaguid_typical b/services/tests/servicestests/res/raw/xt_qtaguid_typical
index 7c4f04e..8df4b1b 100644
--- a/services/tests/servicestests/res/raw/xt_qtaguid_typical
+++ b/services/tests/servicestests/res/raw/xt_qtaguid_typical
@@ -1,32 +1,32 @@
 idx iface acct_tag_hex uid_tag_int rx_bytes tx_bytes
-1 wlan0 0x0 0 14615 4270
-2 wlan0 0x0 1000 5175 915
-3 wlan0 0x0 1021 3381 903
-4 wlan0 0x0 10004 333821 53558
-5 wlan0 0x0 10010 4888 37363
-6 wlan0 0x0 10013 52 104
-7 wlan0 0x74182ada00000000 10004 18725 1066
-8 rmnet0 0x0 0 301274 30244
-9 rmnet0 0x0 1000 304 441
-10 rmnet0 0x0 1013 2880 2272
-11 rmnet0 0x0 1021 31407 8430
-12 rmnet0 0x0 10003 32665 3814
-13 rmnet0 0x0 10004 2373141 420112
-14 rmnet0 0x0 10010 870370 1111727
-15 rmnet0 0x0 10013 240 240
-16 rmnet0 0x0 10016 16703 13512
-17 rmnet0 0x0 10017 3990 3269
-18 rmnet0 0x0 10018 474504 14516062
-19 rmnet0 0x0 10019 782804 71077
-20 rmnet0 0x0 10022 70671 49684
-21 rmnet0 0x0 10029 5785354 397159
-22 rmnet0 0x0 10033 2102 1686
-23 rmnet0 0x0 10034 15495464 227694
-24 rmnet0 0x0 10037 31184994 684122
-25 rmnet0 0x0 10051 298687 113485
-26 rmnet0 0x0 10056 29504 20669
-27 rmnet0 0x0 10069 683 596
-28 rmnet0 0x0 10072 34051 12453
-29 rmnet0 0x0 10077 7025393 213866
-30 rmnet0 0x0 10081 354 1178
-31 rmnet0 0x74182ada00000000 10037 28507378 437004
+2 wlan0 0x0 0 14615 4270
+3 wlan0 0x0 1000 5175 915
+4 wlan0 0x0 1021 3381 903
+5 wlan0 0x0 10004 333821 53558
+6 wlan0 0x0 10010 4888 37363
+7 wlan0 0x0 10013 52 104
+8 wlan0 0x74182ada00000000 10004 18725 1066
+9 rmnet0 0x0 0 301274 30244
+10 rmnet0 0x0 1000 304 441
+11 rmnet0 0x0 1013 2880 2272
+12 rmnet0 0x0 1021 31407 8430
+13 rmnet0 0x0 10003 32665 3814
+14 rmnet0 0x0 10004 2373141 420112
+15 rmnet0 0x0 10010 870370 1111727
+16 rmnet0 0x0 10013 240 240
+17 rmnet0 0x0 10016 16703 13512
+18 rmnet0 0x0 10017 3990 3269
+19 rmnet0 0x0 10018 474504 14516062
+20 rmnet0 0x0 10019 782804 71077
+21 rmnet0 0x0 10022 70671 49684
+22 rmnet0 0x0 10029 5785354 397159
+23 rmnet0 0x0 10033 2102 1686
+24 rmnet0 0x0 10034 15495464 227694
+25 rmnet0 0x0 10037 31184994 684122
+26 rmnet0 0x0 10051 298687 113485
+27 rmnet0 0x0 10056 29504 20669
+28 rmnet0 0x0 10069 683 596
+29 rmnet0 0x0 10072 34051 12453
+30 rmnet0 0x0 10077 7025393 213866
+31 rmnet0 0x0 10081 354 1178
+32 rmnet0 0x74182ada00000000 10037 28507378 437004
diff --git a/services/tests/servicestests/res/raw/xt_qtaguid_typical_with_set b/services/tests/servicestests/res/raw/xt_qtaguid_typical_with_set
index 3678b10..f9f34ac 100644
--- a/services/tests/servicestests/res/raw/xt_qtaguid_typical_with_set
+++ b/services/tests/servicestests/res/raw/xt_qtaguid_typical_with_set
@@ -1,13 +1,13 @@
 idx iface acct_tag_hex uid_tag_int cnt_set rx_bytes rx_packets tx_bytes tx_packets rx_tcp_packets rx_tcp_bytes rx_udp_packets rx_udp_bytes rx_other_packets rx_other_bytes tx_tcp_packets tx_tcp_bytes tx_udp_packets tx_udp_bytes tx_other_packets tx_other_bytes

-1 rmnet0 0x0 0 0 14855 82 2804 47 2000 45 12799 35 56 2 676 13 2128 34 0 0

-1 rmnet0 0x0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0

-2 rmnet0 0x0 1000 0 278102 253 10487 182 277342 243 760 10 0 0 9727 172 760 10 0 0

-2 rmnet0 0x0 1000 1 26033 30 1401 26 25881 28 152 2 0 0 1249 24 152 2 0 0

-3 rmnet0 0x0 10012 0 40524 272 134138 293 40524 272 0 0 0 0 134138 293 0 0 0 0

-3 rmnet0 0x0 10012 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0

-4 rmnet0 0x0 10034 0 15791 59 9905 69 15791 59 0 0 0 0 9905 69 0 0 0 0

-4 rmnet0 0x0 10034 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0

-5 rmnet0 0x0 10055 0 3602 29 7739 59 3602 29 0 0 0 0 7739 59 0 0 0 0

-5 rmnet0 0x0 10055 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0

-6 rmnet0 0x7fff000300000000 1000 0 483 4 1931 6 483 4 0 0 0 0 1931 6 0 0 0 0

-6 rmnet0 0x7fff000300000000 1000 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0

+2 rmnet0 0x0 0 0 14855 82 2804 47 2000 45 12799 35 56 2 676 13 2128 34 0 0

+3 rmnet0 0x0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0

+4 rmnet0 0x0 1000 0 278102 253 10487 182 277342 243 760 10 0 0 9727 172 760 10 0 0

+5 rmnet0 0x0 1000 1 26033 30 1401 26 25881 28 152 2 0 0 1249 24 152 2 0 0

+6 rmnet0 0x0 10012 0 40524 272 134138 293 40524 272 0 0 0 0 134138 293 0 0 0 0

+7 rmnet0 0x0 10012 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0

+8 rmnet0 0x0 10034 0 15791 59 9905 69 15791 59 0 0 0 0 9905 69 0 0 0 0

+9 rmnet0 0x0 10034 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0

+10 rmnet0 0x0 10055 0 3602 29 7739 59 3602 29 0 0 0 0 7739 59 0 0 0 0

+11 rmnet0 0x0 10055 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0

+12 rmnet0 0x7fff000300000000 1000 0 483 4 1931 6 483 4 0 0 0 0 1931 6 0 0 0 0

+13 rmnet0 0x7fff000300000000 1000 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0

diff --git a/telephony/java/android/telephony/PhoneNumberUtils.java b/telephony/java/android/telephony/PhoneNumberUtils.java
index 51922da..e898aac 100644
--- a/telephony/java/android/telephony/PhoneNumberUtils.java
+++ b/telephony/java/android/telephony/PhoneNumberUtils.java
@@ -1547,6 +1547,32 @@
     }
 
     /**
+     * Checks if a given number is an emergency number for a specific country.
+     *
+     * @param number the number to look up.
+     * @param defaultCountryIso the specific country which the number should be checked against
+     * @return if the number is an emergency number for the specific country, then return true,
+     * otherwise false
+     * @hide
+     */
+    public static boolean isEmergencyNumber(String number, String defaultCountryIso) {
+      PhoneNumberUtil util = PhoneNumberUtil.getInstance();
+      try {
+        PhoneNumber pn = util.parse(number, defaultCountryIso);
+        // libphonenumber guarantees short numbers such as emergency numbers are classified as
+        // invalid. Therefore, if the number passes the validation test, we believe it is not an
+        // emergency number.
+        // TODO: Compare against a list of country-specific known emergency numbers instead, once
+        // that has been collected.
+        if (util.isValidNumber(pn)) {
+          return false;
+        }
+      } catch (NumberParseException e) {
+      }
+      return isEmergencyNumber(number);
+    }
+
+    /**
      * isVoiceMailNumber: checks a given number against the voicemail
      *   number provided by the RIL and SIM card. The caller must have
      *   the READ_PHONE_STATE credential.
diff --git a/telephony/java/com/android/internal/telephony/CallerInfo.java b/telephony/java/com/android/internal/telephony/CallerInfo.java
index 25f8c8b..7c37a65 100644
--- a/telephony/java/com/android/internal/telephony/CallerInfo.java
+++ b/telephony/java/com/android/internal/telephony/CallerInfo.java
@@ -254,7 +254,9 @@
         // Change the callerInfo number ONLY if it is an emergency number
         // or if it is the voicemail number.  If it is either, take a
         // shortcut and skip the query.
-        if (PhoneNumberUtils.isEmergencyNumber(number)) {
+        Locale locale = context.getResources().getConfiguration().locale;
+        String countryIso = getCurrentCountryIso(context, locale);
+        if (PhoneNumberUtils.isEmergencyNumber(number, countryIso)) {
             return new CallerInfo().markAsEmergency(context);
         } else if (PhoneNumberUtils.isVoiceMailNumber(number)) {
             return new CallerInfo().markAsVoiceMail();
@@ -514,18 +516,8 @@
         PhoneNumberUtil util = PhoneNumberUtil.getInstance();
         PhoneNumberOfflineGeocoder geocoder = PhoneNumberOfflineGeocoder.getInstance();
 
-        String countryIso;
         Locale locale = context.getResources().getConfiguration().locale;
-        CountryDetector detector = (CountryDetector) context.getSystemService(
-                Context.COUNTRY_DETECTOR);
-        if (detector != null) {
-            countryIso = detector.detectCountry().getCountryIso();
-        } else {
-            countryIso = locale.getCountry();
-            Log.w(TAG, "No CountryDetector; falling back to countryIso based on locale: "
-                  + countryIso);
-        }
-
+        String countryIso = getCurrentCountryIso(context, locale);
         PhoneNumber pn = null;
         try {
             if (VDBG) Log.v(TAG, "parsing '" + number
@@ -546,6 +538,24 @@
     }
 
     /**
+     * @return The ISO 3166-1 two letters country code of the country the user
+     *         is in.
+     */
+    private static String getCurrentCountryIso(Context context, Locale locale) {
+      String countryIso;
+      CountryDetector detector = (CountryDetector) context.getSystemService(
+          Context.COUNTRY_DETECTOR);
+      if (detector != null) {
+        countryIso = detector.detectCountry().getCountryIso();
+      } else {
+        countryIso = locale.getCountry();
+        Log.w(TAG, "No CountryDetector; falling back to countryIso based on locale: "
+              + countryIso);
+      }
+      return countryIso;
+    }
+
+    /**
      * @return a string debug representation of this instance.
      */
     public String toString() {
diff --git a/telephony/java/com/android/internal/telephony/CallerInfoAsyncQuery.java b/telephony/java/com/android/internal/telephony/CallerInfoAsyncQuery.java
index 2e8a742..17734ca 100644
--- a/telephony/java/com/android/internal/telephony/CallerInfoAsyncQuery.java
+++ b/telephony/java/com/android/internal/telephony/CallerInfoAsyncQuery.java
@@ -403,7 +403,9 @@
         cw.number = number;
 
         // check to see if these are recognized numbers, and use shortcuts if we can.
-        if (PhoneNumberUtils.isEmergencyNumber(number)) {
+        CountryDetector detector = (CountryDetector) context.getSystemService(
+            Context.COUNTRY_DETECTOR);
+        if (PhoneNumberUtils.isEmergencyNumber(number, detector.detectCountry().getCountryIso())) {
             cw.event = EVENT_EMERGENCY_NUMBER;
         } else if (PhoneNumberUtils.isVoiceMailNumber(number)) {
             cw.event = EVENT_VOICEMAIL_NUMBER;
diff --git a/telephony/java/com/android/internal/telephony/Phone.java b/telephony/java/com/android/internal/telephony/Phone.java
index 5e64148..444f0d2 100644
--- a/telephony/java/com/android/internal/telephony/Phone.java
+++ b/telephony/java/com/android/internal/telephony/Phone.java
@@ -932,7 +932,8 @@
     boolean getCallForwardingIndicator();
 
     /**
-     * Get the line 1 phone number (MSISDN).<p>
+     * Get the line 1 phone number (MSISDN). For CDMA phones, the MDN is returned
+     * and {@link #getMsisdn()} will return the MSISDN on CDMA/LTE phones.<p>
      *
      * @return phone number. May return null if not
      * available or the SIM is not ready
@@ -1432,6 +1433,13 @@
     String getMeid();
 
     /**
+     * Retrieves the MSISDN from the UICC. For GSM/UMTS phones, this is equivalent to
+     * {@link #getLine1Number()}. For CDMA phones, {@link #getLine1Number()} returns
+     * the MDN, so this method is provided to return the MSISDN on CDMA/LTE phones.
+     */
+    String getMsisdn();
+
+    /**
      * Retrieves IMEI for phones. Returns null if IMEI is not set.
      */
     String getImei();
diff --git a/telephony/java/com/android/internal/telephony/PhoneBase.java b/telephony/java/com/android/internal/telephony/PhoneBase.java
index 4f86ea8..82f3955 100644
--- a/telephony/java/com/android/internal/telephony/PhoneBase.java
+++ b/telephony/java/com/android/internal/telephony/PhoneBase.java
@@ -1124,6 +1124,11 @@
         Log.e(LOG_TAG, "requestIsimAuthentication() is only supported on LTE devices");
     }
 
+    public String getMsisdn() {
+        logUnexpectedGsmMethodCall("getMsisdn");
+        return null;
+    }
+
     /**
      * Common error logger method for unexpected calls to CDMA-only methods.
      */
diff --git a/telephony/java/com/android/internal/telephony/PhoneProxy.java b/telephony/java/com/android/internal/telephony/PhoneProxy.java
index 3678017..e0e8d49 100644
--- a/telephony/java/com/android/internal/telephony/PhoneProxy.java
+++ b/telephony/java/com/android/internal/telephony/PhoneProxy.java
@@ -686,6 +686,10 @@
         return mActivePhone.getMeid();
     }
 
+    public String getMsisdn() {
+        return mActivePhone.getMsisdn();
+    }
+
     public String getImei() {
         return mActivePhone.getImei();
     }
diff --git a/telephony/java/com/android/internal/telephony/cdma/CDMALTEPhone.java b/telephony/java/com/android/internal/telephony/cdma/CDMALTEPhone.java
index f4ed91d..6903025 100644
--- a/telephony/java/com/android/internal/telephony/cdma/CDMALTEPhone.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CDMALTEPhone.java
@@ -141,6 +141,11 @@
     }
 
     @Override
+    public String getMsisdn() {
+        return mIccRecords.getMsisdnNumber();
+    }
+
+    @Override
     public void requestIsimAuthentication(String nonce, Message result) {
         mCM.requestIsimAuthentication(nonce, result);
     }
diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaLteUiccRecords.java b/telephony/java/com/android/internal/telephony/cdma/CdmaLteUiccRecords.java
index c4fa6f6..0617fee 100755
--- a/telephony/java/com/android/internal/telephony/cdma/CdmaLteUiccRecords.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CdmaLteUiccRecords.java
@@ -19,6 +19,7 @@
 import android.os.SystemProperties;
 import android.util.Log;
 
+import com.android.internal.telephony.AdnRecordLoader;
 import com.android.internal.telephony.GsmAlphabet;
 import com.android.internal.telephony.IccCardApplication.AppType;
 import com.android.internal.telephony.IccFileHandler;
@@ -276,6 +277,10 @@
                 obtainMessage(EVENT_GET_ICC_RECORD_DONE, new EfPlLoaded()));
         recordsToLoad++;
 
+        new AdnRecordLoader(phone).loadFromEF(EF_MSISDN, EF_EXT1, 1,
+                obtainMessage(EVENT_GET_MSISDN_DONE));
+        recordsToLoad++;
+
         iccFh.loadEFTransparent(EF_CSIM_LI,
                 obtainMessage(EVENT_GET_ICC_RECORD_DONE, new EfCsimLiLoaded()));
         recordsToLoad++;
diff --git a/telephony/java/com/android/internal/telephony/gsm/GSMPhone.java b/telephony/java/com/android/internal/telephony/gsm/GSMPhone.java
index 1db9860..d325aaa 100644
--- a/telephony/java/com/android/internal/telephony/gsm/GSMPhone.java
+++ b/telephony/java/com/android/internal/telephony/gsm/GSMPhone.java
@@ -877,6 +877,11 @@
         return mIccRecords.getMsisdnNumber();
     }
 
+    @Override
+    public String getMsisdn() {
+        return mIccRecords.getMsisdnNumber();
+    }
+
     public String getLine1AlphaTag() {
         return mIccRecords.getMsisdnAlphaTag();
     }
diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
index 4e43fcd..e32270e 100644
--- a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
+++ b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
@@ -115,7 +115,6 @@
     static final Uri PREFERAPN_URI = Uri.parse("content://telephony/carriers/preferapn");
     static final String APN_ID = "apn_id";
     private boolean canSetPreferApn = false;
-    private boolean mRadioAvailable = false;
 
     @Override
     protected void onActionIntentReconnectAlarm(Intent intent) {
@@ -1572,7 +1571,7 @@
     private void onRecordsLoaded() {
         if (DBG) log("onRecordsLoaded: createAllApnList");
         createAllApnList();
-        if (mRadioAvailable) {
+        if (mPhone.mCM.getRadioState().isOn()) {
             if (DBG) log("onRecordsLoaded: notifying data availability");
             notifyDataAvailability(Phone.REASON_SIM_LOADED);
         }
@@ -1706,7 +1705,6 @@
     @Override
     protected void onRadioAvailable() {
         if (DBG) log("onRadioAvailable");
-        mRadioAvailable = true;
         if (mPhone.getSimulatedRadioControl() != null) {
             // Assume data is connected on the simulator
             // FIXME  this can be improved
@@ -1734,7 +1732,6 @@
             dc.resetRetryCount();
         }
         mReregisterOnReconnectFailure = false;
-        mRadioAvailable = false;
 
         if (mPhone.getSimulatedRadioControl() != null) {
             // Assume data is connected on the simulator
diff --git a/telephony/java/com/android/internal/telephony/gsm/SIMRecords.java b/telephony/java/com/android/internal/telephony/gsm/SIMRecords.java
index d84715e..73c319c 100755
--- a/telephony/java/com/android/internal/telephony/gsm/SIMRecords.java
+++ b/telephony/java/com/android/internal/telephony/gsm/SIMRecords.java
@@ -127,7 +127,7 @@
     private static final int EVENT_GET_MWIS_DONE = 7;
     private static final int EVENT_GET_VOICE_MAIL_INDICATOR_CPHS_DONE = 8;
     protected static final int EVENT_GET_AD_DONE = 9; // Admin data on SIM
-    private static final int EVENT_GET_MSISDN_DONE = 10;
+    protected static final int EVENT_GET_MSISDN_DONE = 10;
     private static final int EVENT_GET_CPHS_MAILBOX_DONE = 11;
     private static final int EVENT_GET_SPN_DONE = 12;
     private static final int EVENT_GET_SPDI_DONE = 13;
diff --git a/telephony/tests/telephonytests/src/com/android/internal/telephony/PhoneNumberUtilsTest.java b/telephony/tests/telephonytests/src/com/android/internal/telephony/PhoneNumberUtilsTest.java
index 6e9d0f9d..d3e4b78 100644
--- a/telephony/tests/telephonytests/src/com/android/internal/telephony/PhoneNumberUtilsTest.java
+++ b/telephony/tests/telephonytests/src/com/android/internal/telephony/PhoneNumberUtilsTest.java
@@ -536,4 +536,20 @@
         // The given number was formatted.
         assertEquals("650-291-0000", PhoneNumberUtils.formatNumber("650-291-0000", null, "US"));
     }
+    @SmallTest
+    public void testIsEmergencyNumber() {
+      assertTrue(PhoneNumberUtils.isEmergencyNumber("911", "US"));
+      assertTrue(PhoneNumberUtils.isEmergencyNumber("112", "US"));
+      // The next two numbers are not valid phone numbers in the US, but can be used to trick the
+      // system to dial 911 and 112, which are emergency numbers in the US. For the purpose of
+      // addressing that, they are also classified as emergency numbers in the US.
+      assertTrue(PhoneNumberUtils.isEmergencyNumber("91112345", "US"));
+      assertTrue(PhoneNumberUtils.isEmergencyNumber("11212345", "US"));
+      // A valid mobile phone number from Singapore shouldn't be classified as an emergency number
+      // in Singapore, as 911 is not an emergency number there.
+      assertFalse(PhoneNumberUtils.isEmergencyNumber("91121234", "SG"));
+      // A valid fixed-line phone number from Brazil shouldn't be classified as an emergency number
+      // in Brazil, as 112 is not an emergency number there.
+      assertFalse(PhoneNumberUtils.isEmergencyNumber("1121234567", "BR"));
+    }
 }
diff --git a/voip/java/com/android/server/sip/SipService.java b/voip/java/com/android/server/sip/SipService.java
index c553947..f417ddd 100644
--- a/voip/java/com/android/server/sip/SipService.java
+++ b/voip/java/com/android/server/sip/SipService.java
@@ -442,6 +442,7 @@
 
             if (wasConnected) {
                 mLocalIp = null;
+                stopPortMappingMeasurement();
                 for (SipSessionGroupExt group : mSipGroups.values()) {
                     group.onConnectivityChanged(false);
                 }
@@ -457,7 +458,6 @@
                 if (isWifi && (mWifiLock != null)) stopWifiScanner();
             } else {
                 mMyWakeLock.reset(); // in case there's a leak
-                stopPortMappingMeasurement();
                 if (isWifi && (mWifiLock != null)) startWifiScanner();
             }
         } catch (SipException e) {
@@ -784,52 +784,50 @@
         private static final int PASS_THRESHOLD = 10;
         private static final int MAX_RETRY_COUNT = 5;
         private static final int NAT_MEASUREMENT_RETRY_INTERVAL = 120; // in seconds
+        private SipProfile mLocalProfile;
         private SipSessionGroupExt mGroup;
         private SipSessionGroup.SipSessionImpl mSession;
         private int mMinInterval;
         private int mMaxInterval;
         private int mInterval;
-        private int mPassCount = 0;
+        private int mPassCount;
 
         public IntervalMeasurementProcess(SipProfile localProfile,
                 int minInterval, int maxInterval) {
             mMaxInterval = maxInterval;
             mMinInterval = minInterval;
-            mInterval = (maxInterval + minInterval) / 2;
-
-            // Don't start measurement if the interval is too small
-            if (mInterval < DEFAULT_KEEPALIVE_INTERVAL) {
-                Log.w(TAG, "interval is too small; measurement aborted; "
-                        + "maxInterval=" + mMaxInterval);
-                return;
-            } else if (checkTermination()) {
-                Log.w(TAG, "interval is too small; measurement aborted; "
-                        + "interval=[" + mMinInterval + "," + mMaxInterval
-                        + "]");
-                return;
-            }
-
-            try {
-                mGroup =  new SipSessionGroupExt(localProfile, null, null);
-                // TODO: remove this line once SipWakeupTimer can better handle
-                // variety of timeout values
-                mGroup.setWakeupTimer(new SipWakeupTimer(mContext, mExecutor));
-            } catch (Exception e) {
-                Log.w(TAG, "start interval measurement error: " + e);
-            }
+            mLocalProfile = localProfile;
         }
 
         public void start() {
             synchronized (SipService.this) {
-                Log.d(TAG, "start measurement w interval=" + mInterval);
-                if (mSession == null) {
+                if (mSession != null) {
+                    return;
+                }
+
+                mInterval = (mMaxInterval + mMinInterval) / 2;
+                mPassCount = 0;
+
+                // Don't start measurement if the interval is too small
+                if (mInterval < DEFAULT_KEEPALIVE_INTERVAL || checkTermination()) {
+                    Log.w(TAG, "measurement aborted; interval=[" +
+                            mMinInterval + "," + mMaxInterval + "]");
+                    return;
+                }
+
+                try {
+                    Log.d(TAG, "start measurement w interval=" + mInterval);
+
+                    mGroup = new SipSessionGroupExt(mLocalProfile, null, null);
+                    // TODO: remove this line once SipWakeupTimer can better handle
+                    // variety of timeout values
+                    mGroup.setWakeupTimer(new SipWakeupTimer(mContext, mExecutor));
+
                     mSession = (SipSessionGroup.SipSessionImpl)
                             mGroup.createSession(null);
-                }
-                try {
                     mSession.startKeepAliveProcess(mInterval, this);
-                } catch (SipException e) {
-                    Log.e(TAG, "start()", e);
+                } catch (Throwable t) {
+                    onError(SipErrorCode.CLIENT_ERROR, t.toString());
                 }
             }
         }
@@ -840,6 +838,10 @@
                     mSession.stopKeepAliveProcess();
                     mSession = null;
                 }
+                if (mGroup != null) {
+                    mGroup.close();
+                    mGroup = null;
+                }
                 mTimer.cancel(this);
             }
         }
diff --git a/voip/java/com/android/server/sip/SipSessionGroup.java b/voip/java/com/android/server/sip/SipSessionGroup.java
index eb5cce7..06cdaf2 100644
--- a/voip/java/com/android/server/sip/SipSessionGroup.java
+++ b/voip/java/com/android/server/sip/SipSessionGroup.java
@@ -100,7 +100,7 @@
     private static final int EXPIRY_TIME = 3600; // in seconds
     private static final int CANCEL_CALL_TIMER = 3; // in seconds
     private static final int END_CALL_TIMER = 3; // in seconds
-    private static final int KEEPALIVE_TIMEOUT = 3; // in seconds
+    private static final int KEEPALIVE_TIMEOUT = 5; // in seconds
     private static final int INCALL_KEEPALIVE_INTERVAL = 10; // in seconds
     private static final long WAKE_LOCK_HOLDING_TIME = 500; // in milliseconds
 
@@ -1555,7 +1555,7 @@
                     try {
                         sendKeepAlive();
                     } catch (Throwable t) {
-                        Log.w(TAG, "keepalive error: " + ": "
+                        Log.w(TAG, "keepalive error: "
                                 + mLocalProfile.getUriString(), getRootCause(t));
                         // It's possible that the keepalive process is being stopped
                         // during session.sendKeepAlive() so need to check mRunning
diff --git a/wifi/java/android/net/wifi/IWifiManager.aidl b/wifi/java/android/net/wifi/IWifiManager.aidl
index 27a60cd..61dfebf 100644
--- a/wifi/java/android/net/wifi/IWifiManager.aidl
+++ b/wifi/java/android/net/wifi/IWifiManager.aidl
@@ -18,8 +18,6 @@
 
 import android.net.wifi.WifiInfo;
 import android.net.wifi.WifiConfiguration;
-import android.net.wifi.Wps;
-import android.net.wifi.WpsResult;
 import android.net.wifi.ScanResult;
 import android.net.DhcpInfo;
 
diff --git a/wifi/java/android/net/wifi/WifiConfigStore.java b/wifi/java/android/net/wifi/WifiConfigStore.java
index c75dec7..18d6eaa 100644
--- a/wifi/java/android/net/wifi/WifiConfigStore.java
+++ b/wifi/java/android/net/wifi/WifiConfigStore.java
@@ -397,7 +397,7 @@
      * Start WPS pin method configuration with pin obtained
      * from the access point
      */
-    static WpsResult startWpsWithPinFromAccessPoint(Wps config) {
+    static WpsResult startWpsWithPinFromAccessPoint(WpsInfo config) {
         WpsResult result = new WpsResult();
         if (WifiNative.startWpsWithPinFromAccessPointCommand(config.BSSID, config.pin)) {
             /* WPS leaves all networks disabled */
@@ -415,7 +415,7 @@
      * from the device
      * @return WpsResult indicating status and pin
      */
-    static WpsResult startWpsWithPinFromDevice(Wps config) {
+    static WpsResult startWpsWithPinFromDevice(WpsInfo config) {
         WpsResult result = new WpsResult();
         result.pin = WifiNative.startWpsWithPinFromDeviceCommand(config.BSSID);
         /* WPS leaves all networks disabled */
@@ -432,7 +432,7 @@
     /**
      * Start WPS push button configuration
      */
-    static WpsResult startWpsPbc(Wps config) {
+    static WpsResult startWpsPbc(WpsInfo config) {
         WpsResult result = new WpsResult();
         if (WifiNative.startWpsPbcCommand(config.BSSID)) {
             /* WPS leaves all networks disabled */
@@ -594,7 +594,7 @@
         sendConfiguredNetworksChangedBroadcast();
     }
 
-    static void updateIpAndProxyFromWpsConfig(int netId, Wps wpsConfig) {
+    static void updateIpAndProxyFromWpsConfig(int netId, WpsInfo wpsConfig) {
         synchronized (sConfiguredNetworks) {
             WifiConfiguration config = sConfiguredNetworks.get(netId);
             if (config != null) {
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index 0fce8e8..40ac2a0 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -1175,7 +1175,7 @@
      * @param config WPS configuration
      * @hide
      */
-    public void startWps(Wps config) {
+    public void startWps(WpsInfo config) {
         if (config == null) {
             return;
         }
@@ -1630,4 +1630,4 @@
              return false;
         }
     }
-}
\ No newline at end of file
+}
diff --git a/wifi/java/android/net/wifi/WifiNative.java b/wifi/java/android/net/wifi/WifiNative.java
index 6cc09e9..a6ea6d4 100644
--- a/wifi/java/android/net/wifi/WifiNative.java
+++ b/wifi/java/android/net/wifi/WifiNative.java
@@ -261,23 +261,23 @@
     public static String p2pConnect(WifiP2pConfig config, boolean joinExistingGroup) {
         if (config == null) return null;
         List<String> args = new ArrayList<String>();
-        Wps wps = config.wps;
+        WpsInfo wps = config.wps;
         args.add(config.deviceAddress);
 
         switch (wps.setup) {
-            case PBC:
+            case WpsInfo.PBC:
                 args.add("pbc");
                 break;
-            case DISPLAY:
+            case WpsInfo.DISPLAY:
                 //TODO: pass the pin back for display
                 args.add("pin");
                 args.add("display");
                 break;
-            case KEYPAD:
+            case WpsInfo.KEYPAD:
                 args.add(wps.pin);
                 args.add("keypad");
                 break;
-            case LABEL:
+            case WpsInfo.LABEL:
                 args.add(wps.pin);
                 args.add("label");
             default:
@@ -303,6 +303,10 @@
         return doStringCommand(command);
     }
 
+    public static boolean p2pCancelConnect() {
+        return doBooleanCommand("P2P_CANCEL");
+    }
+
     public static boolean p2pGroupAdd() {
         return doBooleanCommand("P2P_GROUP_ADD");
     }
diff --git a/wifi/java/android/net/wifi/WifiStateMachine.java b/wifi/java/android/net/wifi/WifiStateMachine.java
index 175a9ce..3b29d40 100644
--- a/wifi/java/android/net/wifi/WifiStateMachine.java
+++ b/wifi/java/android/net/wifi/WifiStateMachine.java
@@ -880,7 +880,7 @@
         sendMessage(message);
     }
 
-    public void startWps(Messenger replyTo, Wps config) {
+    public void startWps(Messenger replyTo, WpsInfo config) {
         Message msg = obtainMessage(CMD_START_WPS, config);
         msg.replyTo = replyTo;
         sendMessage(msg);
diff --git a/wifi/java/android/net/wifi/WifiStateTracker.java b/wifi/java/android/net/wifi/WifiStateTracker.java
index 956c3f2..c34c4645 100644
--- a/wifi/java/android/net/wifi/WifiStateTracker.java
+++ b/wifi/java/android/net/wifi/WifiStateTracker.java
@@ -162,7 +162,7 @@
      * Fetch NetworkInfo for the network
      */
     public NetworkInfo getNetworkInfo() {
-        return mNetworkInfo;
+        return new NetworkInfo(mNetworkInfo);
     }
 
     /**
@@ -242,7 +242,8 @@
                 } else {
                     mLastState = state;
                 }
-                Message msg = mCsHandler.obtainMessage(EVENT_STATE_CHANGED, mNetworkInfo);
+                Message msg = mCsHandler.obtainMessage(EVENT_STATE_CHANGED,
+                        new NetworkInfo(mNetworkInfo));
                 msg.sendToTarget();
             } else if (intent.getAction().equals(WifiManager.LINK_CONFIGURATION_CHANGED_ACTION)) {
                 mLinkProperties = (LinkProperties) intent.getParcelableExtra(
diff --git a/wifi/java/android/net/wifi/Wps.aidl b/wifi/java/android/net/wifi/WpsInfo.aidl
similarity index 88%
rename from wifi/java/android/net/wifi/Wps.aidl
rename to wifi/java/android/net/wifi/WpsInfo.aidl
index ba82a9a..f5e4ebe 100644
--- a/wifi/java/android/net/wifi/Wps.aidl
+++ b/wifi/java/android/net/wifi/WpsInfo.aidl
@@ -1,5 +1,5 @@
 /**
- * Copyright (c) 2010, The Android Open Source Project
+ * 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.
@@ -16,4 +16,4 @@
 
 package android.net.wifi;
 
-parcelable Wps;
+parcelable WpsInfo;
diff --git a/wifi/java/android/net/wifi/Wps.java b/wifi/java/android/net/wifi/WpsInfo.java
similarity index 70%
rename from wifi/java/android/net/wifi/Wps.java
rename to wifi/java/android/net/wifi/WpsInfo.java
index 6d006960..f70e5af 100644
--- a/wifi/java/android/net/wifi/Wps.java
+++ b/wifi/java/android/net/wifi/WpsInfo.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2008 The Android Open Source Project
+ * 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.
@@ -26,27 +26,24 @@
 
 /**
  * A class representing Wi-Fi Protected Setup
- * @hide
  *
  * {@see WifiP2pConfig}
  */
-public class Wps implements Parcelable {
+public class WpsInfo implements Parcelable {
+
+    /** Push button configuration */
+    public static final int PBC     = 0;
+    /** Display pin method configuration - pin is generated and displayed on device */
+    public static final int DISPLAY = 1;
+    /** Keypad pin method configuration - pin is entered on device */
+    public static final int KEYPAD  = 2;
+    /** Label pin method configuration - pin is labelled on device */
+    public static final int LABEL   = 3;
+    /** Invalid configuration */
+    public static final int INVALID = 4;
 
     /** Wi-Fi Protected Setup. www.wi-fi.org/wifi-protected-setup has details */
-    public enum Setup {
-        /* Push button configuration */
-        PBC,
-        /* Display pin method configuration - pin is generated and displayed on device */
-        DISPLAY,
-        /* Keypad pin method configuration - pin is entered on device */
-        KEYPAD,
-        /* Label pin method configuration - pin is obtained from a printed label */
-        LABEL,
-        /* Invalid config */
-        INVALID
-    }
-
-    public Setup setup;
+    public int setup;
 
     /** @hide */
     public String BSSID;
@@ -63,8 +60,8 @@
     /** @hide */
     public LinkProperties linkProperties;
 
-    public Wps() {
-        setup = Setup.INVALID;
+    public WpsInfo() {
+        setup = INVALID;
         BSSID = null;
         pin = null;
         ipAssignment = IpAssignment.UNASSIGNED;
@@ -72,10 +69,9 @@
         linkProperties = new LinkProperties();
     }
 
-    /** @hide */
     public String toString() {
         StringBuffer sbuf = new StringBuffer();
-        sbuf.append(" setup: ").append(setup.toString());
+        sbuf.append(" setup: ").append(setup);
         sbuf.append('\n');
         sbuf.append(" BSSID: ").append(BSSID);
         sbuf.append('\n');
@@ -90,13 +86,13 @@
         return sbuf.toString();
     }
 
-    /** Implement the Parcelable interface {@hide} */
+    /** Implement the Parcelable interface */
     public int describeContents() {
         return 0;
     }
 
-    /** copy constructor {@hide} */
-    public Wps(Wps source) {
+    /* Copy constructor */
+    public WpsInfo(WpsInfo source) {
         if (source != null) {
             setup = source.setup;
             BSSID = source.BSSID;
@@ -107,9 +103,9 @@
         }
     }
 
-    /** Implement the Parcelable interface {@hide} */
+    /** Implement the Parcelable interface */
     public void writeToParcel(Parcel dest, int flags) {
-        dest.writeString(setup.name());
+        dest.writeInt(setup);
         dest.writeString(BSSID);
         dest.writeString(pin);
         dest.writeString(ipAssignment.name());
@@ -117,12 +113,12 @@
         dest.writeParcelable(linkProperties, flags);
     }
 
-    /** Implement the Parcelable interface {@hide} */
-    public static final Creator<Wps> CREATOR =
-        new Creator<Wps>() {
-            public Wps createFromParcel(Parcel in) {
-                Wps config = new Wps();
-                config.setup = Setup.valueOf(in.readString());
+    /** Implement the Parcelable interface */
+    public static final Creator<WpsInfo> CREATOR =
+        new Creator<WpsInfo>() {
+            public WpsInfo createFromParcel(Parcel in) {
+                WpsInfo config = new WpsInfo();
+                config.setup = in.readInt();
                 config.BSSID = in.readString();
                 config.pin = in.readString();
                 config.ipAssignment = IpAssignment.valueOf(in.readString());
@@ -131,8 +127,8 @@
                 return config;
             }
 
-            public Wps[] newArray(int size) {
-                return new Wps[size];
+            public WpsInfo[] newArray(int size) {
+                return new WpsInfo[size];
             }
         };
 }
diff --git a/wifi/java/android/net/wifi/WpsStateMachine.java b/wifi/java/android/net/wifi/WpsStateMachine.java
index f9e903a..c14a8db 100644
--- a/wifi/java/android/net/wifi/WpsStateMachine.java
+++ b/wifi/java/android/net/wifi/WpsStateMachine.java
@@ -53,7 +53,7 @@
 
     private WifiStateMachine mWifiStateMachine;
 
-    private Wps mWpsConfig;
+    private WpsInfo mWpsInfo;
 
     private Context mContext;
     AsyncChannel mReplyChannel = new AsyncChannel();
@@ -90,20 +90,20 @@
         @Override
         public boolean processMessage(Message message) {
             if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
-            Wps wpsConfig;
+            WpsInfo wpsConfig;
             switch (message.what) {
                 case WifiStateMachine.CMD_START_WPS:
-                    mWpsConfig = (Wps) message.obj;
+                    mWpsInfo = (WpsInfo) message.obj;
                     WpsResult result;
-                    switch (mWpsConfig.setup) {
-                        case PBC:
-                            result = WifiConfigStore.startWpsPbc(mWpsConfig);
+                    switch (mWpsInfo.setup) {
+                        case WpsInfo.PBC:
+                            result = WifiConfigStore.startWpsPbc(mWpsInfo);
                             break;
-                        case KEYPAD:
-                            result = WifiConfigStore.startWpsWithPinFromAccessPoint(mWpsConfig);
+                        case WpsInfo.KEYPAD:
+                            result = WifiConfigStore.startWpsWithPinFromAccessPoint(mWpsInfo);
                             break;
-                        case DISPLAY:
-                            result = WifiConfigStore.startWpsWithPinFromDevice(mWpsConfig);
+                        case WpsInfo.DISPLAY:
+                            result = WifiConfigStore.startWpsWithPinFromDevice(mWpsInfo);
                             break;
                         default:
                             result = new WpsResult(Status.FAILURE);
@@ -114,7 +114,7 @@
                     if (result.status == Status.SUCCESS) {
                         transitionTo(mActiveState);
                     } else {
-                        Log.e(TAG, "Failed to start WPS with config " + mWpsConfig.toString());
+                        Log.e(TAG, "Failed to start WPS with config " + mWpsInfo.toString());
                     }
                     break;
                 case WifiStateMachine.CMD_RESET_WPS_STATE:
@@ -154,7 +154,7 @@
                             WifiConfigStore.enableAllNetworks();
                             WifiConfigStore.loadConfiguredNetworks();
                             WifiConfigStore.updateIpAndProxyFromWpsConfig(
-                                    stateChangeResult.networkId, mWpsConfig);
+                                    stateChangeResult.networkId, mWpsInfo);
                             mWifiStateMachine.sendMessage(WifiStateMachine.WPS_COMPLETED_EVENT);
                             transitionTo(mInactiveState);
                             break;
diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pConfig.java b/wifi/java/android/net/wifi/p2p/WifiP2pConfig.java
index e359ce5..e0c1b13 100644
--- a/wifi/java/android/net/wifi/p2p/WifiP2pConfig.java
+++ b/wifi/java/android/net/wifi/p2p/WifiP2pConfig.java
@@ -16,14 +16,12 @@
 
 package android.net.wifi.p2p;
 
-import android.net.wifi.Wps;
-import android.net.wifi.Wps.Setup;
+import android.net.wifi.WpsInfo;
 import android.os.Parcelable;
 import android.os.Parcel;
 
 /**
  * A class representing a Wi-Fi P2p configuration for setting up a connection
- * @hide
  *
  * {@see WifiP2pManager}
  */
@@ -37,7 +35,7 @@
     /**
      * Wi-Fi Protected Setup information
      */
-    public Wps wps;
+    public WpsInfo wps;
 
     /**
      * This is an integer value between 0 and 15 where 0 indicates the least
@@ -63,8 +61,8 @@
 
     public WifiP2pConfig() {
         //set defaults
-        wps = new Wps();
-        wps.setup = Setup.PBC;
+        wps = new WpsInfo();
+        wps.setup = WpsInfo.PBC;
     }
 
     /** P2P-GO-NEG-REQUEST 42:fc:89:a8:96:09 dev_passwd_id=4 {@hide}*/
@@ -76,7 +74,7 @@
         }
 
         deviceAddress = tokens[1];
-        wps = new Wps();
+        wps = new WpsInfo();
 
         if (tokens.length > 2) {
             String[] nameVal = tokens[2].split("=");
@@ -89,25 +87,24 @@
             //As defined in wps/wps_defs.h
             switch (devPasswdId) {
                 case 0x00:
-                    wps.setup = Setup.LABEL;
+                    wps.setup = WpsInfo.LABEL;
                     break;
                 case 0x01:
-                    wps.setup = Setup.KEYPAD;
+                    wps.setup = WpsInfo.KEYPAD;
                     break;
                 case 0x04:
-                    wps.setup = Setup.PBC;
+                    wps.setup = WpsInfo.PBC;
                     break;
                 case 0x05:
-                    wps.setup = Setup.DISPLAY;
+                    wps.setup = WpsInfo.DISPLAY;
                     break;
                 default:
-                    wps.setup = Setup.PBC;
+                    wps.setup = WpsInfo.PBC;
                     break;
             }
         }
     }
 
-    /** @hide */
     public String toString() {
         StringBuffer sbuf = new StringBuffer();
         sbuf.append("\n address: ").append(deviceAddress);
@@ -117,19 +114,22 @@
         return sbuf.toString();
     }
 
-    /** Implement the Parcelable interface {@hide} */
+    /** Implement the Parcelable interface */
     public int describeContents() {
         return 0;
     }
 
-    /** copy constructor {@hide} */
+    /** copy constructor */
     public WifiP2pConfig(WifiP2pConfig source) {
         if (source != null) {
-            //TODO: implement
-       }
+            deviceAddress = source.deviceAddress;
+            wps = new WpsInfo(source.wps);
+            groupOwnerIntent = source.groupOwnerIntent;
+            persist = source.persist;
+        }
     }
 
-    /** Implement the Parcelable interface {@hide} */
+    /** Implement the Parcelable interface */
     public void writeToParcel(Parcel dest, int flags) {
         dest.writeString(deviceAddress);
         dest.writeParcelable(wps, flags);
@@ -137,13 +137,13 @@
         dest.writeString(persist.name());
     }
 
-    /** Implement the Parcelable interface {@hide} */
+    /** Implement the Parcelable interface */
     public static final Creator<WifiP2pConfig> CREATOR =
         new Creator<WifiP2pConfig>() {
             public WifiP2pConfig createFromParcel(Parcel in) {
                 WifiP2pConfig config = new WifiP2pConfig();
                 config.deviceAddress = in.readString();
-                config.wps = (Wps) in.readParcelable(null);
+                config.wps = (WpsInfo) in.readParcelable(null);
                 config.groupOwnerIntent = in.readInt();
                 config.persist = Persist.valueOf(in.readString());
                 return config;
diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pDevice.java b/wifi/java/android/net/wifi/p2p/WifiP2pDevice.java
index 99c585f..1b0c301 100644
--- a/wifi/java/android/net/wifi/p2p/WifiP2pDevice.java
+++ b/wifi/java/android/net/wifi/p2p/WifiP2pDevice.java
@@ -24,7 +24,6 @@
 
 /**
  * A class representing a Wi-Fi p2p device
- * @hide
  *
  * {@see WifiP2pManager}
  */
@@ -109,18 +108,16 @@
      */
     public int groupCapability;
 
+    public static final int CONNECTED   = 0;
+    public static final int INVITED     = 1;
+    public static final int FAILED      = 2;
+    public static final int AVAILABLE   = 3;
+    public static final int UNAVAILABLE = 4;
+
     /** Device connection status */
-    public enum Status {
-        CONNECTED,
-        INVITED,
-        FAILED,
-        AVAILABLE,
-        UNAVAILABLE,
-    }
+    public int status = UNAVAILABLE;
 
-    public Status status = Status.UNAVAILABLE;
-
-    WifiP2pDevice() {
+    public WifiP2pDevice() {
     }
 
     /**
@@ -197,7 +194,7 @@
         }
 
         if (tokens[0].startsWith("P2P-DEVICE-FOUND")) {
-            status = Status.AVAILABLE;
+            status = AVAILABLE;
         }
     }
 
@@ -227,7 +224,6 @@
     }
 
     @Override
-    /** @hide */
     public boolean equals(Object obj) {
         if (this == obj) return true;
         if (!(obj instanceof WifiP2pDevice)) return false;
@@ -239,7 +235,6 @@
         return other.deviceAddress.equals(deviceAddress);
     }
 
-    /** @hide */
     public String toString() {
         StringBuffer sbuf = new StringBuffer();
         sbuf.append("Device: ").append(deviceName);
@@ -254,12 +249,12 @@
         return sbuf.toString();
     }
 
-    /** Implement the Parcelable interface {@hide} */
+    /** Implement the Parcelable interface */
     public int describeContents() {
         return 0;
     }
 
-    /** copy constructor {@hide} */
+    /** copy constructor */
     public WifiP2pDevice(WifiP2pDevice source) {
         if (source != null) {
             deviceName = source.deviceName;
@@ -274,7 +269,7 @@
         }
     }
 
-    /** Implement the Parcelable interface {@hide} */
+    /** Implement the Parcelable interface */
     public void writeToParcel(Parcel dest, int flags) {
         dest.writeString(deviceName);
         dest.writeString(deviceAddress);
@@ -284,10 +279,10 @@
         dest.writeInt(wpsConfigMethodsSupported);
         dest.writeInt(deviceCapability);
         dest.writeInt(groupCapability);
-        dest.writeString(status.name());
+        dest.writeInt(status);
     }
 
-    /** Implement the Parcelable interface {@hide} */
+    /** Implement the Parcelable interface */
     public static final Creator<WifiP2pDevice> CREATOR =
         new Creator<WifiP2pDevice>() {
             public WifiP2pDevice createFromParcel(Parcel in) {
@@ -300,7 +295,7 @@
                 device.wpsConfigMethodsSupported = in.readInt();
                 device.deviceCapability = in.readInt();
                 device.groupCapability = in.readInt();
-                device.status = Status.valueOf(in.readString());
+                device.status = in.readInt();
                 return device;
             }
 
diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pDeviceList.java b/wifi/java/android/net/wifi/p2p/WifiP2pDeviceList.java
index 242bce0..9ce2545 100644
--- a/wifi/java/android/net/wifi/p2p/WifiP2pDeviceList.java
+++ b/wifi/java/android/net/wifi/p2p/WifiP2pDeviceList.java
@@ -27,7 +27,6 @@
 
 /**
  * A class representing a Wi-Fi P2p device list
- * @hide
  *
  * {@see WifiP2pManager}
  */
@@ -35,11 +34,11 @@
 
     private Collection<WifiP2pDevice> mDevices;
 
-    WifiP2pDeviceList() {
+    public WifiP2pDeviceList() {
         mDevices = new ArrayList<WifiP2pDevice>();
     }
 
-    /** copy constructor {@hide} */
+    /** copy constructor */
     public WifiP2pDeviceList(WifiP2pDeviceList source) {
         if (source != null) {
             mDevices = source.getDeviceList();
@@ -91,7 +90,6 @@
         return Collections.unmodifiableCollection(mDevices);
     }
 
-    /** @hide */
     public String toString() {
         StringBuffer sbuf = new StringBuffer();
         for (WifiP2pDevice device : mDevices) {
@@ -100,12 +98,12 @@
         return sbuf.toString();
     }
 
-    /** Implement the Parcelable interface {@hide} */
+    /** Implement the Parcelable interface */
     public int describeContents() {
         return 0;
     }
 
-    /** Implement the Parcelable interface {@hide} */
+    /** Implement the Parcelable interface */
     public void writeToParcel(Parcel dest, int flags) {
         dest.writeInt(mDevices.size());
         for(WifiP2pDevice device : mDevices) {
@@ -113,7 +111,7 @@
         }
     }
 
-    /** Implement the Parcelable interface {@hide} */
+    /** Implement the Parcelable interface */
     public static final Creator<WifiP2pDeviceList> CREATOR =
         new Creator<WifiP2pDeviceList>() {
             public WifiP2pDeviceList createFromParcel(Parcel in) {
diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pGroup.java b/wifi/java/android/net/wifi/p2p/WifiP2pGroup.java
index 48f210b..9473993 100644
--- a/wifi/java/android/net/wifi/p2p/WifiP2pGroup.java
+++ b/wifi/java/android/net/wifi/p2p/WifiP2pGroup.java
@@ -26,7 +26,6 @@
 
 /**
  * A class representing a Wi-Fi P2p group
- * @hide
  *
  * {@see WifiP2pManager}
  */
@@ -49,7 +48,7 @@
 
     private String mInterface;
 
-    WifiP2pGroup() {
+    public WifiP2pGroup() {
     }
 
     /**
@@ -202,7 +201,6 @@
         return mInterface;
     }
 
-    /** @hide */
     public String toString() {
         StringBuffer sbuf = new StringBuffer();
         sbuf.append("network: ").append(mNetworkName);
@@ -215,19 +213,24 @@
         return sbuf.toString();
     }
 
-    /** Implement the Parcelable interface {@hide} */
+    /** Implement the Parcelable interface */
     public int describeContents() {
         return 0;
     }
 
-    /** copy constructor {@hide} */
-    // TODO: implement
+    /** copy constructor */
     public WifiP2pGroup(WifiP2pGroup source) {
         if (source != null) {
-       }
+            mNetworkName = source.getNetworkName();
+            mOwner = new WifiP2pDevice(source.getOwner());
+            mIsGroupOwner = source.mIsGroupOwner;
+            for (WifiP2pDevice d : source.getClientList()) mClients.add(d);
+            mPassphrase = source.getPassphrase();
+            mInterface = source.getInterface();
+        }
     }
 
-    /** Implement the Parcelable interface {@hide} */
+    /** Implement the Parcelable interface */
     public void writeToParcel(Parcel dest, int flags) {
         dest.writeString(mNetworkName);
         dest.writeParcelable(mOwner, flags);
@@ -240,7 +243,7 @@
         dest.writeString(mInterface);
     }
 
-    /** Implement the Parcelable interface {@hide} */
+    /** Implement the Parcelable interface */
     public static final Creator<WifiP2pGroup> CREATOR =
         new Creator<WifiP2pGroup>() {
             public WifiP2pGroup createFromParcel(Parcel in) {
diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pInfo.java b/wifi/java/android/net/wifi/p2p/WifiP2pInfo.java
index 81b7708..dce315a 100644
--- a/wifi/java/android/net/wifi/p2p/WifiP2pInfo.java
+++ b/wifi/java/android/net/wifi/p2p/WifiP2pInfo.java
@@ -24,7 +24,6 @@
 
 /**
  * A class representing connection information about a Wi-Fi p2p group
- * @hide
  *
  * {@see WifiP2pManager}
  */
@@ -39,11 +38,9 @@
     /** Group owner address */
     public InetAddress groupOwnerAddress;
 
-    /** @hide */
-    WifiP2pInfo() {
+    public WifiP2pInfo() {
     }
 
-    /** @hide */
     public String toString() {
         StringBuffer sbuf = new StringBuffer();
         sbuf.append("groupFormed: ").append(groupFormed)
@@ -52,12 +49,12 @@
         return sbuf.toString();
     }
 
-    /** Implement the Parcelable interface {@hide} */
+    /** Implement the Parcelable interface */
     public int describeContents() {
         return 0;
     }
 
-    /** copy constructor {@hide} */
+    /** copy constructor */
     public WifiP2pInfo(WifiP2pInfo source) {
         if (source != null) {
             groupFormed = source.groupFormed;
@@ -66,7 +63,7 @@
        }
     }
 
-    /** Implement the Parcelable interface {@hide} */
+    /** Implement the Parcelable interface */
     public void writeToParcel(Parcel dest, int flags) {
         dest.writeByte(groupFormed ? (byte)1 : (byte)0);
         dest.writeByte(isGroupOwner ? (byte)1 : (byte)0);
@@ -79,7 +76,7 @@
         }
     }
 
-    /** Implement the Parcelable interface {@hide} */
+    /** Implement the Parcelable interface */
     public static final Creator<WifiP2pInfo> CREATOR =
         new Creator<WifiP2pInfo>() {
             public WifiP2pInfo createFromParcel(Parcel in) {
diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pManager.java b/wifi/java/android/net/wifi/p2p/WifiP2pManager.java
index 5715186..9205300 100644
--- a/wifi/java/android/net/wifi/p2p/WifiP2pManager.java
+++ b/wifi/java/android/net/wifi/p2p/WifiP2pManager.java
@@ -24,6 +24,7 @@
 import android.os.Binder;
 import android.os.IBinder;
 import android.os.Handler;
+import android.os.Looper;
 import android.os.Message;
 import android.os.RemoteException;
 import android.os.ServiceManager;
@@ -34,36 +35,44 @@
 import com.android.internal.util.AsyncChannel;
 import com.android.internal.util.Protocol;
 
+import java.util.HashMap;
+
 /**
  * This class provides the API for managing Wi-Fi peer-to-peer connectivity. This lets an
  * application discover available peers, setup connection to peers and query for the list of peers.
  * When a p2p connection is formed over wifi, the device continues to maintain the uplink
  * connection over mobile or any other available network for internet connectivity on the device.
  *
- * <p> The API is asynchronous and response to a request from an application is sent in the form
- * of a {@link android.os.Message} on a {@link android.os.Handler} that needs to be initialized
- * by the application right at the beginning before any p2p operations are performed via
- * {@link #initialize}.
+ * <p> The API is asynchronous and responses to requests from an application are on listener
+ * callbacks provided by the application. The application needs to do an initialization with
+ * {@link #initialize} before doing any p2p operation.
  *
- * <p> An application can request for the current list of peers using {@link #requestPeers}. The
- * {@link #RESPONSE_PEERS} message on the handler indicates that the peer list is available.
- * Use {@link #peersInResponse} to extract the peer device list upon the receiving the
- * {@link #RESPONSE_PEERS} message.
+ * <p> Application actions {@link #discoverPeers}, {@link #connect}, {@link #cancelConnect},
+ * {@link #createGroup} and {@link #removeGroup} need a {@link ActionListener} instance for
+ * receiving callbacks {@link ActionListener#onSuccess} or {@link ActionListener#onFailure}.
+ * Action callbacks indicate whether the initiation of the action was a success or a failure.
+ * Upon failure, the reason of failure can be one of {@link #ERROR}, {@link #P2P_UNSUPPORTED}
+ * or {@link #BUSY}.
  *
- * <p> If an application needs to initiate a discovery, use {@link #discoverPeers} and listen
- * to {@link #WIFI_P2P_PEERS_CHANGED_ACTION} intent action to initiate a request to fetch
- * list of peers with {@link #requestPeers}. An initiated discovery request from an application
- * stays active until the device starts connecting to a peer or forms a p2p group.
+ * <p> An application can initiate discovery of peers with {@link #discoverPeers}. An initiated
+ * discovery request from an application stays active until the device starts connecting to a peer
+ * or forms a p2p group. The {@link ActionListener} callbacks provide feedback on whether the
+ * discovery initiation was successful or failure. Additionally, applications can listen
+ * to {@link #WIFI_P2P_PEERS_CHANGED_ACTION} intent action to know when the peer list changes.
+ *
+ * <p> When the peer list change intent {@link #WIFI_P2P_PEERS_CHANGED_ACTION} is received
+ * or when an application needs to fetch the current list of peers, it can request the list
+ * of peers with {@link #requestPeers}. When the peer list is available
+ * {@link PeerListListener#onPeersAvailable} is called with the device list.
  *
  * <p> An application can initiate a connection request to a peer through {@link #connect}. See
  * {@link WifiP2pConfig} for details on setting up the configuration. For communication with legacy
  * Wi-Fi devices that do not support p2p, an app can create a group using {@link #createGroup}
  * which creates an access point whose details can be fetched with {@link #requestGroupInfo}.
- *
+*
  * <p> After a successful group formation through {@link #createGroup} or through {@link #connect},
- * use {@link #requestConnectionInfo} to fetch the connection details. Connection information
- * can be obtained with {@link #connectionInfoInResponse} on a {@link #RESPONSE_CONNECTION_INFO}
- * message. The connection info {@link WifiP2pInfo} contains the address of the group owner
+ * use {@link #requestConnectionInfo} to fetch the connection details. The connection info
+ * {@link WifiP2pInfo} contains the address of the group owner
  * {@link WifiP2pInfo#groupOwnerAddress} and a flag {@link WifiP2pInfo#isGroupOwner} to indicate
  * if the current device is a p2p group owner. A p2p client can thus communicate with
  * the p2p group owner through a socket connection.
@@ -85,10 +94,10 @@
  * {@see WifiP2pGroup}
  * {@see WifiP2pDevice}
  * {@see WifiP2pDeviceList}
- * {@see android.net.wifi.Wps}
- * @hide
+ * {@see android.net.wifi.WpsInfo}
  */
 public class WifiP2pManager {
+    private static final String TAG = "WifiP2pManager";
     /**
      * Broadcast intent action to indicate whether Wi-Fi p2p is enabled or disabled. An
      * extra {@link #EXTRA_WIFI_STATE} provides the state information as int.
@@ -97,7 +106,7 @@
      */
     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
     public static final String WIFI_P2P_STATE_CHANGED_ACTION =
-        "android.net.wifi.P2P_STATE_CHANGED";
+        "android.net.wifi.p2p.STATE_CHANGED";
 
     /**
      * The lookup key for an int that indicates whether Wi-Fi p2p is enabled or disabled.
@@ -133,7 +142,7 @@
      */
     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
     public static final String WIFI_P2P_CONNECTION_CHANGED_ACTION =
-        "android.net.wifi.CONNECTION_STATE_CHANGE";
+        "android.net.wifi.p2p.CONNECTION_STATE_CHANGE";
 
     /**
      * The lookup key for a {@link android.net.wifi.p2p.WifiP2pInfo} object
@@ -170,27 +179,23 @@
      */
     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
     public static final String WIFI_P2P_PEERS_CHANGED_ACTION =
-        "android.net.wifi.PEERS_CHANGED";
+        "android.net.wifi.p2p.PEERS_CHANGED";
 
     /**
-     * Activity Action: Pick a Wi-Fi p2p network to connect to.
-     * <p>Input: Nothing.
-     * <p>Output: Nothing.
-     * @hide
+     * Broadcast intent action indicating that this device details have changed.
      */
-    @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
-    public static final String ACTION_PICK_WIFI_P2P_NETWORK =
-        "android.net.wifi.PICK_WIFI_P2P_NETWORK";
+    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+    public static final String WIFI_P2P_THIS_DEVICE_CHANGED_ACTION =
+        "android.net.wifi.p2p.THIS_DEVICE_CHANGED";
+
+    /**
+     * The lookup key for a {@link android.net.wifi.p2p.WifiP2pDevice} object
+     * Retrieve with {@link android.content.Intent#getParcelableExtra(String)}.
+     */
+    public static final String EXTRA_WIFI_P2P_DEVICE = "wifiP2pDevice";
 
     IWifiP2pManager mService;
 
-    /**
-     * Message {@link android.os.Message#what} sent on the application handler specified
-     * at {@link #initialize} indicating the asynchronous channel has disconnected. An
-     * application could choose to reconnect with {@link #initialize}
-     */
-    public static final int HANDLER_DISCONNECTION = AsyncChannel.CMD_CHANNEL_DISCONNECTED;
-
     private static final int BASE = Protocol.BASE_WIFI_P2P_MANAGER;
 
     /** @hide */
@@ -209,150 +214,59 @@
 
     /** @hide */
     public static final int DISCOVER_PEERS                          = BASE + 7;
-
-    /**
-     * Message {@link android.os.Message#what} value indicating that the {@link #discoverPeers}
-     * operation failed.
-     * <p> The reason for failure could be one of {@link #P2P_UNSUPPORTED}, {@link #ERROR}
-     * or {@link #BUSY}
-     */
+    /** @hide */
     public static final int DISCOVER_PEERS_FAILED                   = BASE + 8;
-    /**
-     * Message {@link android.os.Message#what} value indicating that the {@link #discoverPeers}
-     * operation succeeded.
-     * <p> The application can register for {@link #WIFI_P2P_PEERS_CHANGED_ACTION} intent
-     * to listen for changes in the peer list as a result of the discovery process.
-     */
+    /** @hide */
     public static final int DISCOVER_PEERS_SUCCEEDED                = BASE + 9;
 
     /** @hide */
     public static final int CONNECT                                 = BASE + 10;
-
-    /**
-     * Message {@link android.os.Message#what} value indicating that the {@link #connect}
-     * operation failed.
-     * <p> The reason for failure could be one of {@link #P2P_UNSUPPORTED}, {@link #ERROR}
-     * or {@link #BUSY}
-     */
+    /** @hide */
     public static final int CONNECT_FAILED                          = BASE + 11;
-    /**
-     * Message {@link android.os.Message#what} value indicating that the {@link #connect}
-     * operation succeeded.
-     * <p> The application can register for {@link #WIFI_P2P_CONNECTION_CHANGED_ACTION} intent
-     * to listen for connectivity change as a result of the connect operation
-     */
+    /** @hide */
     public static final int CONNECT_SUCCEEDED                       = BASE + 12;
 
     /** @hide */
-    public static final int CREATE_GROUP                            = BASE + 13;
-
-    /**
-     * Message {@link android.os.Message#what} value indicating that the {@link #createGroup}
-     * operation failed.
-     * <p> The reason for failure could be one of {@link #P2P_UNSUPPORTED}, {@link #ERROR}
-     * or {@link #BUSY}
-     */
-    public static final int CREATE_GROUP_FAILED                     = BASE + 14;
-    /**
-     * Message {@link android.os.Message#what} value indicating that the {@link #createGroup}
-     * operation succeeded.
-     * <p> The application can request the group details with {@link #requestGroupInfo}
-     */
-    public static final int CREATE_GROUP_SUCCEEDED                  = BASE + 15;
+    public static final int CANCEL_CONNECT                          = BASE + 13;
+    /** @hide */
+    public static final int CANCEL_CONNECT_FAILED                   = BASE + 14;
+    /** @hide */
+    public static final int CANCEL_CONNECT_SUCCEEDED                = BASE + 15;
 
     /** @hide */
-    public static final int REMOVE_GROUP                            = BASE + 16;
-    /**
-     * Message {@link android.os.Message#what} value indicating that the {@link #removeGroup}
-     * operation failed.
-     * <p> The reason for failure could be one of {@link #P2P_UNSUPPORTED}, {@link #ERROR}
-     * or {@link #BUSY}
-     */
-    public static final int REMOVE_GROUP_FAILED                     = BASE + 17;
-    /**
-     * Message {@link android.os.Message#what} value indicating that the {@link #removeGroup}
-     * operation succeeded.
-     */
-    public static final int REMOVE_GROUP_SUCCEEDED                  = BASE + 18;
-
-    /**
-     * Supported {@link android.os.Message#arg1} value on the following response messages:
-     * {@link #DISCOVER_PEERS_FAILED}, {@link #CONNECT_FAILED}, {@link #CREATE_GROUP_FAILED}
-     * and {@link #REMOVE_GROUP_FAILED}
-     *
-     * <p> This indicates that the operation failed due to an internal error
-     */
-    public static final int ERROR               = 0;
-
-    /**
-     * Supported {@link android.os.Message#arg1} value on the following response messages:
-     * {@link #DISCOVER_PEERS_FAILED}, {@link #CONNECT_FAILED}, {@link #CREATE_GROUP_FAILED}
-     * and {@link #REMOVE_GROUP_FAILED}
-     *
-     * <p> This indicates that the operation failed because p2p is unsupported on the
-     * device
-     */
-    public static final int P2P_UNSUPPORTED     = 1;
-
-    /**
-     * Supported {@link android.os.Message#arg1} value on the following response messages:
-     * {@link #DISCOVER_PEERS_FAILED}, {@link #CONNECT_FAILED}, {@link #CREATE_GROUP_FAILED}
-     * and {@link #REMOVE_GROUP_FAILED}
-     *
-     * <p> This indicates that the operation failed because the framework is busy and
-     * unable to service the request
-     */
-    public static final int BUSY                = 2;
+    public static final int CREATE_GROUP                            = BASE + 16;
+    /** @hide */
+    public static final int CREATE_GROUP_FAILED                     = BASE + 17;
+    /** @hide */
+    public static final int CREATE_GROUP_SUCCEEDED                  = BASE + 18;
 
     /** @hide */
-    public static final int REQUEST_PEERS                           = BASE + 19;
-    /**
-     * Message {@link android.os.Message#what} delivered on the application hander
-     * in response to a {@link #requestPeers} call from the application.
-     *
-     * <p> Extract a {@link WifiP2pDeviceList} object by calling {@link #peersInResponse}
-     * on the message object
-     */
-    public static final int RESPONSE_PEERS                          = BASE + 20;
+    public static final int REMOVE_GROUP                            = BASE + 19;
+    /** @hide */
+    public static final int REMOVE_GROUP_FAILED                     = BASE + 20;
+    /** @hide */
+    public static final int REMOVE_GROUP_SUCCEEDED                  = BASE + 21;
 
     /** @hide */
-    public static final int REQUEST_CONNECTION_INFO                 = BASE + 21;
-
-    /**
-     * Message {@link android.os.Message#what} delivered on the application hander
-     * in response to a {@link #requestConnectionInfo} call from the application.
-     *
-     * <p> Extract a {@link WifiP2pInfo} object by calling {@link #connectionInfoInResponse}
-     * on the message object
-     */
-    public static final int RESPONSE_CONNECTION_INFO                = BASE + 22;
+    public static final int REQUEST_PEERS                           = BASE + 22;
+    /** @hide */
+    public static final int RESPONSE_PEERS                          = BASE + 23;
 
     /** @hide */
-    public static final int REQUEST_GROUP_INFO                      = BASE + 23;
-
-    /**
-     * Message {@link android.os.Message#what} delivered on the application hander
-     * in response to a {@link #requestGroupInfo} call from the application.
-     *
-     * <p> Extract a {@link WifiP2pGroup} object by calling {@link #groupInfoInResponse}
-     * on the message object
-     */
-
-    public static final int RESPONSE_GROUP_INFO                     = BASE + 24;
+    public static final int REQUEST_CONNECTION_INFO                 = BASE + 24;
+    /** @hide */
+    public static final int RESPONSE_CONNECTION_INFO                = BASE + 25;
 
     /** @hide */
-    public static final int WPS_PBC                                 = BASE + 25;
+    public static final int REQUEST_GROUP_INFO                      = BASE + 26;
     /** @hide */
-    public static final int WPS_PIN                                 = BASE + 26;
-    /** @hide */
-    public static final int WPS_PIN_AVAILABLE                       = BASE + 27;
+    public static final int RESPONSE_GROUP_INFO                     = BASE + 27;
 
     /**
      * Create a new WifiP2pManager instance. Applications use
      * {@link android.content.Context#getSystemService Context.getSystemService()} to retrieve
      * the standard {@link android.content.Context#WIFI_P2P_SERVICE Context.WIFI_P2P_SERVICE}.
      * @param service the Binder interface
-     * @param handler target for messages
      * @hide - hide this because it takes in a parameter of type IWifiP2pManager, which
      * is a system private class.
      */
@@ -361,38 +275,182 @@
     }
 
     /**
-     * A channel that connects the application handler to the Wifi framework.
-     * Most p2p operations require a Channel as an argument. An instance of Channel is obtained
-     * by doing a call on {@link #initialize}
+     * Passed with {@link ActionListener#onFailure}.
+     * Indicates that the operation failed due to an internal error.
      */
-    public class Channel {
-        Channel(AsyncChannel c) {
-            mAsyncChannel = c;
-        }
-        AsyncChannel mAsyncChannel;
+    public static final int ERROR               = 0;
+
+    /**
+     * Passed with {@link ActionListener#onFailure}.
+     * Indicates that the operation failed because p2p is unsupported on the device.
+     */
+    public static final int P2P_UNSUPPORTED     = 1;
+
+    /**
+     * Passed with {@link ActionListener#onFailure}.
+     * Indicates that the operation failed because the framework is busy and
+     * unable to service the request
+     */
+    public static final int BUSY                = 2;
+
+    /** Interface for callback invocation when framework channel is lost */
+    public interface ChannelListener {
+        /**
+         * The channel to the framework has been disconnected.
+         * Application could try re-initializing using {@link #initialize}
+         */
+        public void onChannelDisconnected();
+    }
+
+    /** Interface for callback invocation on an application action */
+    public interface ActionListener {
+        /** The operation succeeded */
+        public void onSuccess();
+        /**
+         * The operation failed
+         * @param reason The reason for failure could be one of {@link #P2P_UNSUPPORTED},
+         * {@link #ERROR} or {@link #BUSY}
+         */
+        public void onFailure(int reason);
+    }
+
+    /** Interface for callback invocation when peer list is available */
+    public interface PeerListListener {
+        /**
+         * The requested peer list is available
+         * @param peers List of available peers
+         */
+        public void onPeersAvailable(WifiP2pDeviceList peers);
+    }
+
+    /** Interface for callback invocation when connection info is available */
+    public interface ConnectionInfoListener {
+        /**
+         * The requested connection info is available
+         * @param info Wi-Fi p2p connection info
+         */
+        public void onConnectionInfoAvailable(WifiP2pInfo info);
+    }
+
+    /** Interface for callback invocation when group info is available */
+    public interface GroupInfoListener {
+        /**
+         * The requested p2p group info is available
+         * @param group Wi-Fi p2p group info
+         */
+        public void onGroupInfoAvailable(WifiP2pGroup group);
     }
 
     /**
-     * Registers the application handler with the Wi-Fi framework. This function
+     * A channel that connects the application to the Wifi p2p framework.
+     * Most p2p operations require a Channel as an argument. An instance of Channel is obtained
+     * by doing a call on {@link #initialize}
+     */
+    public static class Channel {
+        Channel(Looper looper, ChannelListener l) {
+            mAsyncChannel = new AsyncChannel();
+            mHandler = new P2pHandler(looper);
+            mChannelListener = l;
+        }
+        private ChannelListener mChannelListener;
+        private HashMap<Integer, Object> mListenerMap = new HashMap<Integer, Object>();
+        private Object mListenerMapLock = new Object();
+        private int mListenerKey = 0;
+
+        AsyncChannel mAsyncChannel;
+        P2pHandler mHandler;
+        class P2pHandler extends Handler {
+            P2pHandler(Looper looper) {
+                super(looper);
+            }
+
+            @Override
+            public void handleMessage(Message message) {
+                Object listener = getListener(message.arg2);
+                switch (message.what) {
+                    case AsyncChannel.CMD_CHANNEL_DISCONNECTED:
+                        if (mChannelListener != null) {
+                            mChannelListener.onChannelDisconnected();
+                            mChannelListener = null;
+                        }
+                        break;
+                    /* ActionListeners grouped together */
+                    case WifiP2pManager.DISCOVER_PEERS_FAILED:
+                    case WifiP2pManager.CONNECT_FAILED:
+                    case WifiP2pManager.CANCEL_CONNECT_FAILED:
+                    case WifiP2pManager.CREATE_GROUP_FAILED:
+                    case WifiP2pManager.REMOVE_GROUP_FAILED:
+                        if (listener != null) {
+                            ((ActionListener) listener).onFailure(message.arg1);
+                        }
+                        break;
+                    /* ActionListeners grouped together */
+                    case WifiP2pManager.DISCOVER_PEERS_SUCCEEDED:
+                    case WifiP2pManager.CONNECT_SUCCEEDED:
+                    case WifiP2pManager.CANCEL_CONNECT_SUCCEEDED:
+                    case WifiP2pManager.CREATE_GROUP_SUCCEEDED:
+                    case WifiP2pManager.REMOVE_GROUP_SUCCEEDED:
+                        if (listener != null) {
+                            ((ActionListener) listener).onSuccess();
+                        }
+                        break;
+                    case WifiP2pManager.RESPONSE_PEERS:
+                        WifiP2pDeviceList peers = (WifiP2pDeviceList) message.obj;
+                        if (listener != null) {
+                            ((PeerListListener) listener).onPeersAvailable(peers);
+                        }
+                        break;
+                    case WifiP2pManager.RESPONSE_CONNECTION_INFO:
+                        WifiP2pInfo wifiP2pInfo = (WifiP2pInfo) message.obj;
+                        if (listener != null) {
+                            ((ConnectionInfoListener) listener).onConnectionInfoAvailable(wifiP2pInfo);
+                        }
+                        break;
+                    case WifiP2pManager.RESPONSE_GROUP_INFO:
+                        WifiP2pGroup group = (WifiP2pGroup) message.obj;
+                        if (listener != null) {
+                            ((GroupInfoListener) listener).onGroupInfoAvailable(group);
+                        }
+                        break;
+                   default:
+                        Log.d(TAG, "Ignored " + message);
+                        break;
+                }
+            }
+        }
+
+        int putListener(Object listener) {
+            if (listener == null) return 0;
+            int key;
+            synchronized (mListenerMapLock) {
+                key = mListenerKey++;
+                mListenerMap.put(key, listener);
+            }
+            return key;
+        }
+
+        Object getListener(int key) {
+            synchronized (mListenerMapLock) {
+                return mListenerMap.remove(key);
+            }
+        }
+    }
+
+    /**
+     * Registers the application with the Wi-Fi framework. This function
      * must be the first to be called before any p2p operations are performed.
      *
-     * <p class="note"><strong>Note:</strong>
-     * The handler registered with the framework should only handle messages
-     * with {@link android.os.Message#what} values defined in this file. Adding application
-     * specific private {@link android.os.Message#what} types should be done on a seperate handler
-     *
      * @param srcContext is the context of the source
-     * @param srcHandler is the handler on which the source will receive message responses
-     * asynchronously
+     * @param srcLooper is the Looper on which the callbacks are receivied
+     * @param listener for callback at loss of framework communication. Can be null.
      * @return Channel instance that is necessary for performing any further p2p operations
      */
-    public Channel initialize(Context srcContext, Handler srcHandler) {
+    public Channel initialize(Context srcContext, Looper srcLooper, ChannelListener listener) {
         Messenger messenger = getMessenger();
         if (messenger == null) return null;
 
-        AsyncChannel asyncChannel = new AsyncChannel();
-        Channel c = new Channel(asyncChannel);
-        if (asyncChannel.connectSync(srcContext, srcHandler, messenger)
+        Channel c = new Channel(srcLooper, listener);
+        if (c.mAsyncChannel.connectSync(srcContext, c.mHandler, messenger)
                 == AsyncChannel.STATUS_SUCCESSFUL) {
             return c;
         } else {
@@ -425,30 +483,32 @@
      * for the purpose of establishing a connection.
      *
      * <p> The function call immediately returns after sending a discovery request
-     * to the framework. The application handler is notified of a success or failure to initiate
-     * discovery with {@link #DISCOVER_PEERS_SUCCEEDED} or {@link #DISCOVER_PEERS_FAILED}.
+     * to the framework. The application is notified of a success or failure to initiate
+     * discovery through listener callbacks {@link ActionListener#onSuccess} or
+     * {@link ActionListener#onFailure}.
      *
      * <p> The discovery remains active until a connection is initiated or
      * a p2p group is formed. Register for {@link #WIFI_P2P_PEERS_CHANGED_ACTION} intent to
      * determine when the framework notifies of a change as peers are discovered.
      *
      * <p> Upon receiving a {@link #WIFI_P2P_PEERS_CHANGED_ACTION} intent, an application
-     * can request for the list of peers using {@link #requestPeers} which will deliver a
-     * {@link #RESPONSE_PEERS} message on the application handler. The application can then
-     * extract a {@link WifiP2pDeviceList} object by calling {@link #peersInResponse}
-     * on the message.
+     * can request for the list of peers using {@link #requestPeers}.
+     *
+     * @param c is the channel created at {@link #initialize}
+     * @param listener for callbacks on success or failure. Can be null.
      */
-    public void discoverPeers(Channel c) {
+    public void discoverPeers(Channel c, ActionListener listener) {
         if (c == null) return;
-        c.mAsyncChannel.sendMessage(DISCOVER_PEERS);
+        c.mAsyncChannel.sendMessage(DISCOVER_PEERS, 0, c.putListener(listener));
     }
 
     /**
      * Start a p2p connection to a device with the specified configuration.
      *
      * <p> The function call immediately returns after sending a connection request
-     * to the framework. The application handler is notified of a success or failure to initiate
-     * connectivity with {@link #CONNECT_SUCCEEDED} or {@link #CONNECT_FAILED}.
+     * to the framework. The application is notified of a success or failure to initiate
+     * connect through listener callbacks {@link ActionListener#onSuccess} or
+     * {@link ActionListener#onFailure}.
      *
      * <p> Register for {@link #WIFI_P2P_CONNECTION_CHANGED_ACTION} intent to
      * determine when the framework notifies of a change in connectivity.
@@ -460,100 +520,102 @@
      * a p2p group with {@link #createGroup}, an invitation to join the group is sent to
      * the peer device.
      *
-     * @param config options as described in {@link WifiP2pConfig} class.
+     * @param c is the channel created at {@link #initialize}
+     * @param config options as described in {@link WifiP2pConfig} class
+     * @param listener for callbacks on success or failure. Can be null.
      */
-    public void connect(Channel c, WifiP2pConfig config) {
+    public void connect(Channel c, WifiP2pConfig config, ActionListener listener) {
         if (c == null) return;
-        c.mAsyncChannel.sendMessage(CONNECT, config);
+        c.mAsyncChannel.sendMessage(CONNECT, 0, c.putListener(listener), config);
+    }
+
+    /**
+     * Cancel any ongoing p2p group negotiation
+     *
+     * <p> The function call immediately returns after sending a connection cancellation request
+     * to the framework. The application is notified of a success or failure to initiate
+     * cancellation through listener callbacks {@link ActionListener#onSuccess} or
+     * {@link ActionListener#onFailure}.
+     *
+     * @param c is the channel created at {@link #initialize}
+     * @param listener for callbacks on success or failure. Can be null.
+     */
+    public void cancelConnect(Channel c, ActionListener listener) {
+        if (c == null) return;
+        c.mAsyncChannel.sendMessage(CANCEL_CONNECT, 0, c.putListener(listener));
     }
 
     /**
      * Create a p2p group with the current device as the group owner. This essentially creates
      * an access point that can accept connections from legacy clients as well as other p2p
      * devices.
-     * <p> For p2p operation, this would normally not be used unless the current device needs
+     *
+     * <p class="note"><strong>Note:</strong>
+     * This function would normally not be used unless the current device needs
      * to form a p2p connection with a legacy client
      *
      * <p> The function call immediately returns after sending a group creation request
-     * to the framework. The application handler is notified of a success or failure to create
-     * group with {@link #CREATE_GROUP_SUCCEEDED} or {@link #CREATE_GROUP_FAILED}.
+     * to the framework. The application is notified of a success or failure to initiate
+     * group creation through listener callbacks {@link ActionListener#onSuccess} or
+     * {@link ActionListener#onFailure}.
      *
-     * <p> Application can request for the group details with {@link #requestGroupInfo} which will
-     * deliver a {@link #RESPONSE_GROUP_INFO} message on the application handler. The application
-     * can then extract a {@link WifiP2pGroup} object by calling {@link #groupInfoInResponse}
-     * on the message.
+     * <p> Application can request for the group details with {@link #requestGroupInfo}.
+     *
+     * @param c is the channel created at {@link #initialize}
+     * @param listener for callbacks on success or failure. Can be null.
      */
-    public void createGroup(Channel c) {
+    public void createGroup(Channel c, ActionListener listener) {
         if (c == null) return;
-        c.mAsyncChannel.sendMessage(CREATE_GROUP);
+        c.mAsyncChannel.sendMessage(CREATE_GROUP, 0, c.putListener(listener));
     }
 
     /**
      * Remove the current p2p group.
      *
      * <p> The function call immediately returns after sending a group removal request
-     * to the framework. The application handler is notified of a success or failure to remove
-     * a group with {@link #REMOVE_GROUP_SUCCEEDED} or {@link #REMOVE_GROUP_FAILED}.
+     * to the framework. The application is notified of a success or failure to initiate
+     * group removal through listener callbacks {@link ActionListener#onSuccess} or
+     * {@link ActionListener#onFailure}.
+     *
+     * @param c is the channel created at {@link #initialize}
+     * @param listener for callbacks on success or failure. Can be null.
      */
-    public void removeGroup(Channel c) {
+    public void removeGroup(Channel c, ActionListener listener) {
         if (c == null) return;
-        c.mAsyncChannel.sendMessage(REMOVE_GROUP);
+        c.mAsyncChannel.sendMessage(REMOVE_GROUP, 0, c.putListener(listener));
     }
 
     /**
-     * Request the current list of peers. This returns a {@link #RESPONSE_PEERS} on the application
-     * handler. The {@link #RESPONSE_PEERS} message on the handler indicates that the peer list is
-     * available. Use {@link #peersInResponse} to extract {@link WifiP2pDeviceList} from the message
+     * Request the current list of peers.
+     *
+     * @param c is the channel created at {@link #initialize}
+     * @param listener for callback when peer list is available. Can be null.
      */
-    public void requestPeers(Channel c) {
+    public void requestPeers(Channel c, PeerListListener listener) {
         if (c == null) return;
-        c.mAsyncChannel.sendMessage(REQUEST_PEERS);
+        c.mAsyncChannel.sendMessage(REQUEST_PEERS, 0, c.putListener(listener));
     }
 
     /**
-     * Upon receiving a {@link #RESPONSE_PEERS} on the application handler, an application
-     * can extract the peer device list using this function.
+     * Request device connection info.
+     *
+     * @param c is the channel created at {@link #initialize}
+     * @param listener for callback when connection info is available. Can be null.
      */
-    public WifiP2pDeviceList peersInResponse(Message msg) {
-        return (WifiP2pDeviceList) msg.obj;
-    }
-
-    /**
-     * Request device connection info. This returns a {@link #RESPONSE_CONNECTION_INFO} on
-     * the application handler. The {@link #RESPONSE_CONNECTION_INFO} message on the handler
-     * indicates that connection info is available. Use {@link #connectionInfoInResponse} to
-     * extract {@link WifiP2pInfo} from the message.
-     */
-    public void requestConnectionInfo(Channel c) {
+    public void requestConnectionInfo(Channel c, ConnectionInfoListener listener) {
         if (c == null) return;
-        c.mAsyncChannel.sendMessage(REQUEST_CONNECTION_INFO);
+        c.mAsyncChannel.sendMessage(REQUEST_CONNECTION_INFO, 0, c.putListener(listener));
     }
 
     /**
-     * Upon receiving a {@link #RESPONSE_CONNECTION_INFO} on the application handler, an application
-     * can extract the connection info using this function.
+     * Request p2p group info.
+     *
+     * @param c is the channel created at {@link #initialize}
+     * @param listener for callback when group info is available. Can be null.
      */
-    public WifiP2pInfo connectionInfoInResponse(Message msg) {
-        return (WifiP2pInfo) msg.obj;
-    }
-
-    /**
-     * Request p2p group info. This returns a {@link #RESPONSE_GROUP_INFO} on
-     * the application handler. The {@link #RESPONSE_GROUP_INFO} message on the handler
-     * indicates that group info is available. Use {@link #groupInfoInResponse} to
-     * extract {@link WifiP2pGroup} from the message.
-     */
-    public void requestGroupInfo(Channel c) {
+    public void requestGroupInfo(Channel c, GroupInfoListener listener) {
         if (c == null) return;
-        c.mAsyncChannel.sendMessage(REQUEST_GROUP_INFO);
-    }
-
-    /**
-     * Upon receiving a {@link #RESPONSE_GROUP_INFO} on the application handler, an application
-     * can extract the group info using this function.
-     */
-    public WifiP2pGroup groupInfoInResponse(Message msg) {
-        return (WifiP2pGroup) msg.obj;
+        c.mAsyncChannel.sendMessage(REQUEST_GROUP_INFO, 0, c.putListener(listener));
     }
 
     /**
@@ -571,36 +633,4 @@
         }
     }
 
-    /**
-     * Setup DNS connectivity on the current process to the connected Wi-Fi p2p peers
-     *
-     * @return -1 on failure
-     * @hide
-     */
-    public int startPeerCommunication() {
-        IBinder b = ServiceManager.getService(Context.CONNECTIVITY_SERVICE);
-        IConnectivityManager cm = IConnectivityManager.Stub.asInterface(b);
-        try {
-            return cm.startUsingNetworkFeature(ConnectivityManager.TYPE_WIFI, "p2p", new Binder());
-        } catch (RemoteException e) {
-            return -1;
-        }
-    }
-
-    /**
-     * Tear down connectivity to the connected Wi-Fi p2p peers
-     *
-     * @return -1 on failure
-     * @hide
-     */
-    public int stopPeerCommunication() {
-        IBinder b = ServiceManager.getService(Context.CONNECTIVITY_SERVICE);
-        IConnectivityManager cm = IConnectivityManager.Stub.asInterface(b);
-        try {
-            return cm.stopUsingNetworkFeature(ConnectivityManager.TYPE_WIFI, "p2p");
-        } catch (RemoteException e) {
-            return -1;
-        }
-    }
-
 }
diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pService.java b/wifi/java/android/net/wifi/p2p/WifiP2pService.java
index fb2c134..1b02774 100644
--- a/wifi/java/android/net/wifi/p2p/WifiP2pService.java
+++ b/wifi/java/android/net/wifi/p2p/WifiP2pService.java
@@ -41,9 +41,7 @@
 import android.net.wifi.WifiMonitor;
 import android.net.wifi.WifiNative;
 import android.net.wifi.WifiStateMachine;
-import android.net.wifi.Wps;
-import android.net.wifi.Wps.Setup;
-import android.net.wifi.p2p.WifiP2pDevice.Status;
+import android.net.wifi.WpsInfo;
 import android.os.Binder;
 import android.os.IBinder;
 import android.os.INetworkManagementService;
@@ -137,11 +135,12 @@
     private static final int AIRPLANE_MODE_CHANGED          =   BASE + 6;
     /* Emergency callback mode */
     private static final int EMERGENCY_CALLBACK_MODE        =   BASE + 7;
+    private static final int WPS_PBC                        =   BASE + 8;
+    private static final int WPS_PIN                        =   BASE + 9;
 
     private final boolean mP2pSupported;
-    private final String mDeviceType;
-    private String mDeviceName;
-    private String mDeviceAddress;
+
+    private WifiP2pDevice mThisDevice = new WifiP2pDevice();
 
     /* When a group has been explicitly created by an app, we persist the group
      * even after all clients have been disconnected until an explicit remove
@@ -164,9 +163,9 @@
         mP2pSupported = mContext.getPackageManager().hasSystemFeature(
                 PackageManager.FEATURE_WIFI_DIRECT);
 
-        mDeviceType = mContext.getResources().getString(
+        mThisDevice.primaryDeviceType = mContext.getResources().getString(
                 com.android.internal.R.string.config_wifi_p2p_device_type);
-        mDeviceName = getDefaultDeviceName();
+        mThisDevice.deviceName = getDefaultDeviceName();
 
         mP2pStateMachine = new P2pStateMachine(TAG, mP2pSupported);
         mP2pStateMachine.start();
@@ -350,6 +349,10 @@
                     replyToMessage(message, WifiP2pManager.CONNECT_FAILED,
                             WifiP2pManager.BUSY);
                     break;
+                case WifiP2pManager.CANCEL_CONNECT:
+                    replyToMessage(message, WifiP2pManager.CANCEL_CONNECT_FAILED,
+                            WifiP2pManager.BUSY);
+                    break;
                 case WifiP2pManager.CREATE_GROUP:
                     replyToMessage(message, WifiP2pManager.CREATE_GROUP_FAILED,
                             WifiP2pManager.BUSY);
@@ -410,6 +413,10 @@
                     replyToMessage(message, WifiP2pManager.CONNECT_FAILED,
                             WifiP2pManager.P2P_UNSUPPORTED);
                     break;
+                case WifiP2pManager.CANCEL_CONNECT:
+                    replyToMessage(message, WifiP2pManager.CANCEL_CONNECT_FAILED,
+                            WifiP2pManager.P2P_UNSUPPORTED);
+                    break;
                 case WifiP2pManager.CREATE_GROUP:
                     replyToMessage(message, WifiP2pManager.CREATE_GROUP_FAILED,
                             WifiP2pManager.P2P_UNSUPPORTED);
@@ -656,7 +663,7 @@
                     break;
                 case WifiMonitor.P2P_DEVICE_FOUND_EVENT:
                     WifiP2pDevice device = (WifiP2pDevice) message.obj;
-                    if (mDeviceAddress.equals(device.deviceAddress)) break;
+                    if (mThisDevice.deviceAddress.equals(device.deviceAddress)) break;
                     mPeers.update(device);
                     sendP2pPeersChangedBroadcast();
                     break;
@@ -683,7 +690,7 @@
                             // do nothing if p2pConnect did not return a pin
                         }
                     }
-                    updateDeviceStatus(mSavedConnectConfig.deviceAddress, Status.INVITED);
+                    updateDeviceStatus(mSavedConnectConfig.deviceAddress, WifiP2pDevice.INVITED);
                     sendP2pPeersChangedBroadcast();
                     replyToMessage(message, WifiP2pManager.CONNECT_SUCCEEDED);
                     transitionTo(mGroupNegotiationState);
@@ -706,7 +713,7 @@
                                 P2pStateMachine.this, mGroup.getInterface());
                         mDhcpStateMachine.sendMessage(DhcpStateMachine.CMD_START_DHCP);
                         WifiP2pDevice groupOwner = mGroup.getOwner();
-                        updateDeviceStatus(groupOwner.deviceAddress, Status.CONNECTED);
+                        updateDeviceStatus(groupOwner.deviceAddress, WifiP2pDevice.CONNECTED);
                         sendP2pPeersChangedBroadcast();
                     }
                     transitionTo(mGroupCreatedState);
@@ -783,7 +790,7 @@
                 case WifiMonitor.P2P_GO_NEGOTIATION_FAILURE_EVENT:
                 case WifiMonitor.P2P_GROUP_FORMATION_FAILURE_EVENT:
                     if (DBG) logd(getName() + " go failure");
-                    updateDeviceStatus(mSavedConnectConfig.deviceAddress, Status.FAILED);
+                    updateDeviceStatus(mSavedConnectConfig.deviceAddress, WifiP2pDevice.FAILED);
                     mSavedConnectConfig = null;
                     sendP2pPeersChangedBroadcast();
                     transitionTo(mInactiveState);
@@ -791,7 +798,7 @@
                 case GROUP_NEGOTIATION_TIMED_OUT:
                     if (mGroupNegotiationTimeoutIndex == message.arg1) {
                         if (DBG) logd("Group negotiation timed out");
-                        updateDeviceStatus(mSavedConnectConfig.deviceAddress, Status.FAILED);
+                        updateDeviceStatus(mSavedConnectConfig.deviceAddress, WifiP2pDevice.FAILED);
                         mSavedConnectConfig = null;
                         sendP2pPeersChangedBroadcast();
                         transitionTo(mInactiveState);
@@ -802,6 +809,14 @@
                     replyToMessage(message, WifiP2pManager.DISCOVER_PEERS_FAILED,
                             WifiP2pManager.BUSY);
                     break;
+                case WifiP2pManager.CANCEL_CONNECT:
+                    if (WifiNative.p2pCancelConnect()) {
+                        replyToMessage(message, WifiP2pManager.CANCEL_CONNECT_SUCCEEDED);
+                    } else {
+                        replyToMessage(message, WifiP2pManager.CANCEL_CONNECT_FAILED,
+                                WifiP2pManager.ERROR);
+                    }
+                    break;
                 default:
                     return NOT_HANDLED;
             }
@@ -815,6 +830,8 @@
             if (DBG) logd(getName());
             mNetworkInfo.setDetailedState(NetworkInfo.DetailedState.CONNECTED, null, null);
 
+            updateThisDevice(WifiP2pDevice.CONNECTED);
+
             //DHCP server has already been started if I am a group owner
             if (mGroup.isGroupOwner()) {
                 setWifiP2pInfoOnGroupFormation(SERVER_ADDRESS);
@@ -832,7 +849,7 @@
                     String deviceAddress = getDeviceAddress(interfaceAddress);
                     if (deviceAddress != null) {
                         mGroup.addClient(deviceAddress);
-                        updateDeviceStatus(deviceAddress, Status.CONNECTED);
+                        updateDeviceStatus(deviceAddress, WifiP2pDevice.CONNECTED);
                         if (DBG) logd(getName() + " ap sta connected");
                         sendP2pPeersChangedBroadcast();
                     } else {
@@ -843,7 +860,7 @@
                     interfaceAddress = (String) message.obj;
                     deviceAddress = getDeviceAddress(interfaceAddress);
                     if (deviceAddress != null) {
-                        updateDeviceStatus(deviceAddress, Status.AVAILABLE);
+                        updateDeviceStatus(deviceAddress, WifiP2pDevice.AVAILABLE);
                         if (mGroup.removeClient(deviceAddress)) {
                             if (DBG) logd("Removed client " + deviceAddress);
                             if (!mPersistGroup && mGroup.isClientListEmpty()) {
@@ -888,7 +905,7 @@
                     boolean changed = false;
                     for (WifiP2pDevice d : mPeers.getDeviceList()) {
                         if (devices.contains(d) || mGroup.getOwner().equals(d)) {
-                            d.status = Status.AVAILABLE;
+                            d.status = WifiP2pDevice.AVAILABLE;
                             changed = true;
                         }
                     }
@@ -926,7 +943,7 @@
                     WifiP2pConfig config = (WifiP2pConfig) message.obj;
                     logd("Inviting device : " + config.deviceAddress);
                     if (WifiNative.p2pInvite(mGroup, config.deviceAddress)) {
-                        updateDeviceStatus(config.deviceAddress, Status.INVITED);
+                        updateDeviceStatus(config.deviceAddress, WifiP2pDevice.INVITED);
                         sendP2pPeersChangedBroadcast();
                         replyToMessage(message, WifiP2pManager.CONNECT_SUCCEEDED);
                     } else {
@@ -947,10 +964,10 @@
                 case WifiMonitor.P2P_GROUP_STARTED_EVENT:
                     Slog.e(TAG, "Duplicate group creation event notice, ignore");
                     break;
-                case WifiP2pManager.WPS_PBC:
+                case WPS_PBC:
                     WifiNative.wpsPbc();
                     break;
-                case WifiP2pManager.WPS_PIN:
+                case WPS_PIN:
                     WifiNative.wpsPin((String) message.obj);
                     break;
                 default:
@@ -960,6 +977,7 @@
         }
 
         public void exit() {
+            updateThisDevice(WifiP2pDevice.AVAILABLE);
             setWifiP2pInfoOnGroupTermination();
             mNetworkInfo.setDetailedState(NetworkInfo.DetailedState.DISCONNECTED, null, null);
             sendP2pConnectionChangedBroadcast();
@@ -979,6 +997,13 @@
         mContext.sendStickyBroadcast(intent);
     }
 
+    private void sendThisDeviceChangedBroadcast() {
+        final Intent intent = new Intent(WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION);
+        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
+        intent.putExtra(WifiP2pManager.EXTRA_WIFI_P2P_DEVICE, new WifiP2pDevice(mThisDevice));
+        mContext.sendStickyBroadcast(intent);
+    }
+
     private void sendP2pPeersChangedBroadcast() {
         final Intent intent = new Intent(WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION);
         intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
@@ -1048,7 +1073,7 @@
 
     private void notifyP2pGoNegotationRequest(WifiP2pConfig config) {
         Resources r = Resources.getSystem();
-        Wps wps = config.wps;
+        WpsInfo wps = config.wps;
         final View textEntryView = LayoutInflater.from(mContext)
                 .inflate(R.layout.wifi_p2p_go_negotiation_request_alert, null);
         final EditText pin = (EditText) textEntryView .findViewById(R.id.wifi_p2p_wps_pin);
@@ -1061,9 +1086,9 @@
                             if (DBG) logd(getName() + " connect " + pin.getText());
 
                             if (pin.getVisibility() == View.GONE) {
-                                mSavedGoNegotiationConfig.wps.setup = Setup.PBC;
+                                mSavedGoNegotiationConfig.wps.setup = WpsInfo.PBC;
                             } else {
-                                mSavedGoNegotiationConfig.wps.setup = Setup.KEYPAD;
+                                mSavedGoNegotiationConfig.wps.setup = WpsInfo.KEYPAD;
                                 mSavedGoNegotiationConfig.wps.pin = pin.getText().toString();
                             }
                             sendMessage(WifiP2pManager.CONNECT, mSavedGoNegotiationConfig);
@@ -1079,7 +1104,7 @@
                     })
             .create();
 
-        if (wps.setup == Setup.PBC) {
+        if (wps.setup == WpsInfo.PBC) {
             pin.setVisibility(View.GONE);
             dialog.setMessage(r.getString(R.string.wifi_p2p_pbc_go_negotiation_request_message,
                         config.deviceAddress));
@@ -1104,7 +1129,7 @@
             .setPositiveButton(r.getString(R.string.ok), new OnClickListener() {
                         public void onClick(DialogInterface dialog, int which) {
                                 if (DBG) logd(getName() + " wps_pbc");
-                                sendMessage(WifiP2pManager.WPS_PBC);
+                                sendMessage(WPS_PBC);
                         }
                     })
             .setNegativeButton(r.getString(R.string.cancel), null)
@@ -1130,7 +1155,7 @@
             .setPositiveButton(r.getString(R.string.ok), new OnClickListener() {
                     public void onClick(DialogInterface dialog, int which) {
                         if (DBG) logd(getName() + " wps_pin");
-                        sendMessage(WifiP2pManager.WPS_PIN, pin.getText().toString());
+                        sendMessage(WPS_PIN, pin.getText().toString());
                     }
                     })
             .setNegativeButton(r.getString(R.string.cancel), null)
@@ -1173,7 +1198,7 @@
         dialog.show();
     }
 
-    private void updateDeviceStatus(String deviceAddress, Status status) {
+    private void updateDeviceStatus(String deviceAddress, int status) {
         for (WifiP2pDevice d : mPeers.getDeviceList()) {
             if (d.deviceAddress.equals(deviceAddress)) {
                 d.status = status;
@@ -1218,28 +1243,50 @@
 
     private void initializeP2pSettings() {
         WifiNative.setPersistentReconnect(true);
-        WifiNative.setDeviceName(mDeviceName);
-        WifiNative.setDeviceType(mDeviceType);
+        WifiNative.setDeviceName(mThisDevice.deviceName);
+        WifiNative.setDeviceType(mThisDevice.primaryDeviceType);
 
-        mDeviceAddress = WifiNative.p2pGetDeviceAddress();
-        if (DBG) Slog.d(TAG, "DeviceAddress: " + mDeviceAddress);
+        mThisDevice.deviceAddress = WifiNative.p2pGetDeviceAddress();
+        updateThisDevice(WifiP2pDevice.AVAILABLE);
+        if (DBG) Slog.d(TAG, "DeviceAddress: " + mThisDevice.deviceAddress);
+    }
+
+    private void updateThisDevice(int status) {
+        mThisDevice.status = status;
+        sendThisDeviceChangedBroadcast();
     }
 
     //State machine initiated requests can have replyTo set to null indicating
     //there are no recepients, we ignore those reply actions
     private void replyToMessage(Message msg, int what) {
         if (msg.replyTo == null) return;
-        mReplyChannel.replyToMessage(msg, what);
+        Message dstMsg = obtainMessage(msg);
+        dstMsg.what = what;
+        mReplyChannel.replyToMessage(msg, dstMsg);
     }
 
     private void replyToMessage(Message msg, int what, int arg1) {
         if (msg.replyTo == null) return;
-        mReplyChannel.replyToMessage(msg, what, arg1);
+        Message dstMsg = obtainMessage(msg);
+        dstMsg.what = what;
+        dstMsg.arg1 = arg1;
+        mReplyChannel.replyToMessage(msg, dstMsg);
     }
 
     private void replyToMessage(Message msg, int what, Object obj) {
         if (msg.replyTo == null) return;
-        mReplyChannel.replyToMessage(msg, what, obj);
+        Message dstMsg = obtainMessage(msg);
+        dstMsg.what = what;
+        dstMsg.obj = obj;
+        mReplyChannel.replyToMessage(msg, dstMsg);
+    }
+
+    /* arg2 on the source message has a hash code that needs to be retained in replies
+     * see WifiP2pManager for details */
+    private Message obtainMessage(Message srcMsg) {
+        Message msg = Message.obtain();
+        msg.arg2 = srcMsg.arg2;
+        return msg;
     }
 
     private void logd(String s) {